diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2011-06-16 17:10:36 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-05-22 11:06:54 +0200 |
commit | ec8f5c355f97153a0adcf9370b8b3cf468aef74a (patch) | |
tree | e5514981f6e89dd21f82eb758242197a910c4269 /arch | |
parent | 1566c124c1325a566608c37af06646df2e5407d1 (diff) |
mach-ux500: 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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-mmio.c | 387 |
1 files changed, 387 insertions, 0 deletions
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, + } +}; |