diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2011-06-16 17:10:36 +0200 |
---|---|---|
committer | said m bagheri <ebgheri@steludxu2848.(none)> | 2011-06-17 13:42:17 +0200 |
commit | 27e26b25350b3a44fb5e131408555a0c247313b0 (patch) | |
tree | 60c3c64ebf13a1e8ca9b3adffb365ba48cf300ac | |
parent | 8c9c68f77509b92384ae6f41f60232d6af832aeb (diff) |
Imaging : Camera : Adding Support for U5500 Camera Board
This change will allow users to use B5500/S5500 Camera
ST-Ericsson Linux next: NA
ST-Ericsson ID:
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: If26b76e2f400e2c67cdb555454e92cbcef5b65d4
Signed-off-by: Nikhil Bhandary <nikhil.bhandary@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/23087
Reviewed-by: QATEST
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Conflicts:
arch/arm/configs/u5500_defconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/board-u5500.c
drivers/staging/Kconfig
include/linux/mmio.h
-rw-r--r-- | arch/arm/mach-ux500/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-mmio.c | 387 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-pins.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock-db5500.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/devices.h | 1 | ||||
-rw-r--r-- | drivers/staging/Kconfig | 6 | ||||
-rw-r--r-- | include/linux/mmio.h | 1 |
9 files changed, 407 insertions, 3 deletions
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index b065d2b57ca..5252fc085a7 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \ obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o \ board-u5500-mcde.o board-u5500-regulators.o \ board-u5500-pins.o +obj-$(CONFIG_U5500_MMIO) += board-u5500-mmio.o obj-$(CONFIG_U8500_MMIO) += board-mop500-mmio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-ux500/board-u5500-mmio.c b/arch/arm/mach-ux500/board-u5500-mmio.c new file mode 100644 index 00000000000..e88dafb90e8 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-mmio.c @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2011 ST-Ericsson + * Author: Joakim Axelsson <joakim.axelsson@stericsson.com> for ST-Ericsson + * Author: Rajat Verma <rajat.verma@stericsson.com> for ST-Ericsson. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/mmio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/vmalloc.h> +#include <plat/pincfg.h> +#include <mach/gpio.h> +#include <mach/devices.h> +#include "board-u5500.h" + +struct mmio_board_data{ + int number_of_regulators; + struct regulator **mmio_regulators; + /* * Pin configs */ + struct mmio_gpio xshutdown_pins[CAMERA_SLOT_END]; + /* * Internal clocks */ + struct clk *clk_ptr_bml; + struct clk *clk_ptr_ipi2c; + /* * External clocks */ + struct clk *clk_ptr_ext[CAMERA_SLOT_END]; +}; + +/* + * Fill names of regulators required for powering up the + * camera sensor in below array + */ +static char *regulator_names[] = {"v-mmio-camera" , "v-ana"}; + +static int mmio_clock_init(struct mmio_platform_data *pdata) +{ + int err; + struct mmio_board_data *extra = pdata->extra; + + extra->clk_ptr_ext[PRIMARY_CAMERA] = + clk_get(pdata->dev, "primary-cam"); + if (IS_ERR(extra->clk_ptr_ext[PRIMARY_CAMERA])) { + err = PTR_ERR(extra->clk_ptr_ext[PRIMARY_CAMERA]); + dev_err(pdata->dev, + "Error %d clock 'primary-cam'\n", err); + goto err_pri_ext_clk; + } + extra->clk_ptr_ext[SECONDARY_CAMERA] = + clk_get(pdata->dev, "secondary-cam"); + if (IS_ERR(extra->clk_ptr_ext[SECONDARY_CAMERA])) { + err = PTR_ERR(extra->clk_ptr_ext[SECONDARY_CAMERA]); + dev_err(pdata->dev, + "Error %d clock 'secondary-cam'\n", err); + goto err_sec_ext_clk; + } + + return 0; +err_sec_ext_clk: + clk_put(extra->clk_ptr_ext[PRIMARY_CAMERA]); +err_pri_ext_clk: + return err; +} + +static void mmio_clock_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + + clk_put(extra->clk_ptr_ext[PRIMARY_CAMERA]); + clk_put(extra->clk_ptr_ext[SECONDARY_CAMERA]); +} + +static int mmio_pin_cfg_init(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + + extra->xshutdown_pins[PRIMARY_CAMERA].gpio = + GPIO_PRIMARY_CAM_XSHUTDOWN; + extra->xshutdown_pins[PRIMARY_CAMERA].active_high = 0; + extra->xshutdown_pins[PRIMARY_CAMERA].udelay = 250; + + extra->xshutdown_pins[SECONDARY_CAMERA].gpio = + GPIO_SECONDARY_CAM_XSHUTDOWN; + extra->xshutdown_pins[SECONDARY_CAMERA].active_high = 0; + extra->xshutdown_pins[SECONDARY_CAMERA].udelay = 250; + + return 0; +} + +static void mmio_pin_cfg_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; +} + +/* + * For now, both sensors on B5500/S5500 have some power up sequence. If + * different sequences are needed for primary and secondary sensors, it can + * be implemented easily. Just use camera_slot field of mmio_platform_data + * to determine which camera needs to be powered up + */ +static int mmio_power_init(struct mmio_platform_data *pdata) +{ + int err = 0, i = 0; + struct mmio_board_data *extra = pdata->extra; + + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + extra->number_of_regulators = ARRAY_SIZE(regulator_names); + extra->mmio_regulators = + kzalloc(sizeof(struct regulator *) * extra->number_of_regulators, + GFP_KERNEL); + if (!extra->mmio_regulators) { + dev_err(pdata->dev + , "Error allocating memory for mmio regulators\n"); + err = -ENOMEM; + goto err_no_mem_reg; + } + for (i = 0; i < + extra->number_of_regulators; i++) { + extra->mmio_regulators[i] = + regulator_get(pdata->dev, regulator_names[i]); + if (IS_ERR(extra->mmio_regulators[i])) { + err = PTR_ERR(extra->mmio_regulators[i]); + dev_err(pdata->dev + , "Error %d getting regulator '%s'\n" + , err, regulator_names[i]); + goto err_regulator; + } + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_regulator: + /* + * Return regulators we have already requested + */ + while (i--) + regulator_put(extra->mmio_regulators[i]); + kfree(extra->mmio_regulators); +err_no_mem_reg: + return err; +} + +static void mmio_power_exit(struct mmio_platform_data *pdata) +{ + int i = 0; + struct mmio_board_data *extra = pdata->extra;; + + for (i = 0; i < extra->number_of_regulators; i++) + regulator_put(extra->mmio_regulators[i]); + kfree(extra->mmio_regulators); +} + +static int mmio_platform_init(struct mmio_platform_data *pdata) +{ + int err = 0; + struct mmio_board_data *extra = NULL; + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* + * Alloc memory for our own extra data + */ + extra = kzalloc(sizeof(struct mmio_board_data), GFP_KERNEL); + if (!extra) { + dev_err(pdata->dev, "%s: memory alloc failed for " + "mmio_board_data\n", __func__); + err = -ENOMEM; + goto err_no_mem_extra; + } + /* + * Hook the data for other callbacks to use + */ + pdata->extra = extra; + + pdata->camera_slot = -1; + + err = mmio_power_init(pdata); + if (err) + goto err_regulator; + err = mmio_clock_init(pdata); + if (err) + goto err_clock; + err = mmio_pin_cfg_init(pdata); + if (err) + goto err_pin_cfg; + + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; + +err_pin_cfg: + mmio_clock_exit(pdata); +err_clock: + mmio_power_exit(pdata); +err_regulator: + kfree(extra); +err_no_mem_extra: + return err; +} + +static void mmio_platform_exit(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + + mmio_power_exit(pdata); + mmio_clock_exit(pdata); + mmio_pin_cfg_exit(pdata); + kfree(extra); + pdata->extra = NULL; +} + +static int mmio_power_enable(struct mmio_platform_data *pdata) +{ + int err = 0, i = 0; + struct mmio_board_data *extra = pdata->extra; + + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + /* + * Enable the regulators + */ + for (i = 0; i < extra->number_of_regulators; i++) { + err = regulator_enable(extra->mmio_regulators[i]); + if (IS_ERR(extra->mmio_regulators[i])) { + err = PTR_ERR(extra->mmio_regulators[i]); + dev_err(pdata->dev , "Error %d enabling regulator '%s'" + "\n", err, regulator_names[i]); + goto err_regulator; + } + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_regulator: + /* + * Disable regulators we already enabled + */ + while (i--) + regulator_disable(extra->mmio_regulators[i]); + return err; +} + +static void mmio_power_disable(struct mmio_platform_data *pdata) +{ + int i; + struct mmio_board_data *extra = pdata->extra; + /* + * Disable the regulators + */ + for (i = 0; i < extra->number_of_regulators; i++) + regulator_disable(extra->mmio_regulators[i]); +} + +static int mmio_clock_enable(struct mmio_platform_data *pdata) +{ + int err = 0; + struct mmio_board_data *extra = pdata->extra; + + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + + /* + * Enable appropriate external clock + */ + err = clk_enable(extra->clk_ptr_ext[pdata->camera_slot]); + if (err) { + dev_err(pdata->dev, "Error activating clock for sensor %d, err" + "%d\n", pdata->camera_slot, err); + goto err_ext_clk; + } + dev_dbg(pdata->dev , "Board %s() Exit\n", __func__); + return 0; +err_ext_clk: + return err; +} + +static void mmio_clock_disable(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + + clk_disable(extra->clk_ptr_ext[pdata->camera_slot]); +} + +static int mmio_config_xshutdown_pins(struct mmio_platform_data *pdata, + enum mmio_select_xshutdown_t select, + int is_active_high) +{ + int err = 0; + struct mmio_board_data *extra = pdata->extra; + + dev_dbg(pdata->dev , "Board %s() Enter\n", __func__); + switch (select) { + case MMIO_ENABLE_XSHUTDOWN_HOST: + extra->xshutdown_pins[pdata->camera_slot].active_high = + is_active_high; + dev_dbg(pdata->dev , "Enabling Xshutdown GPIO PIN = %d", + extra->xshutdown_pins[pdata->camera_slot].gpio); + + err = gpio_request + (extra->xshutdown_pins[pdata->camera_slot].gpio, + "MMIO GPIO"); + if (err) { + dev_err(pdata->dev, "Error %d while requesting" + "Xshutdown MMIO GPIO\n", + err); + return err; + } + + err = gpio_direction_output + (extra->xshutdown_pins[pdata->camera_slot].gpio, + 0); + if (err) { + dev_err(pdata->dev, "Error %d while setting" + "Xshutdown MMIO GPIO" + "output mode\n", err); + return err; + } + break; + case MMIO_DISABLE_XSHUTDOWN: + dev_dbg(pdata->dev , "Disabling Xshutdown GPIO PIN = %d", + extra->xshutdown_pins[pdata->camera_slot].gpio); + gpio_free(extra->xshutdown_pins[pdata->camera_slot].gpio); + break; + default: + break; + } + if (err) + dev_err(pdata->dev , "Error configuring xshutdown, err = %d\n", + err); + return err; +} + +static void mmio_set_xshutdown(struct mmio_platform_data *pdata) +{ + struct mmio_board_data *extra = pdata->extra; + + gpio_set_value(extra->xshutdown_pins[pdata->camera_slot].gpio , + (extra->xshutdown_pins[pdata->camera_slot].active_high + ? 1 : 0)); + udelay(extra->xshutdown_pins[pdata->camera_slot].udelay); +} + +/* + * TODO: This function would be removed in futute. + * Since this function is called frequently + * from HSM Camera code , it is kept for Legacy. + */ +static int mmio_config_i2c_pins(struct mmio_platform_data *pdata, + enum mmio_select_i2c_t select) +{ + int err = 0; + + switch (select) { + case MMIO_ACTIVATE_I2C_HOST: + dev_dbg(pdata->dev , "Activate I2C from Host called\n"); + break; + case MMIO_DEACTIVATE_I2C: + dev_dbg(pdata->dev , "DeActivate I2C from Host called\n"); + break; + default: + break; + } + + return err; +} + +static struct mmio_platform_data mmio_config = { + .platform_init = mmio_platform_init, + .platform_exit = mmio_platform_exit, + .power_enable = mmio_power_enable, + .power_disable = mmio_power_disable, + .clock_enable = mmio_clock_enable, + .clock_disable = mmio_clock_disable, + .config_i2c_pins = mmio_config_i2c_pins, + .config_xshutdown_pins = mmio_config_xshutdown_pins, + .set_xshutdown = mmio_set_xshutdown +}; + +struct platform_device u5500_mmio_device = { + .name = MMIO_NAME, + .id = -1, + .dev = { + .platform_data = &mmio_config, + } +}; diff --git a/arch/arm/mach-ux500/board-u5500-pins.c b/arch/arm/mach-ux500/board-u5500-pins.c index 11b4a95f5cb..18cc60796bb 100644 --- a/arch/arm/mach-ux500/board-u5500-pins.c +++ b/arch/arm/mach-ux500/board-u5500-pins.c @@ -90,6 +90,10 @@ static pin_cfg_t u5500_pins_default[] = { /* Display & HDMI HW sync */ GPIO204_LCD_VSI1 | PIN_INPUT_PULLUP, + + /* Camera & MMIO XshutDown*/ + GPIO1_GPIO | PIN_OUTPUT_LOW, + GPIO2_GPIO | PIN_OUTPUT_LOW, }; static UX500_PINS(u5500_pins_i2c1, diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 247a2d30b92..3759a815261 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -356,6 +356,9 @@ static struct platform_device *u5500_platform_devices[] __initdata = { &ux500_hwmem_device, &u5500_b2r2_device, &u5500_mloader_device, +#ifdef CONFIG_U5500_MMIO + &u5500_mmio_device, +#endif }; static void __init u5500_i2c_init(void) diff --git a/arch/arm/mach-ux500/board-u5500.h b/arch/arm/mach-ux500/board-u5500.h index 8ff1c7834db..dda59f39bdf 100644 --- a/arch/arm/mach-ux500/board-u5500.h +++ b/arch/arm/mach-ux500/board-u5500.h @@ -10,6 +10,9 @@ #define GPIO_SDMMC_CD 180 #define GPIO_MMC_CARD_CTRL 227 #define GPIO_MMC_CARD_VSEL 185 +#define GPIO_PRIMARY_CAM_XSHUTDOWN 1 +#define GPIO_SECONDARY_CAM_XSHUTDOWN 2 + struct ab5500_regulator_platform_data; extern struct ab5500_regulator_platform_data u5500_ab5500_regulator_data; diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c index 0d019a6f44c..93f65e5cc79 100644 --- a/arch/arm/mach-ux500/clock-db5500.c +++ b/arch/arm/mach-ux500/clock-db5500.c @@ -741,8 +741,8 @@ static struct clk_lookup db5500_prcc_clocks[] = { }; static struct clk_lookup db5500_clkouts[] = { - CLK_LOOKUP(clkout1, "pri-cam", NULL), - CLK_LOOKUP(clkout1, "sec-cam", NULL), + CLK_LOOKUP(clkout1, "mmio_camera", "primary-cam"), + CLK_LOOKUP(clkout1, "mmio_camera", "secondary-cam"), }; static struct clk_lookup u5500_clocks[] = { diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index 33d29990680..c10333a5e0a 100644 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h @@ -31,6 +31,7 @@ extern struct platform_device u8500_dma40_device; extern struct platform_device ux500_ske_keypad_device; extern struct platform_device u8500_hsi_device; extern struct platform_device ux500_mmio_device; +extern struct platform_device u5500_mmio_device; void dma40_u8500ed_fixup(void); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 08edeb055d7..3b8d084490b 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,9 +24,13 @@ menuconfig STAGING if STAGING +config U5500_MMIO + bool "ST-Ericsson U5500 MMIO (Camera) Driver" + depends on UX500_SOC_DB5500 + config U8500_MMIO bool "ST-Ericsson MMIO (Camera) Driver" - depends on ARCH_U8500 + depends on UX500_SOC_DB8500 config U8500_FLASH bool "ST-Ericsson Flash (Camera) Driver" diff --git a/include/linux/mmio.h b/include/linux/mmio.h index 9dee32055ef..1c6f68e3556 100644 --- a/include/linux/mmio.h +++ b/include/linux/mmio.h @@ -12,6 +12,7 @@ #include <linux/ioctl.h> #define MMIO_NAME "mmio_camera" +#define SRA_SUPPORT 1 #ifdef SRA_SUPPORT #define SREG_16_BIT (0x1) |