diff options
author | Ming Wong <miwong@nvidia.com> | 2014-01-10 12:23:50 -0800 |
---|---|---|
committer | Sachin Nikam <snikam@nvidia.com> | 2014-01-16 00:56:59 -0800 |
commit | 908b2f172be5aea21c29ac3cebfba75eec81e184 (patch) | |
tree | 216b729362059ba2f5fba3d76bdd3ac1ea3eb9b4 | |
parent | b8a898bcc14b73f678cff8d5e77993c1d1f5e947 (diff) |
media: convert imx179 driver to non-nvc format
bug 1415077
Change-Id: I98ea518ea8de07b2cd78066522c039dadee379bd
Signed-off-by: Ming Wong <miwong@nvidia.com>
Reviewed-on: http://git-master/r/354372
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Prayas Mohanty <pmohanty@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
-rw-r--r-- | drivers/media/platform/tegra/imx179.c | 3030 | ||||
-rw-r--r-- | include/media/imx179.h | 113 |
2 files changed, 865 insertions, 2278 deletions
diff --git a/drivers/media/platform/tegra/imx179.c b/drivers/media/platform/tegra/imx179.c index 9a540ae3535d..ea048840a287 100644 --- a/drivers/media/platform/tegra/imx179.c +++ b/drivers/media/platform/tegra/imx179.c @@ -1,199 +1,92 @@ /* -* imx179.c - imx179 sensor driver -* -* Copyright (c) 2013-2014, NVIDIA Corporation. All Rights Reserved. -* -* This file is licensed under the terms of the GNU General Public License -* version 2. This program is licensed "as is" without any warranty of any -* kind, whether express or implied. -*/ + * imx179.c - imx179 sensor driver + * + * Copyright (c) 2014, NVIDIA CORPORATION, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/delay.h> #include <linux/fs.h> #include <linux/i2c.h> #include <linux/clk.h> #include <linux/miscdevice.h> #include <linux/slab.h> -#include <linux/delay.h> #include <linux/uaccess.h> -#include <linux/atomic.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> -#include <linux/module.h> -#include <linux/list.h> +#include <linux/regmap.h> #include <media/imx179.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/edp.h> -#include "nvc_utilities.h" - -#define IMX179_ID 0x0179 -#define IMX179_ID_ADDRESS 0x0002 -#define IMX179_STREAM_CONTROL_REG 0x0100 -#define IMX179_STREAM_ENABLE 0x01 -#define IMX179_STREAM_DISABLE 0x00 -#define IMX179_SENSOR_TYPE NVC_IMAGER_TYPE_RAW -#define IMX179_STARTUP_DELAY_MS 50 -#define IMX179_RES_CHG_WAIT_TIME_MS 100 -#define IMX179_SIZEOF_I2C_BUF 16 -#define IMX179_TABLE_WAIT_MS 0 -#define IMX179_TABLE_END 1 -#define IMX179_NUM_MODES ARRAY_SIZE(imx179_mode_table) -#define IMX179_MODE_UNKNOWN (IMX179_NUM_MODES + 1) -#define IMX179_LENS_MAX_APERTURE 0 /* / _INT2FLOAT_DIVISOR */ -#define IMX179_LENS_FNUMBER 0 /* / _INT2FLOAT_DIVISOR */ -#define IMX179_LENS_FOCAL_LENGTH 3700 /* / _INT2FLOAT_DIVISOR */ -#define IMX179_LENS_VIEW_ANGLE_H 75600 /* / _INT2FLOAT_DIVISOR */ -#define IMX179_LENS_VIEW_ANGLE_V 75600 /* / _INT2FLOAT_DIVISOR */ -#define IMX179_WAIT_MS 3 -#define IMX179_I2C_TABLE_MAX_ENTRIES 400 - -static u16 imx179_ids[] = { - 0x0179, -}; - -static struct nvc_gpio_init imx179_gpios[] = { - {IMX179_GPIO_RESET, GPIOF_OUT_INIT_LOW, "reset", false, true}, - {IMX179_GPIO_PWDN, GPIOF_OUT_INIT_LOW, "pwdn", false, true}, - {IMX179_GPIO_GP1, 0, "gp1", false, false}, -}; - -static struct nvc_regulator_init imx179_vregs[] = { - { IMX179_VREG_DVDD, "vdig", }, - { IMX179_VREG_AVDD, "vana", }, - { IMX179_VREG_IOVDD, "vif", }, -}; +#include <linux/kernel.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> -struct imx179_info { - atomic_t in_use; - struct i2c_client *i2c_client; - struct imx179_platform_data *pdata; - struct nvc_imager_cap *cap; - struct miscdevice miscdev; - struct list_head list; - struct clk *mclk; - struct nvc_gpio gpio[ARRAY_SIZE(imx179_gpios)]; - struct nvc_regulator vreg[ARRAY_SIZE(imx179_vregs)]; - int pwr_api; - int pwr_dev; - u8 s_mode; - struct imx179_info *s_info; - u32 mode_index; - bool mode_valid; - bool mode_enable; - bool reset_flag; - unsigned test_pattern; - struct nvc_imager_static_nvc sdata; - u8 i2c_buf[IMX179_SIZEOF_I2C_BUF]; - u8 bin_en; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; - u16 i2c_reg; -#endif -}; +#include "nvc_utilities.h" struct imx179_reg { u16 addr; - u16 val; -}; - -struct imx179_mode_data { - struct nvc_imager_mode sensor_mode; - struct nvc_imager_dynamic_nvc sensor_dnvc; - struct imx179_reg *p_mode_i2c; -}; - -static struct nvc_imager_cap imx179_dflt_cap = { - .identifier = "IMX179", - .sensor_nvc_interface = 3, - .pixel_types[0] = 0x100, - .orientation = 0, - .direction = 0, - .initial_clock_rate_khz = 6000, - .clock_profiles[0] = { - .external_clock_khz = 24000, - .clock_multiplier = 8500000, /* value / 1,000,000 */ - }, - .clock_profiles[1] = { - .external_clock_khz = 0, - .clock_multiplier = 0, - }, - .h_sync_edge = 0, - .v_sync_edge = 0, - .mclk_on_vgp0 = 0, - .csi_port = 0, - .data_lanes = 4, - .virtual_channel_id = 0, - .discontinuous_clk_mode = 1, - .cil_threshold_settle = 0x0, - .min_blank_time_width = 16, - .min_blank_time_height = 16, - .preferred_mode_index = 1, - .focuser_guid = NVC_FOCUS_GUID(0), - .torch_guid = 0, /*NVC_TORCH_GUID(0),*/ - .cap_version = NVC_IMAGER_CAPABILITIES_VERSION2, -}; - -static struct imx179_platform_data imx179_dflt_pdata = { - .cfg = 0, - .num = 0, - .sync = 0, - .dev_name = "camera", - .cap = &imx179_dflt_cap, -}; - - /* NOTE: static vs dynamic - * If a member in the nvc_imager_static_nvc structure is not actually - * static data, then leave blank and add the parameter to the parameter - * read function that dynamically reads the data. The NVC user driver - * will call the parameter read for the data if the member data is 0. - * If the dynamic data becomes static during probe (a one time read - * such as device ID) then add the dynamic read to the _sdata_init - * function. - */ -static struct nvc_imager_static_nvc imx179_dflt_sdata = { - .api_version = NVC_IMAGER_API_STATIC_VER, - .sensor_type = IMX179_SENSOR_TYPE, - .bits_per_pixel = 10, - .sensor_id = IMX179_ID, - .sensor_id_minor = 0, - .focal_len = IMX179_LENS_FOCAL_LENGTH, - .max_aperture = IMX179_LENS_MAX_APERTURE, - .fnumber = IMX179_LENS_FNUMBER, - .view_angle_h = IMX179_LENS_VIEW_ANGLE_H, - .view_angle_v = IMX179_LENS_VIEW_ANGLE_V, - .res_chg_wait_time = IMX179_RES_CHG_WAIT_TIME_MS, + u8 val; }; -static LIST_HEAD(imx179_info_list); -static DEFINE_SPINLOCK(imx179_spinlock); - - -static struct imx179_reg tp_none_seq[] = { - {IMX179_TABLE_END, 0x0000} +struct imx179_info { + struct miscdevice miscdev_info; + int mode; + struct imx179_power_rail power; + struct imx179_sensordata sensor_data; + struct i2c_client *i2c_client; + struct imx179_platform_data *pdata; + struct clk *mclk; + struct regmap *regmap; + struct mutex imx179_camera_lock; + struct dentry *debugdir; + atomic_t in_use; + struct edp_client *edpc; + unsigned int edp_state; }; -static struct imx179_reg tp_cbars_seq[] = { - {IMX179_TABLE_END, 0x0000} +static const struct regmap_config sensor_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, }; -static struct imx179_reg tp_checker_seq[] = { - {IMX179_TABLE_END, 0x0000} -}; +#define IMX179_TABLE_WAIT_MS 0 +#define IMX179_TABLE_END 1 +#define IMX179_MAX_RETRIES 3 +#define IMX179_WAIT_MS 3 -static struct imx179_reg *test_patterns[] = { - tp_none_seq, - tp_cbars_seq, - tp_checker_seq, -}; +#define MAX_BUFFER_SIZE 32 +#define IMX179_FRAME_LENGTH_ADDR_MSB 0x0340 +#define IMX179_FRAME_LENGTH_ADDR_LSB 0x0341 +#define IMX179_COARSE_TIME_ADDR_MSB 0x0202 +#define IMX179_COARSE_TIME_ADDR_LSB 0x0203 +#define IMX179_GAIN_ADDR 0x0205 -static struct imx179_reg imx179_3280x2464_i2c[] = { - /*stand by*/ +static struct imx179_reg mode_3280x2464[] = { + /* software reset */ {0x0100, 0x00}, {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, + /* global settings */ {0x0101, 0x00}, {0x0202, 0x09}, - {0x0203, 0xCC}, + {0x0203, 0xC7}, {0x0301, 0x05}, {0x0303, 0x01}, {0x0305, 0x06}, @@ -202,7 +95,7 @@ static struct imx179_reg imx179_3280x2464_i2c[] = { {0x030C, 0x00}, {0x030D, 0xA2}, {0x0340, 0x09}, - {0x0341, 0xD0}, + {0x0341, 0xCB}, {0x0342, 0x0D}, {0x0343, 0x70}, {0x0344, 0x00}, @@ -251,1040 +144,434 @@ static struct imx179_reg imx179_3280x2464_i2c[] = { {0x4108, 0x01}, {0x4109, 0x7C}, + {0x0100, 0x01}, {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, {IMX179_TABLE_END, 0x00} }; -static struct imx179_reg imx179_1640x1232_i2c[] = { - /*stand by*/ - {0x0100, 0x00}, - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, - - {0x0101, 0x00}, - {0x0202, 0x09}, - {0x0203, 0xCC}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0305, 0x06}, - {0x0309, 0x05}, - {0x030B, 0x01}, - {0x030C, 0x00}, - {0x030D, 0xA2}, - {0x0340, 0x09}, - {0x0341, 0xD0}, - {0x0342, 0x0D}, - {0x0343, 0x70}, - {0x0344, 0x00}, - {0x0345, 0x00}, - {0x0346, 0x00}, - {0x0347, 0x00}, - {0x0348, 0x0C}, - {0x0349, 0xCF}, - {0x034A, 0x09}, - {0x034B, 0x9F}, - {0x034C, 0x06}, - {0x034D, 0x68}, - {0x034E, 0x04}, - {0x034F, 0xD0}, - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x01}, - {0x0401, 0x00}, - {0x0405, 0x10}, - {0x3020, 0x10}, - {0x3041, 0x15}, - {0x3042, 0x87}, - {0x3089, 0x4F}, - {0x3309, 0x9A}, - {0x3344, 0x57}, - {0x3345, 0x1F}, - {0x3362, 0x0A}, - {0x3363, 0x0A}, - {0x3364, 0x00}, - {0x3368, 0x18}, - {0x3369, 0x00}, - {0x3370, 0x77}, - {0x3371, 0x2F}, - {0x3372, 0x4F}, - {0x3373, 0x2F}, - {0x3374, 0x2F}, - {0x3375, 0x37}, - {0x3376, 0x9F}, - {0x3377, 0x37}, - {0x33C8, 0x00}, - {0x33D4, 0x06}, - {0x33D5, 0x68}, - {0x33D6, 0x04}, - {0x33D7, 0xD0}, - {0x4100, 0x0E}, - {0x4108, 0x01}, - {0x4109, 0x7C}, +enum { + IMX179_MODE_3280X2464, +}; - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, - {IMX179_TABLE_END, 0x00} +static struct imx179_reg *mode_table[] = { + [IMX179_MODE_3280X2464] = mode_3280x2464, }; -static struct imx179_reg imx179_1920x1080_i2c[] = { - /*stand by*/ - {0x0100, 0x00}, - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, +static void imx179_edp_lowest(struct imx179_info *info) +{ + if (!info->edpc) + return; - {0x0101, 0x00}, - {0x0202, 0x09}, - {0x0203, 0xCC}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0305, 0x06}, - {0x0309, 0x05}, - {0x030B, 0x01}, - {0x030C, 0x00}, - {0x030D, 0xA2}, - {0x0340, 0x09}, - {0x0341, 0xD0}, - {0x0342, 0x0D}, - {0x0343, 0x70}, - {0x0344, 0x02}, - {0x0345, 0xA8}, - {0x0346, 0x02}, - {0x0347, 0xB4}, - {0x0348, 0x0A}, - {0x0349, 0x27}, - {0x034A, 0x06}, - {0x034B, 0xEB}, - {0x034C, 0x07}, - {0x034D, 0x80}, - {0x034E, 0x04}, - {0x034F, 0x38}, - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x00}, - {0x0401, 0x00}, - {0x0405, 0x10}, - {0x3020, 0x10}, - {0x3041, 0x15}, - {0x3042, 0x87}, - {0x3089, 0x4F}, - {0x3309, 0x9A}, - {0x3344, 0x57}, - {0x3345, 0x1F}, - {0x3362, 0x0A}, - {0x3363, 0x0A}, - {0x3364, 0x00}, - {0x3368, 0x18}, - {0x3369, 0x00}, - {0x3370, 0x77}, - {0x3371, 0x2F}, - {0x3372, 0x4F}, - {0x3373, 0x2F}, - {0x3374, 0x2F}, - {0x3375, 0x37}, - {0x3376, 0x9F}, - {0x3377, 0x37}, - {0x33C8, 0x00}, - {0x33D4, 0x07}, - {0x33D5, 0x80}, - {0x33D6, 0x04}, - {0x33D7, 0x38}, - {0x4100, 0x0E}, - {0x4108, 0x01}, - {0x4109, 0x7C}, + info->edp_state = info->edpc->num_states - 1; + dev_dbg(&info->i2c_client->dev, "%s %d\n", __func__, info->edp_state); + if (edp_update_client_request(info->edpc, info->edp_state, NULL)) { + dev_err(&info->i2c_client->dev, "THIS IS NOT LIKELY HAPPEN!\n"); + dev_err(&info->i2c_client->dev, + "UNABLE TO SET LOWEST EDP STATE!\n"); + } +} - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, - {IMX179_TABLE_END, 0x00} -}; +static void imx179_edp_throttle(unsigned int new_state, void *priv_data) +{ + struct imx179_info *info = priv_data; -static struct imx179_reg imx179_1280x720_i2c[] = { - /*stand by*/ - {0x0100, 0x00}, - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, + if (info->pdata && info->pdata->power_off) + info->pdata->power_off(&info->power); +} - {0x0101, 0x00}, - {0x0202, 0x09}, - {0x0203, 0xCC}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0305, 0x06}, - {0x0309, 0x05}, - {0x030B, 0x01}, - {0x030C, 0x00}, - {0x030D, 0xA2}, - {0x0340, 0x09}, - {0x0341, 0xD0}, - {0x0342, 0x0D}, - {0x0343, 0x70}, - {0x0344, 0x01}, - {0x0345, 0x68}, - {0x0346, 0x02}, - {0x0347, 0x00}, - {0x0348, 0x0B}, - {0x0349, 0x67}, - {0x034A, 0x07}, - {0x034B, 0x9F}, - {0x034C, 0x05}, - {0x034D, 0x00}, - {0x034E, 0x02}, - {0x034F, 0xD0}, - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x01}, - {0x0401, 0x00}, - {0x0405, 0x10}, - {0x3020, 0x10}, - {0x3041, 0x15}, - {0x3042, 0x87}, - {0x3089, 0x4F}, - {0x3309, 0x9A}, - {0x3344, 0x57}, - {0x3345, 0x1F}, - {0x3362, 0x0A}, - {0x3363, 0x0A}, - {0x3364, 0x00}, - {0x3368, 0x18}, - {0x3369, 0x00}, - {0x3370, 0x77}, - {0x3371, 0x2F}, - {0x3372, 0x4F}, - {0x3373, 0x2F}, - {0x3374, 0x2F}, - {0x3375, 0x37}, - {0x3376, 0x9F}, - {0x3377, 0x37}, - {0x33C8, 0x00}, - {0x33D4, 0x05}, - {0x33D5, 0x00}, - {0x33D6, 0x02}, - {0x33D7, 0xD0}, - {0x4100, 0x0E}, - {0x4108, 0x01}, - {0x4109, 0x7C}, +static void imx179_edp_register(struct imx179_info *info) +{ + struct edp_manager *edp_manager; + struct edp_client *edpc = &info->pdata->edpc_config; + int ret; - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, - {IMX179_TABLE_END, 0x00} -}; + info->edpc = NULL; + if (!edpc->num_states) { + dev_warn(&info->i2c_client->dev, + "%s: No edp states defined.\n", __func__); + return; + } -static struct imx179_reg imx179_640x480_i2c[] = { - /*stand by*/ - {0x0100, 0x00}, - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, + strncpy(edpc->name, "imx179", EDP_NAME_LEN - 1); + edpc->name[EDP_NAME_LEN - 1] = 0; + edpc->private_data = info; + edpc->throttle = imx179_edp_throttle; - {0x0101, 0x00}, - {0x0202, 0x09}, - {0x0203, 0xCC}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0305, 0x06}, - {0x0309, 0x05}, - {0x030B, 0x01}, - {0x030C, 0x00}, - {0x030D, 0xA2}, - {0x0340, 0x09}, - {0x0341, 0xD0}, - {0x0342, 0x0D}, - {0x0343, 0x70}, - {0x0344, 0x01}, - {0x0345, 0x68}, - {0x0346, 0x01}, - {0x0347, 0x10}, - {0x0348, 0x0B}, - {0x0349, 0x67}, - {0x034A, 0x08}, - {0x034B, 0x8F}, - {0x034C, 0x02}, - {0x034D, 0x80}, - {0x034E, 0x01}, - {0x034F, 0xE0}, - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x02}, - {0x0401, 0x00}, - {0x0405, 0x10}, - {0x3020, 0x10}, - {0x3041, 0x15}, - {0x3042, 0x87}, - {0x3089, 0x4F}, - {0x3309, 0x9A}, - {0x3344, 0x57}, - {0x3345, 0x1F}, - {0x3362, 0x0A}, - {0x3363, 0x0A}, - {0x3364, 0x00}, - {0x3368, 0x18}, - {0x3369, 0x00}, - {0x3370, 0x77}, - {0x3371, 0x2F}, - {0x3372, 0x4F}, - {0x3373, 0x2F}, - {0x3374, 0x2F}, - {0x3375, 0x37}, - {0x3376, 0x9F}, - {0x3377, 0x37}, - {0x33C8, 0x00}, - {0x33D4, 0x02}, - {0x33D5, 0x80}, - {0x33D6, 0x01}, - {0x33D7, 0xE0}, - {0x4100, 0x0E}, - {0x4108, 0x01}, - {0x4109, 0x7C}, + dev_dbg(&info->i2c_client->dev, "%s: %s, e0 = %d, p %d\n", + __func__, edpc->name, edpc->e0_index, edpc->priority); + for (ret = 0; ret < edpc->num_states; ret++) + dev_dbg(&info->i2c_client->dev, "e%d = %d mA", + ret - edpc->e0_index, edpc->states[ret]); - {IMX179_TABLE_WAIT_MS, IMX179_WAIT_MS}, - {IMX179_TABLE_END, 0x00} -}; -/* Each resolution requires the below data table setup and the corresponding - * I2C data table. - * If more NVC data is needed for the NVC driver, be sure and modify the - * nvc_imager_nvc structure in nvc_imager.h - * If more data sets are needed per resolution, they can be added to the - * table format below with the imx179_mode_data structure. New data sets - * should conform to an already defined NVC structure. If it's data for the - * NVC driver, then it should be added to the nvc_imager_nvc structure. - * Steps to add a resolution: - * 1. Add I2C data table - * 2. Add imx179_mode_data table - * 3. Add entry to the imx179_mode_table - */ -static struct imx179_mode_data imx179_3280x2464 = { - .sensor_mode = { - .res_x = 3280, - .res_y = 2464, - .active_start_x = 0, - .active_stary_y = 0, - .peak_frame_rate = 30000, /* / _INT2FLOAT_DIVISOR */ - .pixel_aspect_ratio = 1000, /* / _INT2FLOAT_DIVISOR */ - .pll_multiplier = 11000, /* / _INT2FLOAT_DIVISOR */ - .crop_mode = NVC_IMAGER_CROPMODE_NONE, - }, - .sensor_dnvc = { - .api_version = NVC_IMAGER_API_DYNAMIC_VER, - .region_start_x = 0, - .region_start_y = 0, - .x_scale = 1, - .y_scale = 1, - .bracket_caps = 1, - .flush_count = 2, - .init_intra_frame_skip = 0, - .ss_intra_frame_skip = 2, - .ss_frame_number = 3, - .coarse_time = 0x09CC, - .max_coarse_diff = 5, - .min_exposure_course = 2, - .max_exposure_course = 0xFFFC, - .diff_integration_time = 110, /* / _INT2FLOAT_DIVISOR */ - .line_length = 0x0D70, - .frame_length = 0x09D0, - .min_frame_length = 0x09D0, - .max_frame_length = 0xFFFF, - .min_gain = 1, /* / _INT2FLOAT_DIVISOR */ - .max_gain = 16000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain = 1000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain_bin_en = 1000, /* / _INT2FLOAT_DIVISOR */ - .support_bin_control = 0, - .support_fast_mode = 0, - .pll_mult = 0xA2, - .pll_div = 0x06, - }, - .p_mode_i2c = imx179_3280x2464_i2c, -}; + edp_manager = edp_get_manager("battery"); + if (!edp_manager) { + dev_err(&info->i2c_client->dev, + "unable to get edp manager: battery\n"); + return; + } -static struct imx179_mode_data imx179_1640x1232 = { - .sensor_mode = { - .res_x = 1640, - .res_y = 1232, - .active_start_x = 0, - .active_stary_y = 0, - .peak_frame_rate = 30000, /* / _INT2FLOAT_DIVISOR */ - .pixel_aspect_ratio = 1000, /* / _INT2FLOAT_DIVISOR */ - .pll_multiplier = 11000, /* / _INT2FLOAT_DIVISOR */ - .crop_mode = NVC_IMAGER_CROPMODE_NONE, - }, - .sensor_dnvc = { - .api_version = NVC_IMAGER_API_DYNAMIC_VER, - .region_start_x = 0, - .region_start_y = 0, - .x_scale = 1, - .y_scale = 1, - .bracket_caps = 1, - .flush_count = 2, - .init_intra_frame_skip = 0, - .ss_intra_frame_skip = 2, - .ss_frame_number = 3, - .coarse_time = 0x09CC, - .max_coarse_diff = 5, - .min_exposure_course = 2, - .max_exposure_course = 0xFFFC, - .diff_integration_time = 110, /* / _INT2FLOAT_DIVISOR */ - .line_length = 0x0D70, - .frame_length = 0x09D0, - .min_frame_length = 0x09D0, - .max_frame_length = 0xFFFF, - .min_gain = 1, /* / _INT2FLOAT_DIVISOR */ - .max_gain = 16000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain = 1000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain_bin_en = 1000, /* / _INT2FLOAT_DIVISOR */ - .support_bin_control = 0, - .support_fast_mode = 0, - .pll_mult = 0xA2, - .pll_div = 0x06, - }, - .p_mode_i2c = imx179_1640x1232_i2c, -}; + ret = edp_register_client(edp_manager, edpc); + if (ret) { + dev_err(&info->i2c_client->dev, + "unable to register edp client\n"); + return; + } -static struct imx179_mode_data imx179_1920x1080 = { - .sensor_mode = { - .res_x = 1920, - .res_y = 1080, - .active_start_x = 0, - .active_stary_y = 0, - .peak_frame_rate = 30000, /* / _INT2FLOAT_DIVISOR */ - .pixel_aspect_ratio = 1000, /* / _INT2FLOAT_DIVISOR */ - .pll_multiplier = 11000, /* / _INT2FLOAT_DIVISOR */ - .crop_mode = NVC_IMAGER_CROPMODE_NONE, - }, - .sensor_dnvc = { - .api_version = NVC_IMAGER_API_DYNAMIC_VER, - .region_start_x = 0, - .region_start_y = 0, - .x_scale = 1, - .y_scale = 1, - .bracket_caps = 1, - .flush_count = 2, - .init_intra_frame_skip = 0, - .ss_intra_frame_skip = 2, - .ss_frame_number = 3, - .coarse_time = 0x09CC, - .max_coarse_diff = 5, - .min_exposure_course = 2, - .max_exposure_course = 0xFFFC, - .diff_integration_time = 110, /* / _INT2FLOAT_DIVISOR */ - .line_length = 0x0D70, - .frame_length = 0x09D0, - .min_frame_length = 0x09D0, - .max_frame_length = 0xFFFF, - .min_gain = 1, /* / _INT2FLOAT_DIVISOR */ - .max_gain = 16000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain = 1000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain_bin_en = 1000, /* / _INT2FLOAT_DIVISOR */ - .support_bin_control = 0, - .support_fast_mode = 0, - .pll_mult = 0xA2, - .pll_div = 0x06, - }, - .p_mode_i2c = imx179_1920x1080_i2c, -}; + info->edpc = edpc; + /* set to lowest state at init */ + imx179_edp_lowest(info); +} -static struct imx179_mode_data imx179_1280x720 = { - .sensor_mode = { - .res_x = 1280, - .res_y = 720, - .active_start_x = 0, - .active_stary_y = 0, - .peak_frame_rate = 30000, /* / _INT2FLOAT_DIVISOR */ - .pixel_aspect_ratio = 1000, /* / _INT2FLOAT_DIVISOR */ - .pll_multiplier = 11000, /* / _INT2FLOAT_DIVISOR */ - .crop_mode = NVC_IMAGER_CROPMODE_NONE, - }, - .sensor_dnvc = { - .api_version = NVC_IMAGER_API_DYNAMIC_VER, - .region_start_x = 0, - .region_start_y = 0, - .x_scale = 1, - .y_scale = 1, - .bracket_caps = 1, - .flush_count = 2, - .init_intra_frame_skip = 0, - .ss_intra_frame_skip = 2, - .ss_frame_number = 3, - .coarse_time = 0x09CC, - .max_coarse_diff = 5, - .min_exposure_course = 2, - .max_exposure_course = 0xFFFC, - .diff_integration_time = 110, /* / _INT2FLOAT_DIVISOR */ - .line_length = 0x0D70, - .frame_length = 0x09D0, - .min_frame_length = 0x09D0, - .max_frame_length = 0xFFFF, - .min_gain = 1, /* / _INT2FLOAT_DIVISOR */ - .max_gain = 16000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain = 1000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain_bin_en = 1000, /* / _INT2FLOAT_DIVISOR */ - .support_bin_control = 0, - .support_fast_mode = 0, - .pll_mult = 0xA2, - .pll_div = 0x06, - }, - .p_mode_i2c = imx179_1280x720_i2c, -}; +static int imx179_edp_req(struct imx179_info *info, unsigned new_state) +{ + unsigned approved; + int ret = 0; -static struct imx179_mode_data imx179_640x480 = { - .sensor_mode = { - .res_x = 640, - .res_y = 480, - .active_start_x = 0, - .active_stary_y = 0, - .peak_frame_rate = 30000, /* / _INT2FLOAT_DIVISOR */ - .pixel_aspect_ratio = 1000, /* / _INT2FLOAT_DIVISOR */ - .pll_multiplier = 11000, /* / _INT2FLOAT_DIVISOR */ - .crop_mode = NVC_IMAGER_CROPMODE_NONE, - }, - .sensor_dnvc = { - .api_version = NVC_IMAGER_API_DYNAMIC_VER, - .region_start_x = 0, - .region_start_y = 0, - .x_scale = 1, - .y_scale = 1, - .bracket_caps = 1, - .flush_count = 2, - .init_intra_frame_skip = 0, - .ss_intra_frame_skip = 2, - .ss_frame_number = 3, - .coarse_time = 0x09CC, - .max_coarse_diff = 5, - .min_exposure_course = 2, - .max_exposure_course = 0xFFFC, - .diff_integration_time = 110, /* / _INT2FLOAT_DIVISOR */ - .line_length = 0x0D70, - .frame_length = 0x09D0, - .min_frame_length = 0x09D0, - .max_frame_length = 0xFFFF, - .min_gain = 1, /* / _INT2FLOAT_DIVISOR */ - .max_gain = 16000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain = 1000, /* / _INT2FLOAT_DIVISOR */ - .inherent_gain_bin_en = 1000, /* / _INT2FLOAT_DIVISOR */ - .support_bin_control = 0, - .support_fast_mode = 0, - .pll_mult = 0xA2, - .pll_div = 0x06, - }, - .p_mode_i2c = imx179_640x480_i2c, -}; + if (!info->edpc) + return 0; -static struct imx179_mode_data *imx179_mode_table[] = { - &imx179_3280x2464, - &imx179_1640x1232, - &imx179_1920x1080, - &imx179_1280x720, - &imx179_640x480, -}; + dev_dbg(&info->i2c_client->dev, "%s %d\n", __func__, new_state); + ret = edp_update_client_request(info->edpc, new_state, &approved); + if (ret) { + dev_err(&info->i2c_client->dev, "E state transition failed\n"); + return ret; + } -static int imx179_i2c_rd8(struct imx179_info *info, u16 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[3]; - - buf[0] = (reg >> 8); - buf[1] = (reg & 0x00FF); - msg[0].addr = info->i2c_client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = &buf[0]; - msg[1].addr = info->i2c_client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &buf[2]; - *val = 0; - if (i2c_transfer(info->i2c_client->adapter, msg, 2) != 2) - return -EIO; - - *val = buf[2]; + if (approved > new_state) { + dev_err(&info->i2c_client->dev, "EDP no enough current\n"); + return -ENODEV; + } + + info->edp_state = approved; return 0; } -static int imx179_i2c_rd16(struct imx179_info *info, u16 reg, u16 *val) +static inline void +msleep_range(unsigned int delay_base) { - struct i2c_msg msg[2]; - u8 buf[4]; - - buf[0] = (reg >> 8); - buf[1] = (reg & 0x00FF); - msg[0].addr = info->i2c_client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = &buf[0]; - msg[1].addr = info->i2c_client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 2; - msg[1].buf = &buf[2]; - *val = 0; - if (i2c_transfer(info->i2c_client->adapter, msg, 2) != 2) - return -EIO; - - *val = (((u16)buf[2] << 8) | (u16)buf[3]); - return 0; + usleep_range(delay_base*1000, delay_base*1000+500); } -static int imx179_i2c_wr8(struct imx179_info *info, u16 reg, u8 val) +static inline void +imx179_get_frame_length_regs(struct imx179_reg *regs, u32 frame_length) { - struct i2c_msg msg; - u8 buf[3]; - - buf[0] = (reg >> 8); - buf[1] = (reg & 0x00FF); - buf[2] = val; - msg.addr = info->i2c_client->addr; - msg.flags = 0; - msg.len = 3; - msg.buf = &buf[0]; - if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; + regs->addr = IMX179_FRAME_LENGTH_ADDR_MSB; + regs->val = (frame_length >> 8) & 0xff; + (regs + 1)->addr = IMX179_FRAME_LENGTH_ADDR_LSB; + (regs + 1)->val = (frame_length) & 0xff; } -static int imx179_i2c_wr16(struct imx179_info *info, u16 reg, u16 val) +static inline void +imx179_get_coarse_time_regs(struct imx179_reg *regs, u32 coarse_time) { - struct i2c_msg msg; - u8 buf[4]; - - buf[0] = (reg >> 8); - buf[1] = (reg & 0x00FF); - buf[2] = (val & 0x00FF); - buf[3] = (val >> 8); - msg.addr = info->i2c_client->addr; - msg.flags = 0; - msg.len = 4; - msg.buf = &buf[0]; - if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; + regs->addr = IMX179_COARSE_TIME_ADDR_MSB; + regs->val = (coarse_time >> 8) & 0xff; + (regs + 1)->addr = IMX179_COARSE_TIME_ADDR_LSB; + (regs + 1)->val = (coarse_time) & 0xff; } -static int imx179_i2c_rd_table(struct imx179_info *info, - struct imx179_reg table[]) +static inline void +imx179_get_gain_reg(struct imx179_reg *regs, u16 gain) { - struct imx179_reg *p_table = table; - u8 val; - int err = 0; - - while (p_table->addr != IMX179_TABLE_END) { - err = imx179_i2c_rd8(info, p_table->addr, &val); - if (err) - return err; - - p_table->val = (u16)val; - p_table++; - } + regs->addr = IMX179_GAIN_ADDR; + regs->val = gain; +} - return err; +static inline int +imx179_read_reg(struct imx179_info *info, u16 addr, u8 *val) +{ + return regmap_read(info->regmap, addr, (unsigned int *) val); } -static int imx179_i2c_wr_blk(struct imx179_info *info, u8 *buf, int len) +static int +imx179_write_reg(struct imx179_info *info, u16 addr, u8 val) { - struct i2c_msg msg; + int err; - msg.addr = info->i2c_client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = buf; - if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1) - return -EIO; + pr_err("%s:i2c write, %x = %x\n", + __func__, addr, val); + err = regmap_write(info->regmap, addr, val); - return 0; + if (err) + pr_err("%s:i2c write failed, %x = %x\n", + __func__, addr, val); + + return err; } -static int imx179_i2c_wr_table(struct imx179_info *info, - struct imx179_reg table[]) +static int +imx179_write_table(struct imx179_info *info, + const struct imx179_reg table[], + const struct imx179_reg override_list[], + int num_override_regs) { int err; const struct imx179_reg *next; - const struct imx179_reg *n_next; - u8 *b_ptr = info->i2c_buf; - u16 buf_count = 0; + int i; + u16 val; for (next = table; next->addr != IMX179_TABLE_END; next++) { if (next->addr == IMX179_TABLE_WAIT_MS) { - msleep(next->val); + msleep_range(next->val); continue; } - if (!buf_count) { - b_ptr = info->i2c_buf; - *b_ptr++ = next->addr >> 8; - *b_ptr++ = next->addr & 0xFF; - buf_count = 2; + val = next->val; + + /* When an override list is passed in, replace the reg */ + /* value to write if the reg is in the list */ + if (override_list) { + for (i = 0; i < num_override_regs; i++) { + if (next->addr == override_list[i].addr) { + val = override_list[i].val; + break; + } + } } - *b_ptr++ = next->val; - buf_count++; - n_next = next + 1; - if (n_next->addr == next->addr + 1 && - n_next->addr != IMX179_TABLE_WAIT_MS && - buf_count < IMX179_SIZEOF_I2C_BUF && - n_next->addr != IMX179_TABLE_END) - continue; - err = imx179_i2c_wr_blk(info, info->i2c_buf, buf_count); - if (err) + err = imx179_write_reg(info, next->addr, val); + if (err) { + pr_err("%s:imx179_write_table:%d", __func__, err); return err; - - buf_count = 0; + } } - return 0; } -static inline void imx179_frame_length_reg(struct imx179_reg *regs, - u32 frame_length) +static int imx179_get_flash_cap(struct imx179_info *info) { - regs->addr = 0x0340; - regs->val = (frame_length >> 8) & 0xFF; - (regs + 1)->addr = 0x0341; - (regs + 1)->val = (frame_length) & 0xFF; -} + struct imx179_flash_control *fctl; -static inline void imx179_coarse_time_reg(struct imx179_reg *regs, - u32 coarse_time) -{ - regs->addr = 0x0202; - regs->val = (coarse_time >> 8) & 0xFF; - (regs + 1)->addr = 0x0203; - (regs + 1)->val = (coarse_time) & 0xFF; + dev_dbg(&info->i2c_client->dev, "%s: %p\n", __func__, info->pdata); + if (info->pdata) { + fctl = &info->pdata->flash_cap; + dev_dbg(&info->i2c_client->dev, + "edg: %x, st: %x, rpt: %x, dl: %x\n", + fctl->edge_trig_en, + fctl->start_edge, + fctl->repeat, + fctl->delay_frm); + + if (fctl->enable) + return 0; + } + return -ENODEV; } -static inline void imx179_gain_reg(struct imx179_reg *regs, u32 gain) +static inline int imx179_set_flash_control( + struct imx179_info *info, struct imx179_flash_control *fc) { - regs->addr = 0x0205; - regs->val = gain & 0xFF; + dev_dbg(&info->i2c_client->dev, "%s\n", __func__); + return imx179_write_reg(info, 0x0802, 0x01); } -static int imx179_bin_wr(struct imx179_info *info, u8 enable) +static int +imx179_set_mode(struct imx179_info *info, struct imx179_mode *mode) { - int err = 0; + int sensor_mode; + int err; + struct imx179_reg reg_list[8]; - if (enable == info->bin_en) - return 0; + pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u\n", + __func__, mode->xres, mode->yres, mode->frame_length, + mode->coarse_time, mode->gain); - if (!info->mode_valid || !imx179_mode_table[info->mode_index]-> - sensor_dnvc.support_bin_control) + if (mode->xres == 3280 && mode->yres == 2464) { + sensor_mode = IMX179_MODE_3280X2464; + } else { + pr_err("%s: invalid resolution supplied to set mode %d %d\n", + __func__, mode->xres, mode->yres); return -EINVAL; + } - if (!err) - info->bin_en = enable; - dev_dbg(&info->i2c_client->dev, "%s bin_en=%x err=%d\n", - __func__, info->bin_en, err); - return err; -} - -static int imx179_exposure_wr(struct imx179_info *info, - struct nvc_imager_bayer *mode) -{ - struct imx179_reg reg_list[8]; - int err; + /* request highest edp state */ + err = imx179_edp_req(info, 0); + if (err) { + dev_err(&info->i2c_client->dev, + "%s: ERROR cannot set edp state! %d\n", __func__, err); + return err; + } - reg_list[0].addr = 0x0104; - reg_list[0].val = 0x01; - imx179_frame_length_reg(reg_list+1, mode->frame_length); - imx179_coarse_time_reg(reg_list + 3, mode->coarse_time); - imx179_gain_reg(reg_list + 5, mode->gain); - reg_list[6].addr = 0x0104; - reg_list[6].val = 0x00; - reg_list[7].addr = IMX179_TABLE_END; - err = imx179_i2c_wr_table(info, reg_list); - if (!err) - err = imx179_bin_wr(info, mode->bin_en); - return err; -} + /* get a list of override regs for the asking frame length, */ + /* coarse integration time, and gain. */ + imx179_get_frame_length_regs(reg_list, mode->frame_length); + imx179_get_coarse_time_regs(reg_list + 2, mode->coarse_time); + imx179_get_gain_reg(reg_list + 4, mode->gain); -static int imx179_gain_wr(struct imx179_info *info, u32 gain) -{ - int err; + err = imx179_write_table(info, + mode_table[sensor_mode], + reg_list, 5); + if (err) + return err; + if (err) + return err; - gain &= 0xFF; - err = imx179_i2c_wr16(info, 0x0205, (u16)gain); - return err; + info->mode = sensor_mode; + pr_info("[IMX179]: stream on.\n"); + return 0; } -static int imx179_gain_rd(struct imx179_info *info, u32 *gain) +static int +imx179_get_status(struct imx179_info *info, u8 *dev_status) { - int err; - - *gain = 0; - err = imx179_i2c_rd8(info, 0x0205, (u8 *)gain); - return err; + *dev_status = 0; + return 0; } -static int imx179_group_hold_wr(struct imx179_info *info, - struct nvc_imager_ae *ae) +static int +imx179_set_frame_length(struct imx179_info *info, u32 frame_length, + bool group_hold) { - int err; - bool groupHoldEnable; - struct imx179_reg reg_list[6]; - int count = 0; + struct imx179_reg reg_list[2]; + int i = 0; + int ret; - groupHoldEnable = ae->gain_enable | - ae->frame_length_enable | - ae->coarse_time_enable; + imx179_get_frame_length_regs(reg_list, frame_length); - if (groupHoldEnable) { - err = imx179_i2c_wr8(info, 0x0104, 1); - if (err) { - dev_err(&info->i2c_client->dev, - "Error: %s fail to enable grouphold\n", - __func__); - return err; - } + if (group_hold) { + ret = imx179_write_reg(info, 0x0104, 0x01); + if (ret) + return ret; } - if (ae->gain_enable) { - imx179_gain_reg(reg_list + count, ae->gain); - count += 1; - } - if (ae->coarse_time_enable) { - imx179_coarse_time_reg(reg_list + count, ae->coarse_time); - count += 2; - } - if (ae->frame_length_enable) { - imx179_frame_length_reg(reg_list + count, ae->frame_length); - count += 2; - } - reg_list[count].addr = IMX179_TABLE_END; - err = imx179_i2c_wr_table(info, reg_list); - if (err) { - dev_err(&info->i2c_client->dev, "Error: %s i2c wr_table fail\n", - __func__); + for (i = 0; i < 2; i++) { + ret = imx179_write_reg(info, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; } - if (groupHoldEnable) { - err = imx179_i2c_wr8(info, 0x0104, 0); - if (err) { - dev_err(&info->i2c_client->dev, - "Error: %s fail to release grouphold\n", - __func__); - } + if (group_hold) { + ret = imx179_write_reg(info, 0x0104, 0x0); + if (ret) + return ret; } - return err; -} -static int imx179_test_pattern_wr(struct imx179_info *info, unsigned pattern) -{ - if (pattern >= ARRAY_SIZE(test_patterns)) - return -EINVAL; - - return imx179_i2c_wr_table(info, test_patterns[pattern]); + return 0; } -static int imx179_set_flash_output(struct imx179_info *info) +static int +imx179_set_coarse_time(struct imx179_info *info, u32 coarse_time, + bool group_hold) { - struct imx179_flash_config *fcfg; - u8 val = 0; - int ret = 0; + int ret; - if (!info->pdata) - return 0; + struct imx179_reg reg_list[2]; + int i = 0; - fcfg = &info->pdata->flash_cap; - if (fcfg->xvs_trigger_enabled) - val |= 0x0c; - if (fcfg->sdo_trigger_enabled) - val |= 0x02; - dev_dbg(&info->i2c_client->dev, "%s: %02x\n", __func__, val); - /* disable all flash pulse output */ - ret = imx179_i2c_wr8(info, 0x304A, 0); - /* config XVS/SDO pin output mode */ - ret |= imx179_i2c_wr8(info, 0x3240, val); - /* set the control pulse width settings - Gain + Step - * Pulse width(sec) = 64 * 2^(Gain) * (Step + 1) / Logic Clk - * Logic Clk = ExtClk * PLL Multipiler / Pre_Div / Post_Div - * / Logic Clk Division Ratio - * Logic Clk Division Ratio = 5 @4lane, 10 @2lane, 20 @1lane - */ - ret |= imx179_i2c_wr8(info, 0x307C, 0x07); - ret |= imx179_i2c_wr8(info, 0x307D, 0x3F); - return ret; -} + imx179_get_coarse_time_regs(reg_list, coarse_time); -static void imx179_get_flash_cap(struct imx179_info *info) -{ - struct nvc_imager_cap *fcap = info->cap; - struct imx179_flash_config *fcfg; + if (group_hold) { + ret = imx179_write_reg(info, 0x104, 0x01); + if (ret) + return ret; + } - if (!info->pdata) - return; + for (i = 0; i < 2; i++) { + ret = imx179_write_reg(info, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } - fcfg = &info->pdata->flash_cap; - fcap->flash_control_enabled = - fcfg->xvs_trigger_enabled | fcfg->sdo_trigger_enabled; - fcap->adjustable_flash_timing = fcfg->adjustable_flash_timing; + if (group_hold) { + ret = imx179_write_reg(info, 0x104, 0x0); + if (ret) + return ret; + } + return 0; } -static int imx179_flash_control( - struct imx179_info *info, union nvc_imager_flash_control *fm) +static int +imx179_set_gain(struct imx179_info *info, u16 gain, bool group_hold) { int ret; - u8 f_cntl; - u8 f_tim; + struct imx179_reg reg_list; - if (!info->pdata) - return -EFAULT; + imx179_get_gain_reg(®_list, gain); - ret = imx179_i2c_wr8(info, 0x304A, 0); - f_tim = 0; - f_cntl = 0; - if (fm->settings.enable) { - if (fm->settings.edge_trig_en) { - f_cntl |= 0x10; - if (fm->settings.start_edge) - f_tim |= 0x08; - if (fm->settings.repeat) - f_tim |= 0x04; - f_tim |= fm->settings.delay_frm & 0x03; - } else - f_cntl |= 0x20; + if (group_hold) { + ret = imx179_write_reg(info, 0x104, 0x1); + if (ret) + return ret; } - ret |= imx179_i2c_wr8(info, 0x307B, f_tim); - ret |= imx179_i2c_wr8(info, 0x304A, f_cntl); - dev_dbg(&info->i2c_client->dev, - "%s: %04x %02x %02x\n", __func__, fm->mode, f_tim, f_cntl); - return ret; -} + ret = imx179_write_reg(info, reg_list.addr, reg_list.val); + if (ret) + return ret; -static int imx179_gpio_rd(struct imx179_info *info, - enum imx179_gpio i) -{ - int val = -EINVAL; - - if (info->gpio[i].flag) { - val = gpio_get_value_cansleep(info->gpio[i].gpio); - if (val) - val = 1; - dev_dbg(&info->i2c_client->dev, "%s %u %d\n", - __func__, info->gpio[i].gpio, val); - if (!info->gpio[i].active_high) - val = !val; - val &= 1; + if (group_hold) { + ret = imx179_write_reg(info, 0x104, 0x0); + if (ret) + return ret; } - return val; /* return read value or error */ + return 0; } -static int imx179_gpio_wr(struct imx179_info *info, - enum imx179_gpio i, - int val) /* val: 0=deassert, 1=assert */ +static int +imx179_set_group_hold(struct imx179_info *info, struct imx179_ae *ae) { - int err = -EINVAL; - - if (info->gpio[i].flag) { - if (val) - val = 1; - if (!info->gpio[i].active_high) - val = !val; - val &= 1; - err = val; - gpio_set_value_cansleep(info->gpio[i].gpio, val); - dev_dbg(&info->i2c_client->dev, "%s %u %d\n", - __func__, info->gpio[i].gpio, val); + int ret; + int count = 0; + bool group_hold_enabled = false; + + if (ae->gain_enable) + count++; + if (ae->coarse_time_enable) + count++; + if (ae->frame_length_enable) + count++; + if (count >= 2) + group_hold_enabled = true; + + if (group_hold_enabled) { + ret = imx179_write_reg(info, 0x104, 0x1); + if (ret) + return ret; } - return err; /* return value written or error */ -} - -static int imx179_gpio_pwrdn(struct imx179_info *info, int val) -{ - int prev_val; - prev_val = imx179_gpio_rd(info, IMX179_GPIO_PWDN); - if (prev_val < 0) - return 1; /* assume PWRDN hardwired deasserted */ - - if (val == prev_val) - return 0; /* no change */ - - imx179_gpio_wr(info, IMX179_GPIO_PWDN, val); - return 1; /* return state change */ -} - -static int imx179_gpio_reset(struct imx179_info *info, int val) -{ - int err = 0; - - if (val) { - if (!info->reset_flag) { - info->reset_flag = true; - err = imx179_gpio_wr(info, IMX179_GPIO_RESET, 1); - if (err < 0) - return 0; /* flag no reset */ - - usleep_range(1000, 1500); - imx179_gpio_wr(info, IMX179_GPIO_RESET, 0); - msleep(IMX179_STARTUP_DELAY_MS); /* startup delay */ - err = 1; /* flag that a reset was done */ - } - } else { - info->reset_flag = false; + if (ae->gain_enable) + imx179_set_gain(info, ae->gain, false); + if (ae->coarse_time_enable) + imx179_set_coarse_time(info, ae->coarse_time, true); + if (ae->frame_length_enable) + imx179_set_frame_length(info, ae->frame_length, false); + + if (group_hold_enabled) { + ret = imx179_write_reg(info, 0x104, 0x0); + if (ret) + return ret; } - return err; -} -static void imx179_gpio_able(struct imx179_info *info, int val) -{ - if (val) - imx179_gpio_wr(info, IMX179_GPIO_GP1, val); - else - imx179_gpio_wr(info, IMX179_GPIO_GP1, val); + return 0; } -static void imx179_gpio_exit(struct imx179_info *info) +static int imx179_get_sensor_id(struct imx179_info *info) { - unsigned i; + int ret = 0; + int i; + u8 bak = 0; - for (i = 0; i < ARRAY_SIZE(imx179_gpios); i++) { - if (info->gpio[i].flag && info->gpio[i].own) { - gpio_free(info->gpio[i].gpio); - info->gpio[i].own = false; - } - } -} + pr_info("%s\n", __func__); + if (info->sensor_data.fuse_id_size) + return 0; -static void imx179_gpio_init(struct imx179_info *info) -{ - char label[32]; - unsigned long flags; - unsigned type; - unsigned i; - unsigned j; - int err; + /* Note 1: If the sensor does not have power at this point + Need to supply the power, e.g. by calling power on function */ - for (i = 0; i < ARRAY_SIZE(imx179_gpios); i++) - info->gpio[i].flag = false; - if (!info->pdata->gpio_count || !info->pdata->gpio) - return; + /*ret |= imx179_write_reg(info, 0x3B02, 0x00); + ret |= imx179_write_reg(info, 0x3B00, 0x01); + for (i = 0; i < 9; i++) { + ret |= imx179_read_reg(info, 0x3B24 + i, &bak); + info->sensor_data.fuse_id[i] = bak; + } - for (i = 0; i < ARRAY_SIZE(imx179_gpios); i++) { - type = imx179_gpios[i].gpio_type; - for (j = 0; j < info->pdata->gpio_count; j++) { - if (type == info->pdata->gpio[j].gpio_type) - break; - } - if (j == info->pdata->gpio_count) - continue; + if (!ret) + info->sensor_data.fuse_id_size = i;*/ - info->gpio[type].gpio = info->pdata->gpio[j].gpio; - info->gpio[type].flag = true; - if (imx179_gpios[i].use_flags) { - flags = imx179_gpios[i].flags; - info->gpio[type].active_high = - imx179_gpios[i].active_high; - } else { - info->gpio[type].active_high = - info->pdata->gpio[j].active_high; - if (info->gpio[type].active_high) - flags = GPIOF_OUT_INIT_LOW; - else - flags = GPIOF_OUT_INIT_HIGH; - } - if (!info->pdata->gpio[j].init_en) - continue; + /* Note 2: Need to clean up any action carried out in Note 1 */ - snprintf(label, sizeof(label), "imx179_%u_%s", - info->pdata->num, imx179_gpios[i].label); - err = gpio_request_one(info->gpio[type].gpio, flags, label); - if (err) { - dev_err(&info->i2c_client->dev, "%s ERR %s %u\n", - __func__, label, info->gpio[type].gpio); - } else { - info->gpio[type].own = true; - dev_dbg(&info->i2c_client->dev, "%s %s %u\n", - __func__, label, info->gpio[type].gpio); - } - } + return ret; } static void imx179_mclk_disable(struct imx179_info *info) @@ -1296,8 +583,7 @@ static void imx179_mclk_disable(struct imx179_info *info) static int imx179_mclk_enable(struct imx179_info *info) { int err; - unsigned long mclk_init_rate = - nvc_imager_get_mclk(info->cap, &imx179_dflt_cap, 0); + unsigned long mclk_init_rate = 24000000; dev_dbg(&info->i2c_client->dev, "%s: enable MCLK with %lu Hz\n", __func__, mclk_init_rate); @@ -1305,1242 +591,527 @@ static int imx179_mclk_enable(struct imx179_info *info) err = clk_set_rate(info->mclk, mclk_init_rate); if (!err) err = clk_prepare_enable(info->mclk); - return err; } -static int imx179_vreg_dis_all(struct imx179_info *info) -{ - int err; - - if (!info->pdata || !info->pdata->power_off) - return -EFAULT; - - err = info->pdata->power_off(info->vreg); - - imx179_mclk_disable(info); - - return err; -} - -static int imx179_vreg_en_all(struct imx179_info *info) +static long +imx179_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { int err = 0; - if (!info->pdata || !info->pdata->power_on) - return -EFAULT; - - err = imx179_mclk_enable(info); - if (err) - return err; - - err = info->pdata->power_on(info->vreg); - if (err < 0) - imx179_mclk_disable(info); - - return err; -} - -static void imx179_vreg_exit(struct imx179_info *info) -{ - unsigned i; + struct imx179_info *info = file->private_data; - for (i = 0; i < ARRAY_SIZE(imx179_vregs); i++) { - regulator_put(info->vreg[i].vreg); - info->vreg[i].vreg = NULL; + switch (cmd) { + case IMX179_IOCTL_SET_POWER: + if (!info->pdata) + break; + if (arg && info->pdata->power_on) { + err = imx179_mclk_enable(info); + if (!err) + err = info->pdata->power_on(&info->power); + if (err < 0) + imx179_mclk_disable(info); + } + if (!arg && info->pdata->power_off) { + info->pdata->power_off(&info->power); + imx179_mclk_disable(info); + imx179_edp_lowest(info); + } + break; + case IMX179_IOCTL_SET_MODE: + { + struct imx179_mode mode; + if (copy_from_user(&mode, (const void __user *)arg, + sizeof(struct imx179_mode))) { + pr_err("%s:Failed to get mode from user.\n", __func__); + return -EFAULT; + } + return imx179_set_mode(info, &mode); } -} - -static int imx179_vreg_init(struct imx179_info *info) -{ - unsigned i; - unsigned j; - int err = 0; + case IMX179_IOCTL_SET_FRAME_LENGTH: + return imx179_set_frame_length(info, (u32)arg, true); + case IMX179_IOCTL_SET_COARSE_TIME: + return imx179_set_coarse_time(info, (u32)arg, true); + case IMX179_IOCTL_SET_GAIN: + return imx179_set_gain(info, (u16)arg, true); + case IMX179_IOCTL_GET_STATUS: + { + u8 status; - for (i = 0; i < ARRAY_SIZE(imx179_vregs); i++) { - j = imx179_vregs[i].vreg_num; - info->vreg[j].vreg_name = imx179_vregs[i].vreg_name; - info->vreg[j].vreg_flag = false; - info->vreg[j].vreg = regulator_get(&info->i2c_client->dev, - info->vreg[j].vreg_name); - if (IS_ERR(info->vreg[j].vreg)) { - dev_dbg(&info->i2c_client->dev, "%s %s ERR: %d\n", - __func__, info->vreg[j].vreg_name, - (int)info->vreg[j].vreg); - err |= PTR_ERR(info->vreg[j].vreg); - info->vreg[j].vreg = NULL; - } else { - dev_dbg(&info->i2c_client->dev, "%s: %s\n", - __func__, info->vreg[j].vreg_name); + err = imx179_get_status(info, &status); + if (err) + return err; + if (copy_to_user((void __user *)arg, &status, 1)) { + pr_err("%s:Failed to copy status to user\n", __func__); + return -EFAULT; } + return 0; } - return err; -} - -static int imx179_pm_wr(struct imx179_info *info, int pwr) -{ - int ret; - int err = 0; + case IMX179_IOCTL_GET_SENSORDATA: + { + err = imx179_get_sensor_id(info); - if ((info->pdata->cfg & (NVC_CFG_OFF2STDBY | NVC_CFG_BOOT_INIT)) && - (pwr == NVC_PWR_OFF || - pwr == NVC_PWR_STDBY_OFF)) - pwr = NVC_PWR_STDBY; - if (pwr == info->pwr_dev) + if (err) { + pr_err("%s:Failed to get fuse id info.\n", __func__); + return err; + } + if (copy_to_user((void __user *)arg, &info->sensor_data, + sizeof(struct imx179_sensordata))) { + pr_info("%s:Failed to copy fuse id to user space\n", + __func__); + return -EFAULT; + } return 0; + } + case IMX179_IOCTL_SET_GROUP_HOLD: + { + struct imx179_ae ae; + if (copy_from_user(&ae, (const void __user *)arg, + sizeof(struct imx179_ae))) { + pr_info("%s:fail group hold\n", __func__); + return -EFAULT; + } + return imx179_set_group_hold(info, &ae); + } + case IMX179_IOCTL_SET_FLASH_MODE: + { + struct imx179_flash_control values; - switch (pwr) { - case NVC_PWR_OFF_FORCE: - case NVC_PWR_OFF: - case NVC_PWR_STDBY_OFF: - imx179_gpio_pwrdn(info, 1); - err = imx179_vreg_dis_all(info); - imx179_gpio_able(info, 0); - imx179_gpio_reset(info, 0); - info->mode_valid = false; - info->bin_en = 0; - break; - - case NVC_PWR_STDBY: - imx179_gpio_pwrdn(info, 1); - err = imx179_vreg_en_all(info); - imx179_gpio_able(info, 1); + dev_dbg(&info->i2c_client->dev, + "IMX179_IOCTL_SET_FLASH_MODE\n"); + if (copy_from_user(&values, + (const void __user *)arg, + sizeof(struct imx179_flash_control))) { + err = -EFAULT; + break; + } + err = imx179_set_flash_control(info, &values); break; - - case NVC_PWR_COMM: - case NVC_PWR_ON: - if (info->pwr_dev != NVC_PWR_ON && - info->pwr_dev != NVC_PWR_COMM) - imx179_gpio_pwrdn(info, 1); - err = imx179_vreg_en_all(info); - imx179_gpio_able(info, 1); - ret = imx179_gpio_pwrdn(info, 0); - ret &= !imx179_gpio_reset(info, 1); - if (ret) /* if no reset && pwrdn changed states then delay */ - msleep(IMX179_STARTUP_DELAY_MS); + } + case IMX179_IOCTL_GET_FLASH_CAP: + err = imx179_get_flash_cap(info); break; - default: + pr_err("%s:unknown cmd.\n", __func__); err = -EINVAL; - break; - } - - if (err < 0) { - dev_err(&info->i2c_client->dev, "%s err %d\n", __func__, err); - pwr = NVC_PWR_ERR; } - info->pwr_dev = pwr; - dev_dbg(&info->i2c_client->dev, "%s pwr_dev=%d\n", - __func__, info->pwr_dev); - if (err > 0) - return 0; return err; } -static int imx179_pm_wr_s(struct imx179_info *info, int pwr) +static int imx179_debugfs_show(struct seq_file *s, void *unused) { - int err1 = 0; - int err2 = 0; - - if ((info->s_mode == NVC_SYNC_OFF) || - (info->s_mode == NVC_SYNC_MASTER) || - (info->s_mode == NVC_SYNC_STEREO)) - err1 = imx179_pm_wr(info, pwr); - if ((info->s_mode == NVC_SYNC_SLAVE) || - (info->s_mode == NVC_SYNC_STEREO)) - err2 = imx179_pm_wr(info->s_info, pwr); - return err1 | err2; -} + struct imx179_info *dev = s->private; -static int imx179_pm_api_wr(struct imx179_info *info, int pwr) -{ - int err = 0; + dev_dbg(&dev->i2c_client->dev, "%s: ++\n", __func__); - if (!pwr || (pwr > NVC_PWR_ON)) - return 0; + mutex_lock(&dev->imx179_camera_lock); + mutex_unlock(&dev->imx179_camera_lock); - if (pwr > info->pwr_dev) - err = imx179_pm_wr_s(info, pwr); - if (!err) - info->pwr_api = pwr; - else - info->pwr_api = NVC_PWR_ERR; - if (info->pdata->cfg & NVC_CFG_NOERR) - return 0; - - return err; -} - -static int imx179_pm_dev_wr(struct imx179_info *info, int pwr) -{ - if (pwr < info->pwr_api) - pwr = info->pwr_api; - if (info->mode_enable) - pwr = NVC_PWR_ON; - return imx179_pm_wr(info, pwr); + return 0; } -static void imx179_pm_exit(struct imx179_info *info) +static ssize_t imx179_debugfs_write( + struct file *file, + char const __user *buf, + size_t count, + loff_t *offset) { - imx179_pm_wr(info, NVC_PWR_OFF_FORCE); - imx179_vreg_exit(info); - imx179_gpio_exit(info); + struct imx179_info *dev = + ((struct seq_file *)file->private_data)->private; + struct i2c_client *i2c_client = dev->i2c_client; + int ret = 0; + char buffer[MAX_BUFFER_SIZE]; + u32 address; + u32 data; + u8 readback; + + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); + + if (copy_from_user(&buffer, buf, sizeof(buffer))) + goto debugfs_write_fail; + + if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2) + goto set_attr; + if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2) + goto set_attr; + if (sscanf(buf, "%d %d", &address, &data) == 2) + goto set_attr; + + if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1) + goto read; + if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1) + goto read; + if (sscanf(buf, "%d %d", &address, &data) == 1) + goto read; + + dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf); + return -EFAULT; + +set_attr: + dev_info(&i2c_client->dev, + "new address = %x, data = %x\n", address, data); + ret |= imx179_write_reg(dev, address, data); +read: + ret |= imx179_read_reg(dev, address, &readback); + dev_dbg(&i2c_client->dev, + "wrote to address 0x%x with value 0x%x\n", + address, readback); + + if (ret) + goto debugfs_write_fail; + + return count; + +debugfs_write_fail: + dev_err(&i2c_client->dev, + "%s: test pattern write failed\n", __func__); + return -EFAULT; } -static void imx179_pm_init(struct imx179_info *info) +static int imx179_debugfs_open(struct inode *inode, struct file *file) { - imx179_gpio_init(info); - imx179_vreg_init(info); -} + struct imx179_info *dev = inode->i_private; + struct i2c_client *i2c_client = dev->i2c_client; -static int imx179_reset(struct imx179_info *info, u32 level) -{ - int err; + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); - if (level == NVC_RESET_SOFT) { - err = imx179_pm_wr(info, NVC_PWR_COMM); - err |= imx179_i2c_wr8(info, 0x0103, 0x01); /* SW reset */ - } else { - err = imx179_pm_wr(info, NVC_PWR_OFF_FORCE); - } - err |= imx179_pm_wr(info, info->pwr_api); - return err; -} - -static int imx179_dev_id(struct imx179_info *info) -{ - u16 val = 0; - unsigned i; - int err; - - dev_dbg(&info->i2c_client->dev, "%s +++++\n", - __func__); - imx179_pm_dev_wr(info, NVC_PWR_COMM); - dev_dbg(&info->i2c_client->dev, "DUCK:%s:%d\n", - __func__, __LINE__); - err = imx179_i2c_rd16(info, IMX179_ID_ADDRESS, &val); - if (!err) { - dev_dbg(&info->i2c_client->dev, "%s found devId: %x\n", - __func__, val); - info->sdata.sensor_id_minor = 0; - for (i = 0; i < ARRAY_SIZE(imx179_ids); i++) { - if (val == imx179_ids[i]) { - info->sdata.sensor_id_minor = val; - break; - } - } - if (!info->sdata.sensor_id_minor) { - err = -ENODEV; - dev_dbg(&info->i2c_client->dev, "%s No devId match\n", - __func__); - } - } - imx179_pm_dev_wr(info, NVC_PWR_OFF); - dev_dbg(&info->i2c_client->dev, "%s -----\n", - __func__); - return err; + return single_open(file, imx179_debugfs_show, inode->i_private); } -static int imx179_mode_able(struct imx179_info *info, bool mode_enable) -{ - u8 val; - int err; - - if (mode_enable) - val = IMX179_STREAM_ENABLE; - else - val = IMX179_STREAM_DISABLE; - err = imx179_i2c_wr8(info, IMX179_STREAM_CONTROL_REG, val); - if (!err) { - info->mode_enable = mode_enable; - dev_dbg(&info->i2c_client->dev, "%s streaming=%x\n", - __func__, info->mode_enable); - if (!mode_enable) - imx179_pm_dev_wr(info, NVC_PWR_OFF); - } - msleep(IMX179_WAIT_MS); - return err; -} +static const struct file_operations imx179_debugfs_fops = { + .open = imx179_debugfs_open, + .read = seq_read, + .write = imx179_debugfs_write, + .llseek = seq_lseek, + .release = single_release, +}; -static int imx179_mode_rd(struct imx179_info *info, - s32 res_x, - s32 res_y, - u32 *index) +static void imx179_remove_debugfs(struct imx179_info *dev) { - int i; - - if (!res_x && !res_y) { - *index = info->cap->preferred_mode_index; - return 0; - } + struct i2c_client *i2c_client = dev->i2c_client; - for (i = 0; i < IMX179_NUM_MODES; i++) { - if ((res_x == imx179_mode_table[i]->sensor_mode.res_x) && - (res_y == imx179_mode_table[i]->sensor_mode.res_y)) { - break; - } - } - - if (i == IMX179_NUM_MODES) { - dev_err(&info->i2c_client->dev, - "%s invalid resolution: %dx%d\n", - __func__, res_x, res_y); - return -EINVAL; - } + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); - *index = i; - return 0; + debugfs_remove_recursive(dev->debugdir); + dev->debugdir = NULL; } -static int imx179_mode_wr_full(struct imx179_info *info, u32 mode_index) +static void imx179_create_debugfs(struct imx179_info *dev) { - int err; - - imx179_pm_dev_wr(info, NVC_PWR_ON); - imx179_bin_wr(info, 0); - err = imx179_i2c_wr_table(info, - imx179_mode_table[mode_index]->p_mode_i2c); - if (!err) { - info->mode_index = mode_index; - info->mode_valid = true; - } else { - info->mode_valid = false; - } - - return err; + struct dentry *ret; + struct i2c_client *i2c_client = dev->i2c_client; + + dev_dbg(&i2c_client->dev, "%s\n", __func__); + + dev->debugdir = + debugfs_create_dir(dev->miscdev_info.this_device->kobj.name, + NULL); + if (!dev->debugdir) + goto remove_debugfs; + + ret = debugfs_create_file("d", + S_IWUSR | S_IRUGO, + dev->debugdir, dev, + &imx179_debugfs_fops); + if (!ret) + goto remove_debugfs; + + return; +remove_debugfs: + dev_err(&i2c_client->dev, "couldn't create debugfs\n"); + imx179_remove_debugfs(dev); } -static int imx179_mode_wr(struct imx179_info *info, - struct nvc_imager_bayer *mode) +static int imx179_get_extra_regulators(struct imx179_power_rail *pw) { - u32 mode_index; - int err; - - err = imx179_mode_rd(info, mode->res_x, mode->res_y, &mode_index); - if (err < 0) - return err; - - if (!mode->res_x && !mode->res_y) { - if (mode->frame_length || mode->coarse_time || mode->gain) { - /* write exposure only */ - err = imx179_exposure_wr(info, mode); - return err; - } else { - /* turn off streaming */ - err = imx179_mode_able(info, false); - return err; + if (!pw->ext_reg1) { + pw->ext_reg1 = regulator_get(NULL, "imx179_reg1"); + if (WARN_ON(IS_ERR(pw->ext_reg1))) { + pr_err("%s: can't get regulator imx179_reg1: %ld\n", + __func__, PTR_ERR(pw->ext_reg1)); + pw->ext_reg1 = NULL; + return -ENODEV; } } - if (!info->mode_valid || (info->mode_index != mode_index)) - err = imx179_mode_wr_full(info, mode_index); - else - dev_dbg(&info->i2c_client->dev, "%s short mode\n", __func__); - err |= imx179_exposure_wr(info, mode); - if (err < 0) { - info->mode_valid = false; - goto imx179_mode_wr_err; + if (!pw->ext_reg2) { + pw->ext_reg2 = regulator_get(NULL, "imx179_reg2"); + if (WARN_ON(IS_ERR(pw->ext_reg2))) { + pr_err("%s: can't get regulator imx179_reg2: %ld\n", + __func__, PTR_ERR(pw->ext_reg2)); + pw->ext_reg2 = NULL; + return -ENODEV; + } } - err = imx179_set_flash_output(info); - - err |= imx179_mode_able(info, true); - if (err < 0) - goto imx179_mode_wr_err; - return 0; - -imx179_mode_wr_err: - if (!info->mode_enable) - imx179_pm_dev_wr(info, NVC_PWR_STDBY); - return err; } - -static int imx179_param_rd(struct imx179_info *info, unsigned long arg) +static int imx179_power_on(struct imx179_power_rail *pw) { - struct nvc_param params; - struct imx179_reg *p_i2c_table; - const void *data_ptr; - u32 data_size = 0; - u32 u32val; int err; + struct imx179_info *info = container_of(pw, struct imx179_info, power); - if (copy_from_user(¶ms, - (const void __user *)arg, - sizeof(struct nvc_param))) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", __func__, __LINE__); + if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) return -EFAULT; - } - - if (info->s_mode == NVC_SYNC_SLAVE) - info = info->s_info; - - switch (params.param) { - case NVC_PARAM_GAIN: - imx179_pm_dev_wr(info, NVC_PWR_COMM); - err = imx179_gain_rd(info, &u32val); - imx179_pm_dev_wr(info, NVC_PWR_OFF); - dev_dbg(&info->i2c_client->dev, "%s GAIN: %u err: %d\n", - __func__, u32val, err); - if (err) - return err; - - data_ptr = &u32val; - data_size = sizeof(u32val); - break; - case NVC_PARAM_STEREO_CAP: - if (info->s_info != NULL) - err = 0; - else - err = -ENODEV; - dev_dbg(&info->i2c_client->dev, "%s STEREO_CAP: %d\n", - __func__, err); - data_ptr = &err; - data_size = sizeof(err); - break; + if (info->pdata->ext_reg) { + if (imx179_get_extra_regulators(pw)) + goto imx179_poweron_fail; - case NVC_PARAM_STEREO: - dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n", - __func__, info->s_mode); - data_ptr = &info->s_mode; - data_size = sizeof(info->s_mode); - break; + err = regulator_enable(pw->ext_reg1); + if (unlikely(err)) + goto imx179_ext_reg1_fail; - case NVC_PARAM_STS: - err = imx179_dev_id(info); - dev_dbg(&info->i2c_client->dev, "%s STS: %d\n", - __func__, err); - data_ptr = &err; - data_size = sizeof(err); - break; + err = regulator_enable(pw->ext_reg2); + if (unlikely(err)) + goto imx179_ext_reg2_fail; - case NVC_PARAM_DEV_ID: - if (!info->sdata.sensor_id_minor) - imx179_dev_id(info); - data_ptr = &info->sdata.sensor_id; - data_size = sizeof(info->sdata.sensor_id) * 2; - dev_dbg(&info->i2c_client->dev, "%s DEV_ID: %x-%x\n", - __func__, info->sdata.sensor_id, - info->sdata.sensor_id_minor); - break; - - case NVC_PARAM_SENSOR_TYPE: - data_ptr = &info->sdata.sensor_type; - data_size = sizeof(info->sdata.sensor_type); - dev_dbg(&info->i2c_client->dev, "%s SENSOR_TYPE: %d\n", - __func__, info->sdata.sensor_type); - break; - - case NVC_PARAM_FOCAL_LEN: - data_ptr = &info->sdata.focal_len; - data_size = sizeof(info->sdata.focal_len); - dev_dbg(&info->i2c_client->dev, "%s FOCAL_LEN: %u\n", - __func__, info->sdata.focal_len); - break; - - case NVC_PARAM_MAX_APERTURE: - data_ptr = &info->sdata.max_aperture; - data_size = sizeof(info->sdata.max_aperture); - dev_dbg(&info->i2c_client->dev, "%s MAX_APERTURE: %u\n", - __func__, info->sdata.max_aperture); - break; - - case NVC_PARAM_FNUMBER: - data_ptr = &info->sdata.fnumber; - data_size = sizeof(info->sdata.fnumber); - dev_dbg(&info->i2c_client->dev, "%s FNUMBER: %u\n", - __func__, info->sdata.fnumber); - break; - - case NVC_PARAM_VIEW_ANGLE_H: - data_ptr = &info->sdata.view_angle_h; - data_size = sizeof(info->sdata.view_angle_h); - dev_dbg(&info->i2c_client->dev, "%s VIEW_ANGLE_H: %u\n", - __func__, info->sdata.view_angle_h); - break; - - case NVC_PARAM_VIEW_ANGLE_V: - data_ptr = &info->sdata.view_angle_v; - data_size = sizeof(info->sdata.view_angle_v); - dev_dbg(&info->i2c_client->dev, "%s VIEW_ANGLE_V: %u\n", - __func__, info->sdata.view_angle_v); - break; - - case NVC_PARAM_I2C: - dev_dbg(&info->i2c_client->dev, "%s I2C\n", __func__); - if (params.sizeofvalue > IMX179_I2C_TABLE_MAX_ENTRIES) { - dev_err(&info->i2c_client->dev, - "%s NVC_PARAM_I2C request size too large\n", - __func__); - return -EINVAL; - } - p_i2c_table = kzalloc(sizeof(params.sizeofvalue), GFP_KERNEL); - if (p_i2c_table == NULL) { - pr_err("%s: kzalloc error\n", __func__); - return -ENOMEM; - } - - if (copy_from_user(p_i2c_table, - (const void __user *)params.p_value, - params.sizeofvalue)) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", - __func__, __LINE__); - kfree(p_i2c_table); - return -EINVAL; - } - - imx179_pm_dev_wr(info, NVC_PWR_COMM); - err = imx179_i2c_rd_table(info, p_i2c_table); - imx179_pm_dev_wr(info, NVC_PWR_OFF); - if (copy_to_user((void __user *)params.p_value, - p_i2c_table, - params.sizeofvalue)) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - err = -EINVAL; - } - kfree(p_i2c_table); - return err; - default: - dev_dbg(&info->i2c_client->dev, - "%s unsupported parameter: %d\n", - __func__, params.param); - return -EINVAL; } - if (params.sizeofvalue < data_size) { - dev_err(&info->i2c_client->dev, - "%s data size mismatch %d != %d Param: %d\n", - __func__, params.sizeofvalue, data_size, params.param); - return -EINVAL; - } + gpio_set_value(info->pdata->reset_gpio, 0); + gpio_set_value(info->pdata->af_gpio, 1); + gpio_set_value(info->pdata->cam1_gpio, 0); + usleep_range(10, 20); - if (copy_to_user((void __user *)params.p_value, - data_ptr, - data_size)) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", __func__, __LINE__); - return -EFAULT; - } - - return 0; -} - -static int imx179_param_wr_s(struct imx179_info *info, - struct nvc_param *params, - u32 u32val) -{ - struct imx179_reg *p_i2c_table; - u8 u8val; - int err; - - u8val = (u8)u32val; - switch (params->param) { - case NVC_PARAM_GAIN: - dev_dbg(&info->i2c_client->dev, "%s GAIN: %u\n", - __func__, u32val); - imx179_pm_dev_wr(info, NVC_PWR_COMM); - err = imx179_gain_wr(info, u32val); - if (err) { - dev_err(&info->i2c_client->dev, "Error: %s SET GAIN ERR", - __func__); - } - imx179_pm_dev_wr(info, NVC_PWR_STDBY); - return err; + err = regulator_enable(pw->avdd); + if (err) + goto imx179_avdd_fail; - case NVC_PARAM_RESET: - err = imx179_reset(info, u32val); - dev_dbg(&info->i2c_client->dev, "%s RESET=%d err=%d\n", - __func__, u32val, err); - return err; + err = regulator_enable(pw->iovdd); + if (err) + goto imx179_iovdd_fail; - case NVC_PARAM_TESTMODE: - dev_dbg(&info->i2c_client->dev, "%s TESTMODE: %u\n", - __func__, (unsigned)u8val); - if (u8val) - u32val = info->test_pattern; - else - u32val = 0; - imx179_pm_dev_wr(info, NVC_PWR_ON); - err = imx179_test_pattern_wr(info, u32val); - if (!u8val) - imx179_pm_dev_wr(info, NVC_PWR_OFF); - return err; + usleep_range(1, 2); + gpio_set_value(info->pdata->reset_gpio, 1); + gpio_set_value(info->pdata->cam1_gpio, 1); - case NVC_PARAM_TEST_PATTERN: - dev_dbg(&info->i2c_client->dev, "%s TEST_PATTERN: %d\n", - __func__, u32val); - info->test_pattern = u32val; - return 0; + usleep_range(300, 310); - case NVC_PARAM_SELF_TEST: - err = imx179_dev_id(info); - dev_dbg(&info->i2c_client->dev, "%s SELF_TEST: %d\n", - __func__, err); - return err; + return 1; - case NVC_PARAM_I2C: - dev_dbg(&info->i2c_client->dev, "%s I2C\n", __func__); - if (params->sizeofvalue > IMX179_I2C_TABLE_MAX_ENTRIES) { - dev_err(&info->i2c_client->dev, - "%s NVC_PARAM_I2C request size too large\n", - __func__); - return -EINVAL; - } - p_i2c_table = kzalloc(sizeof(params->sizeofvalue), GFP_KERNEL); - if (p_i2c_table == NULL) { - dev_err(&info->i2c_client->dev, - "%s kzalloc err line %d\n", - __func__, __LINE__); - return -ENOMEM; - } - if (copy_from_user(p_i2c_table, - (const void __user *)params->p_value, - params->sizeofvalue)) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", - __func__, __LINE__); - kfree(p_i2c_table); - return -EFAULT; - } +imx179_iovdd_fail: + regulator_disable(pw->avdd); - imx179_pm_dev_wr(info, NVC_PWR_ON); - err = imx179_i2c_wr_table(info, p_i2c_table); - kfree(p_i2c_table); - return err; +imx179_avdd_fail: + if (pw->ext_reg2) + regulator_disable(pw->ext_reg2); - case NVC_PARAM_SET_SENSOR_FLASH_MODE: - { - union nvc_imager_flash_control fm; - if (copy_from_user(&fm, - (const void __user *)params->p_value, sizeof(fm))) { - pr_info("%s:fail set flash mode.\n", __func__); - return -EFAULT; - } - return imx179_flash_control(info, &fm); - } +imx179_ext_reg2_fail: + if (pw->ext_reg1) + regulator_disable(pw->ext_reg1); + gpio_set_value(info->pdata->af_gpio, 0); - default: - dev_dbg(&info->i2c_client->dev, - "%s unsupported parameter: %d\n", - __func__, params->param); - return -EINVAL; - } +imx179_ext_reg1_fail: +imx179_poweron_fail: + pr_err("%s failed.\n", __func__); + return -ENODEV; } -static int imx179_param_wr(struct imx179_info *info, unsigned long arg) +static int imx179_power_off(struct imx179_power_rail *pw) { - struct nvc_param params; - u8 u8val; - u32 u32val; - int err = 0; + struct imx179_info *info = container_of(pw, struct imx179_info, power); - if (copy_from_user(¶ms, (const void __user *)arg, - sizeof(struct nvc_param))) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", __func__, __LINE__); + if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) return -EFAULT; - } - - if (copy_from_user(&u32val, (const void __user *)params.p_value, - sizeof(u32val))) { - dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", - __func__, __LINE__); - return -EFAULT; - } - - u8val = (u8)u32val; - /* parameters independent of sync mode */ - switch (params.param) { - case NVC_PARAM_STEREO: - dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n", - __func__, u8val); - if (u8val == info->s_mode) - return 0; - switch (u8val) { - case NVC_SYNC_OFF: - info->s_mode = u8val; - if (info->s_info != NULL) { - info->s_info->s_mode = u8val; - imx179_pm_wr(info->s_info, NVC_PWR_OFF); - } - break; - - case NVC_SYNC_MASTER: - info->s_mode = u8val; - if (info->s_info != NULL) - info->s_info->s_mode = u8val; - break; - - case NVC_SYNC_SLAVE: - if (info->s_info != NULL) { - /* sync power */ - info->s_info->pwr_api = info->pwr_api; - err = imx179_pm_wr(info->s_info, - info->pwr_dev); - if (!err) { - info->s_mode = u8val; - info->s_info->s_mode = u8val; - } else { - if (info->s_mode != NVC_SYNC_STEREO) - imx179_pm_wr(info->s_info, - NVC_PWR_OFF); - err = -EIO; - } - } else { - err = -EINVAL; - } - break; + usleep_range(1, 2); + gpio_set_value(info->pdata->cam1_gpio, 0); + usleep_range(1, 2); - case NVC_SYNC_STEREO: - if (info->s_info != NULL) { - /* sync power */ - info->s_info->pwr_api = info->pwr_api; - err = imx179_pm_wr(info->s_info, - info->pwr_dev); - if (!err) { - info->s_mode = u8val; - info->s_info->s_mode = u8val; - } else { - if (info->s_mode != NVC_SYNC_SLAVE) - imx179_pm_wr(info->s_info, - NVC_PWR_OFF); - err = -EIO; - } - } else { - err = -EINVAL; - } - break; - - default: - err = -EINVAL; - } - if (info->pdata->cfg & NVC_CFG_NOERR) - return 0; + regulator_disable(pw->iovdd); + regulator_disable(pw->avdd); - return err; - - case NVC_PARAM_GROUP_HOLD: - { - struct nvc_imager_ae ae; - dev_dbg(&info->i2c_client->dev, "%s GROUP_HOLD\n", - __func__); - if (copy_from_user(&ae, (const void __user *)params.p_value, - sizeof(struct nvc_imager_ae))) { - dev_err(&info->i2c_client->dev, "Error: %s %d copy_from_user err\n", - __func__, __LINE__); - return -EFAULT; - } - imx179_pm_dev_wr(info, NVC_PWR_COMM); - err = imx179_group_hold_wr(info, &ae); - imx179_pm_dev_wr(info, NVC_PWR_STDBY); - return err; + if (info->pdata->ext_reg) { + regulator_disable(pw->ext_reg1); + regulator_disable(pw->ext_reg2); } - default: - /* parameters dependent on sync mode */ - switch (info->s_mode) { - case NVC_SYNC_OFF: - case NVC_SYNC_MASTER: - return imx179_param_wr_s(info, ¶ms, u32val); - - case NVC_SYNC_SLAVE: - return imx179_param_wr_s(info->s_info, ¶ms, - u32val); - - case NVC_SYNC_STEREO: - err = imx179_param_wr_s(info, ¶ms, u32val); - if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX)) - err |= imx179_param_wr_s(info->s_info, - ¶ms, u32val); - return err; - - default: - dev_err(&info->i2c_client->dev, "%s %d internal err\n", - __func__, __LINE__); - return -EINVAL; - } - } -} - -static long imx179_ioctl(struct file *file, - unsigned int cmd, - unsigned long arg) -{ - struct imx179_info *info = file->private_data; - struct nvc_imager_bayer mode; - struct nvc_imager_mode_list mode_list; - struct nvc_imager_mode mode_table[IMX179_NUM_MODES]; - struct nvc_imager_dnvc dnvc; - const void *data_ptr; - s32 num_modes; - u32 i; - int pwr; - int err; - - switch (cmd) { - case NVC_IOCTL_PARAM_WR: - err = imx179_param_wr(info, arg); - return err; - - case NVC_IOCTL_PARAM_RD: - err = imx179_param_rd(info, arg); - return err; - - case NVC_IOCTL_DYNAMIC_RD: - if (copy_from_user(&dnvc, (const void __user *)arg, - sizeof(struct nvc_imager_dnvc))) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - dev_dbg(&info->i2c_client->dev, "%s DYNAMIC_RD x=%d y=%d\n", - __func__, dnvc.res_x, dnvc.res_y); - err = imx179_mode_rd(info, dnvc.res_x, dnvc.res_y, &i); - if (err) - return -EINVAL; - - if (dnvc.p_mode) { - if (copy_to_user((void __user *)dnvc.p_mode, - &imx179_mode_table[i]->sensor_mode, - sizeof(struct nvc_imager_mode))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - } - - if (dnvc.p_dnvc) { - if (copy_to_user((void __user *)dnvc.p_dnvc, - &imx179_mode_table[i]->sensor_dnvc, - sizeof(struct nvc_imager_dynamic_nvc))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - } - - return 0; - - case NVC_IOCTL_MODE_WR: - if (copy_from_user(&mode, (const void __user *)arg, - sizeof(struct nvc_imager_bayer))) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - dev_dbg(&info->i2c_client->dev, - "%s MODE_WR x=%d y=%d coarse=%u frame=%u gain=%u\n", - __func__, mode.res_x, mode.res_y, - mode.coarse_time, mode.frame_length, mode.gain); - - err = imx179_mode_wr(info, &mode); - return err; - - case NVC_IOCTL_MODE_RD: - /* - * Return a list of modes that sensor bayer supports. - * If called with a NULL ptr to pModes, - * then it just returns the count. - */ - dev_dbg(&info->i2c_client->dev, "%s MODE_RD n=%d\n", - __func__, IMX179_NUM_MODES); - if (copy_from_user(&mode_list, (const void __user *)arg, - sizeof(struct nvc_imager_mode_list))) { - dev_err(&info->i2c_client->dev, - "%s copy_from_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - num_modes = IMX179_NUM_MODES; - if (mode_list.p_num_mode != NULL) { - if (copy_to_user((void __user *)mode_list.p_num_mode, - &num_modes, sizeof(num_modes))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - } - - if (mode_list.p_modes != NULL) { - for (i = 0; i < IMX179_NUM_MODES; i++) { - mode_table[i] = - imx179_mode_table[i]->sensor_mode; - } - if (copy_to_user((void __user *)mode_list.p_modes, - (const void *)&mode_table, - sizeof(mode_table))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - } - - return 0; - - case NVC_IOCTL_PWR_WR: - /* This is a Guaranteed Level of Service (GLOS) call */ - pwr = (int)arg * 2; - dev_dbg(&info->i2c_client->dev, "%s PWR_WR: %d\n", - __func__, pwr); - err = imx179_pm_api_wr(info, pwr); - return err; - - case NVC_IOCTL_PWR_RD: - if (info->s_mode == NVC_SYNC_SLAVE) - pwr = info->s_info->pwr_api / 2; - else - pwr = info->pwr_api / 2; - dev_dbg(&info->i2c_client->dev, "%s PWR_RD: %d\n", - __func__, pwr); - if (copy_to_user((void __user *)arg, (const void *)&pwr, - sizeof(pwr))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - return 0; - - case NVC_IOCTL_CAPS_RD: - dev_dbg(&info->i2c_client->dev, "%s CAPS_RD n=%d\n", - __func__, sizeof(imx179_dflt_cap)); - data_ptr = info->cap; - if (copy_to_user((void __user *)arg, - data_ptr, - sizeof(imx179_dflt_cap))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - return 0; - - case NVC_IOCTL_STATIC_RD: - dev_dbg(&info->i2c_client->dev, "%s STATIC_RD n=%d\n", - __func__, sizeof(struct nvc_imager_static_nvc)); - data_ptr = &info->sdata; - if (copy_to_user((void __user *)arg, - data_ptr, - sizeof(struct nvc_imager_static_nvc))) { - dev_err(&info->i2c_client->dev, - "%s copy_to_user err line %d\n", - __func__, __LINE__); - return -EFAULT; - } - - return 0; - - default: - dev_dbg(&info->i2c_client->dev, "%s unsupported ioctl: %x\n", - __func__, cmd); - } - - return -EINVAL; -} - -static void imx179_sdata_init(struct imx179_info *info) -{ - if (info->pdata->cap) - info->cap = info->pdata->cap; - else - info->cap = &imx179_dflt_cap; - memcpy(&info->sdata, &imx179_dflt_sdata, sizeof(info->sdata)); - if (info->pdata->lens_focal_length) - info->sdata.focal_len = info->pdata->lens_focal_length; - if (info->pdata->lens_max_aperture) - info->sdata.max_aperture = info->pdata->lens_max_aperture; - if (info->pdata->lens_fnumber) - info->sdata.fnumber = info->pdata->lens_fnumber; - if (info->pdata->lens_view_angle_h) - info->sdata.view_angle_h = info->pdata->lens_view_angle_h; - if (info->pdata->lens_view_angle_v) - info->sdata.view_angle_v = info->pdata->lens_view_angle_v; -} - -static int imx179_sync_en(unsigned num, unsigned sync) -{ - struct imx179_info *master = NULL; - struct imx179_info *slave = NULL; - struct imx179_info *pos = NULL; - - rcu_read_lock(); - list_for_each_entry_rcu(pos, &imx179_info_list, list) { - if (pos->pdata->num == num) { - master = pos; - break; - } - } - pos = NULL; - list_for_each_entry_rcu(pos, &imx179_info_list, list) { - if (pos->pdata->num == sync) { - slave = pos; - break; - } - } - rcu_read_unlock(); - if (master != NULL) - master->s_info = NULL; - if (slave != NULL) - slave->s_info = NULL; - if (!sync) - return 0; /* no err if sync disabled */ - - if (num == sync) - return -EINVAL; /* err if sync instance is itself */ - - if ((master != NULL) && (slave != NULL)) { - master->s_info = slave; - slave->s_info = master; - } return 0; } -static int imx179_sync_dis(struct imx179_info *info) -{ - if (info->s_info != NULL) { - info->s_info->s_mode = 0; - info->s_info->s_info = NULL; - info->s_mode = 0; - info->s_info = NULL; - return 0; - } - - return -EINVAL; -} - -static int imx179_open(struct inode *inode, struct file *file) +static int +imx179_open(struct inode *inode, struct file *file) { - struct imx179_info *info = NULL; - struct imx179_info *pos = NULL; - int err; - - rcu_read_lock(); - list_for_each_entry_rcu(pos, &imx179_info_list, list) { - if (pos->miscdev.minor == iminor(inode)) { - info = pos; - break; - } - } - rcu_read_unlock(); - if (!info) { - pr_err("%s err @%d info is null\n", __func__, __LINE__); - return -ENODEV; - } + struct miscdevice *miscdev = file->private_data; + struct imx179_info *info; - dev_dbg(&info->i2c_client->dev, "%s +++++\n", __func__); - err = imx179_sync_en(info->pdata->num, info->pdata->sync); - if (err == -EINVAL) - dev_err(&info->i2c_client->dev, - "%s err: invalid num (%u) and sync (%u) instance\n", - __func__, info->pdata->num, info->pdata->sync); + info = container_of(miscdev, struct imx179_info, miscdev_info); + /* check if the device is in use */ if (atomic_xchg(&info->in_use, 1)) { - dev_err(&info->i2c_client->dev, "%s err @%d device is busy\n", - __func__, __LINE__); + pr_info("%s:BUSY!\n", __func__); return -EBUSY; } - if (info->s_info != NULL) { - if (atomic_xchg(&info->s_info->in_use, 1)) { - dev_err(&info->i2c_client->dev, "%s err @%d sync device is busy\n", - __func__, __LINE__); - return -EBUSY; - } - info->sdata.stereo_cap = 1; - } file->private_data = info; - dev_dbg(&info->i2c_client->dev, "%s -----\n", __func__); + return 0; } -static int imx179_release(struct inode *inode, struct file *file) +static int +imx179_release(struct inode *inode, struct file *file) { struct imx179_info *info = file->private_data; - dev_dbg(&info->i2c_client->dev, "%s +++++\n", __func__); - imx179_pm_wr_s(info, NVC_PWR_OFF); file->private_data = NULL; + + /* warn if device is already released */ WARN_ON(!atomic_xchg(&info->in_use, 0)); - if (info->s_info != NULL) - WARN_ON(!atomic_xchg(&info->s_info->in_use, 0)); - imx179_sync_dis(info); - dev_dbg(&info->i2c_client->dev, "%s -----\n", __func__); return 0; } -static const struct file_operations imx179_fileops = { - .owner = THIS_MODULE, - .open = imx179_open, - .unlocked_ioctl = imx179_ioctl, - .release = imx179_release, -}; - -static void imx179_del(struct imx179_info *info) +static int imx179_power_put(struct imx179_power_rail *pw) { - imx179_pm_exit(info); - if ((info->s_mode == NVC_SYNC_SLAVE) || - (info->s_mode == NVC_SYNC_STEREO)) - imx179_pm_exit(info->s_info); - imx179_sync_dis(info); - spin_lock(&imx179_spinlock); - list_del_rcu(&info->list); - spin_unlock(&imx179_spinlock); - synchronize_rcu(); -} + if (unlikely(!pw)) + return -EFAULT; -static int imx179_remove(struct i2c_client *client) -{ - struct imx179_info *info = i2c_get_clientdata(client); + if (likely(pw->avdd)) + regulator_put(pw->avdd); - dev_dbg(&info->i2c_client->dev, "%s\n", __func__); -#ifdef CONFIG_DEBUG_FS - if (info->debugfs_root) - debugfs_remove_recursive(info->debugfs_root); -#endif - misc_deregister(&info->miscdev); - imx179_del(info); - return 0; -} + if (likely(pw->iovdd)) + regulator_put(pw->iovdd); -#ifdef CONFIG_DEBUG_FS -static int i2ca_get(void *data, u64 *val) -{ - struct imx179_info *info = (struct imx179_info *)(data); - *val = (u64)info->i2c_reg; - return 0; -} + if (likely(pw->dvdd)) + regulator_put(pw->dvdd); -static int i2ca_set(void *data, u64 val) -{ - struct imx179_info *info = (struct imx179_info *)(data); + if (likely(pw->ext_reg1)) + regulator_put(pw->ext_reg1); - if (val > 0x36FF) { - dev_err(&info->i2c_client->dev, "ERR:%s out of range\n", - __func__); - return -EIO; - } + if (likely(pw->ext_reg2)) + regulator_put(pw->ext_reg2); + + pw->avdd = NULL; + pw->iovdd = NULL; + pw->dvdd = NULL; + pw->ext_reg1 = NULL; + pw->ext_reg2 = NULL; - info->i2c_reg = (u16) val; return 0; } -DEFINE_SIMPLE_ATTRIBUTE(i2ca_fops, i2ca_get, i2ca_set, "0x%02llx\n"); - -static int i2cr_get(void *data, u64 *val) +static int imx179_regulator_get(struct imx179_info *info, + struct regulator **vreg, char vreg_name[]) { - u8 temp = 0; - struct imx179_info *info = (struct imx179_info *)(data); + struct regulator *reg = NULL; + int err = 0; - if (imx179_i2c_rd8(info, info->i2c_reg, &temp)) { - dev_err(&info->i2c_client->dev, "ERR:%s failed\n", __func__); - return -EIO; - } - *val = (u64)temp; - return 0; + reg = regulator_get(&info->i2c_client->dev, vreg_name); + if (unlikely(IS_ERR(reg))) { + dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n", + __func__, vreg_name, (int)reg); + err = PTR_ERR(reg); + reg = NULL; + } else + dev_dbg(&info->i2c_client->dev, "%s: %s\n", + __func__, vreg_name); + + *vreg = reg; + return err; } -static int i2cr_set(void *data, u64 val) +static int imx179_power_get(struct imx179_info *info) { - return 0; -} + struct imx179_power_rail *pw = &info->power; + int err = 0; -DEFINE_SIMPLE_ATTRIBUTE(i2cr_fops, i2cr_get, i2cr_set, "0x%02llx\n"); + err |= imx179_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */ + err |= imx179_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */ + err |= imx179_regulator_get(info, &pw->iovdd, "vif"); /* IO 1.8v */ -static int i2cw_get(void *data, u64 *val) -{ - return 0; + return err; } -static int i2cw_set(void *data, u64 val) -{ - struct imx179_info *info = (struct imx179_info *)(data); - - val &= 0xFF; - if (imx179_i2c_wr8(info, info->i2c_reg, val)) { - dev_err(&info->i2c_client->dev, "ERR:%s failed\n", __func__); - return -EIO; - } - return 0; -} +static const struct file_operations imx179_fileops = { + .owner = THIS_MODULE, + .open = imx179_open, + .unlocked_ioctl = imx179_ioctl, + .release = imx179_release, +}; -DEFINE_SIMPLE_ATTRIBUTE(i2cw_fops, i2cw_get, i2cw_set, "0x%02llx\n"); +static struct miscdevice imx179_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "imx179", + .fops = &imx179_fileops, +}; -static int imx179_debug_init(struct imx179_info *info) -{ - dev_dbg(&info->i2c_client->dev, "%s", __func__); +static struct of_device_id imx179_of_match[] = { + { .compatible = "nvidia,imx179", }, + { }, +}; - info->i2c_reg = 0; - info->debugfs_root = debugfs_create_dir(info->miscdev.name, NULL); +MODULE_DEVICE_TABLE(of, imx179_of_match); - if (!info->debugfs_root) - goto err_out; +static struct imx179_platform_data *imx179_parse_dt(struct i2c_client *client) +{ + struct device_node *np = client->dev.of_node; + struct imx179_platform_data *board_info_pdata; + const struct of_device_id *match; + + match = of_match_device(imx179_of_match, &client->dev); + if (!match) { + dev_err(&client->dev, "Failed to find matching dt id\n"); + return NULL; + } - if (!debugfs_create_file("i2ca", S_IRUGO | S_IWUSR, - info->debugfs_root, info, &i2ca_fops)) - goto err_out; + board_info_pdata = devm_kzalloc(&client->dev, sizeof(*board_info_pdata), + GFP_KERNEL); + if (!board_info_pdata) { + dev_err(&client->dev, "Failed to allocate pdata\n"); + return NULL; + } - if (!debugfs_create_file("i2cr", S_IRUGO, - info->debugfs_root, info, &i2cr_fops)) - goto err_out; + board_info_pdata->cam1_gpio = of_get_named_gpio(np, "cam1-gpios", 0); + board_info_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + board_info_pdata->af_gpio = of_get_named_gpio(np, "af-gpios", 0); - if (!debugfs_create_file("i2cw", S_IWUSR, - info->debugfs_root, info, &i2cw_fops)) - goto err_out; + board_info_pdata->ext_reg = of_property_read_bool(np, "nvidia,ext_reg"); - return 0; + board_info_pdata->power_on = imx179_power_on; + board_info_pdata->power_off = imx179_power_off; -err_out: - dev_err(&info->i2c_client->dev, "ERROR:%s failed", __func__); - if (info->debugfs_root) - debugfs_remove_recursive(info->debugfs_root); - return -ENOMEM; + return board_info_pdata; } -#endif -static int imx179_probe( - struct i2c_client *client, - const struct i2c_device_id *id) +static int +imx179_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct imx179_info *info; - char dname[16]; - unsigned long clock_probe_rate; int err; const char *mclk_name; - dev_dbg(&client->dev, "%s +++++\n", __func__); - info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); - if (info == NULL) { - dev_err(&client->dev, "%s: kzalloc error\n", __func__); + pr_err("[IMX179]: probing sensor.\n"); + + info = devm_kzalloc(&client->dev, + sizeof(struct imx179_info), GFP_KERNEL); + if (!info) { + pr_err("%s:Unable to allocate memory!\n", __func__); return -ENOMEM; } - info->i2c_client = client; - if (client->dev.platform_data) { + info->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); + if (IS_ERR(info->regmap)) { + dev_err(&client->dev, + "regmap init failed: %ld\n", PTR_ERR(info->regmap)); + return -ENODEV; + } + + if (client->dev.of_node) + info->pdata = imx179_parse_dt(client); + else info->pdata = client->dev.platform_data; - } else { - info->pdata = &imx179_dflt_pdata; - dev_dbg(&client->dev, - "%s No platform data. Using defaults.\n", __func__); + + if (!info->pdata) { + pr_err("[IMX179]:%s:Unable to get platform data\n", __func__); + return -EFAULT; } + info->i2c_client = client; + atomic_set(&info->in_use, 0); + info->mode = -1; + mclk_name = info->pdata->mclk_name ? info->pdata->mclk_name : "default_mclk"; info->mclk = devm_clk_get(&client->dev, mclk_name); @@ -2550,74 +1121,48 @@ static int imx179_probe( return PTR_ERR(info->mclk); } - i2c_set_clientdata(client, info); - INIT_LIST_HEAD(&info->list); - spin_lock(&imx179_spinlock); - list_add_rcu(&info->list, &imx179_info_list); - spin_unlock(&imx179_spinlock); - imx179_pm_init(info); - imx179_sdata_init(info); - imx179_get_flash_cap(info); - if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) { - if (info->pdata->probe_clock) { - if (info->cap->initial_clock_rate_khz) - clock_probe_rate = info->cap-> - initial_clock_rate_khz; - else - clock_probe_rate = imx179_dflt_cap. - initial_clock_rate_khz; - clock_probe_rate *= 1000; - info->pdata->probe_clock(clock_probe_rate); - } - err = imx179_dev_id(info); - if (err < 0) { - if (info->pdata->cfg & NVC_CFG_NODEV) { - imx179_del(info); - if (info->pdata->probe_clock) - info->pdata->probe_clock(0); - return -ENODEV; - } else { - dev_err(&client->dev, "%s device not found\n", - __func__); - } - } else { - dev_dbg(&client->dev, "%s device found\n", __func__); - if (info->pdata->cfg & NVC_CFG_BOOT_INIT) - imx179_mode_wr_full(info, info->cap-> - preferred_mode_index); - } - imx179_pm_dev_wr(info, NVC_PWR_OFF); - if (info->pdata->probe_clock) - info->pdata->probe_clock(0); - } + imx179_power_get(info); - if (info->pdata->dev_name != 0) - strcpy(dname, info->pdata->dev_name); - else - strcpy(dname, "imx179"); - if (info->pdata->num) - snprintf(dname, sizeof(dname), "%s.%u", - dname, info->pdata->num); - info->miscdev.name = dname; - info->miscdev.fops = &imx179_fileops; - info->miscdev.minor = MISC_DYNAMIC_MINOR; - if (misc_register(&info->miscdev)) { - dev_err(&client->dev, "%s unable to register misc device %s\n", - __func__, dname); - imx179_del(info); - return -ENODEV; + imx179_edp_register(info); + + memcpy(&info->miscdev_info, + &imx179_device, + sizeof(struct miscdevice)); + + err = misc_register(&info->miscdev_info); + if (err) { + pr_err("%s:Unable to register misc device!\n", __func__); + goto imx179_probe_fail; } -#ifdef CONFIG_DEBUG_FS - imx179_debug_init(info); -#endif - dev_dbg(&client->dev, "%s -----\n", __func__); + i2c_set_clientdata(client, info); + /* create debugfs interface */ + imx179_create_debugfs(info); + pr_err("[IMX179]: end of probing sensor.\n"); + return 0; + +imx179_probe_fail: + imx179_power_put(&info->power); + + return err; +} + +static int +imx179_remove(struct i2c_client *client) +{ + struct imx179_info *info; + info = i2c_get_clientdata(client); + misc_deregister(&imx179_device); + + imx179_power_put(&info->power); + + imx179_remove_debugfs(info); return 0; } static const struct i2c_device_id imx179_id[] = { { "imx179", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(i2c, imx179_id); @@ -2627,10 +1172,21 @@ static struct i2c_driver imx179_i2c_driver = { .name = "imx179", .owner = THIS_MODULE, }, - .id_table = imx179_id, .probe = imx179_probe, .remove = imx179_remove, + .id_table = imx179_id, }; -module_i2c_driver(imx179_i2c_driver); -MODULE_LICENSE("GPL v2"); +static int __init imx179_init(void) +{ + pr_info("[IMX179] sensor driver loading\n"); + return i2c_add_driver(&imx179_i2c_driver); +} + +static void __exit imx179_exit(void) +{ + i2c_del_driver(&imx179_i2c_driver); +} + +module_init(imx179_init); +module_exit(imx179_exit); diff --git a/include/media/imx179.h b/include/media/imx179.h index 52acf5e14e98..cc6bfd32de02 100644 --- a/include/media/imx179.h +++ b/include/media/imx179.h @@ -1,59 +1,90 @@ -/* -* imx179.h -* -* Copyright (c) 2013, NVIDIA CORPORATION, All rights reserved. -* -* This file is licensed under the terms of the GNU General Public License -* version 2. This program is licensed "as is" without any warranty of any -* kind, whether express or implied. -*/ +/** + * Copyright (c) 2012-2014, NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #ifndef __IMX179_H__ #define __IMX179_H__ +#include <linux/ioctl.h> /* For IOCTL macros */ +#include <linux/edp.h> #include <media/nvc.h> #include <media/nvc_image.h> -/* See notes in the nvc.h file on the GPIO usage */ -enum imx179_gpio { - IMX179_GPIO_RESET = 0, - IMX179_GPIO_PWDN, - IMX179_GPIO_GP1, +#define IMX179_IOCTL_SET_MODE _IOW('o', 1, struct imx179_mode) +#define IMX179_IOCTL_GET_STATUS _IOR('o', 2, __u8) +#define IMX179_IOCTL_SET_FRAME_LENGTH _IOW('o', 3, __u32) +#define IMX179_IOCTL_SET_COARSE_TIME _IOW('o', 4, __u32) +#define IMX179_IOCTL_SET_GAIN _IOW('o', 5, __u16) +#define IMX179_IOCTL_GET_SENSORDATA _IOR('o', 6, struct imx179_sensordata) +#define IMX179_IOCTL_SET_GROUP_HOLD _IOW('o', 7, struct imx179_ae) +#define IMX179_IOCTL_SET_POWER _IOW('o', 20, __u32) +#define IMX179_IOCTL_GET_FLASH_CAP _IOR('o', 30, __u32) +#define IMX179_IOCTL_SET_FLASH_MODE _IOW('o', 31, \ + struct imx179_flash_control) + +struct imx179_mode { + int xres; + int yres; + __u32 frame_length; + __u32 coarse_time; + __u16 gain; +}; + +struct imx179_ae { + __u32 frame_length; + __u8 frame_length_enable; + __u32 coarse_time; + __u8 coarse_time_enable; + __s32 gain; + __u8 gain_enable; }; -/* The enumeration must be in the order the regulators are to be enabled */ -/* See Power Requirements note in the driver */ -enum imx179_vreg { - IMX179_VREG_DVDD = 0, - IMX179_VREG_AVDD, - IMX179_VREG_IOVDD, +struct imx179_sensordata { + __u32 fuse_id_size; + __u8 fuse_id[16]; }; -struct imx179_flash_config { - u8 xvs_trigger_enabled; - u8 sdo_trigger_enabled; - u8 adjustable_flash_timing; - u16 pulse_width_uS; +struct imx179_flash_control { + u8 enable; + u8 edge_trig_en; + u8 start_edge; + u8 repeat; + u16 delay_frm; +}; + + +#ifdef __KERNEL__ +struct imx179_power_rail { + struct regulator *dvdd; + struct regulator *avdd; + struct regulator *iovdd; + struct regulator *ext_reg1; + struct regulator *ext_reg2; }; struct imx179_platform_data { - unsigned cfg; - unsigned num; - unsigned sync; - const char *dev_name; - unsigned gpio_count; /* see nvc.h GPIO notes */ - struct nvc_gpio_pdata *gpio; /* see nvc.h GPIO notes */ - struct imx179_flash_config flash_cap; - struct nvc_imager_cap *cap; - unsigned lens_focal_length; /* / _INT2FLOAT_DIVISOR */ - unsigned lens_max_aperture; /* / _INT2FLOAT_DIVISOR */ - unsigned lens_fnumber; /* / _INT2FLOAT_DIVISOR */ - unsigned lens_view_angle_h; /* / _INT2FLOAT_DIVISOR */ - unsigned lens_view_angle_v; /* / _INT2FLOAT_DIVISOR */ + struct imx179_flash_control flash_cap; const char *mclk_name; /* NULL for default default_mclk */ - int (*probe_clock)(unsigned long); - int (*power_on)(struct nvc_regulator *); - int (*power_off)(struct nvc_regulator *); + struct edp_client edpc_config; + unsigned int cam1_gpio; + unsigned int reset_gpio; + unsigned int af_gpio; + bool ext_reg; + int (*power_on)(struct imx179_power_rail *pw); + int (*power_off)(struct imx179_power_rail *pw); }; +#endif /* __KERNEL__ */ #endif /* __IMX179_H__ */ |