media: video: tegra: add power rail definitions
Charlie Huang [Mon, 8 Oct 2012 23:02:29 +0000 (16:02 -0700)]
In imx091/imx132/nvc_ov9772 drivers, so board files can turn the
module on/off specifically and following the power sequence.

minor fix in as364x, initialize the power state as OFF.

bug 1060778
bug 1059684
bug 1054873

Change-Id: Iedaa867e3d9bd90f2698db943b5da74cb3eac1ec
Signed-off-by: Charlie Huang <chahuang@nvidia.com>
(cherry picked from commit efd72b1c8503041022bd166c78f867b43bd8fd90)
Reviewed on http://git-master/r/#change,142534
Reviewed-on: http://git-master/r/146548
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

drivers/media/video/tegra/as364x.c
drivers/media/video/tegra/imx091.c
drivers/media/video/tegra/imx132.c
drivers/media/video/tegra/ov9772.c
include/media/imx091.h
include/media/imx132.h
include/media/ov9772.h

index cd1100d..9ada6fd 100644 (file)
@@ -253,7 +253,8 @@ static int as364x_set_leds(struct as364x_info *info,
                val &= ~0x08;
        else
                val |= 0x08;
-       pr_info("%s %x %x %x val = %x\n", __func__, mask, curr1, curr2, val);
+       dev_dbg(&info->i2c_client->dev, "%s %x %x %x val = %x\n",
+                       __func__, mask, curr1, curr2, val);
        err |= as364x_reg_wr(info, AS364X_REG_CONTROL, val);
 
 set_led_end:
@@ -674,7 +675,8 @@ static int as364x_get_dev_id(struct as364x_info *info)
        if ((info->regs.dev_id & 0xb0) == 0xb0)
                return 0;
 
-       if (NVC_PWR_OFF == info->pwr_state)
+       if (NVC_PWR_OFF == info->pwr_state ||
+               NVC_PWR_OFF_FORCE == info->pwr_state)
                as364x_power_on(info);
        err = as364x_reg_rd(info, AS364X_REG_CHIPID, &info->regs.dev_id);
        if (err)
@@ -686,6 +688,7 @@ static int as364x_get_dev_id(struct as364x_info *info)
 read_devid_exit:
        if (NVC_PWR_OFF == info->pwr_state)
                as364x_power_off(info);
+
        return err;
 }
 
@@ -780,7 +783,7 @@ static int as364x_set_param(struct as364x_info *info,
 
        switch (params->param) {
        case NVC_PARAM_FLASH_LEVEL:
-               dev_info(&info->i2c_client->dev, "%s FLASH_LEVEL: %d\n",
+               dev_dbg(&info->i2c_client->dev, "%s FLASH_LEVEL: %d\n",
                                __func__, val);
                info->regs.ftime =
                        info->flash_cap->levels[val].rechargefactor;
@@ -791,13 +794,13 @@ static int as364x_set_param(struct as364x_info *info,
                        info->flash_mode = AS364X_REG_CONTROL_MODE_ASSIST;
                return err;
        case NVC_PARAM_TORCH_LEVEL:
-               dev_info(&info->i2c_client->dev, "%s TORCH_LEVEL: %d\n",
+               dev_dbg(&info->i2c_client->dev, "%s TORCH_LEVEL: %d\n",
                                __func__, val);
                info->flash_mode = AS364X_REG_CONTROL_MODE_ASSIST;
                err = as364x_set_leds(info, info->led_mask, val, val);
                return err;
        case NVC_PARAM_FLASH_PIN_STATE:
-               dev_info(&info->i2c_client->dev, "%s FLASH_PIN_STATE: %d\n",
+               dev_dbg(&info->i2c_client->dev, "%s FLASH_PIN_STATE: %d\n",
                                __func__, val);
                return as364x_strobe(info, val);
        default:
@@ -1087,6 +1090,7 @@ static int as364x_power_get(struct as364x_info *info)
 
        as364x_regulator_get(info, &pw->v_in, "vin"); /* 3.7v */
        as364x_regulator_get(info, &pw->v_i2c, "vi2c"); /* 1.8v */
+       info->pwr_state = NVC_PWR_OFF;
 
        return 0;
 }
index eb55336..1aa353f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
 #include <media/imx091.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
@@ -27,16 +28,17 @@ struct imx091_reg {
 };
 
 struct imx091_info {
-       int                         mode;
-       struct imx091_sensordata    sensor_data;
-       struct i2c_client           *i2c_client;
-       struct imx091_platform_data *pdata;
-       atomic_t                    in_use;
+       struct miscdevice               miscdev_info;
+       int                             mode;
+       struct imx091_power_rail        power;
+       struct imx091_sensordata        sensor_data;
+       struct i2c_client               *i2c_client;
+       struct imx091_platform_data     *pdata;
+       atomic_t                        in_use;
 };
 
 #define IMX091_TABLE_WAIT_MS 0
 #define IMX091_TABLE_END 1
-#define IMX091_MAX_RETRIES 3
 
 #define IMX091_WAIT_MS 3
 
@@ -901,7 +903,6 @@ imx091_write_reg(struct i2c_client *client, u16 addr, u8 val)
        int err;
        struct i2c_msg msg;
        unsigned char data[3];
-       int retry = 0;
 
        if (!client->adapter)
                return -ENODEV;
@@ -915,15 +916,12 @@ imx091_write_reg(struct i2c_client *client, u16 addr, u8 val)
        msg.len = 3;
        msg.buf = data;
 
-       do {
-               err = i2c_transfer(client->adapter, &msg, 1);
-               if (err == 1)
-                       return 0;
-               retry++;
-               pr_err("[IMX091]:%s:i2c transfer failed, retrying %x %x\n",
-                      __func__, addr, val);
-               msleep_range(3);
-       } while (retry <= IMX091_MAX_RETRIES);
+       err = i2c_transfer(client->adapter, &msg, 1);
+       if (err == 1)
+               return 0;
+
+       pr_err("%s:i2c write failed, %x = %x\n",
+              __func__, addr, val);
 
        return err;
 }
@@ -960,7 +958,7 @@ imx091_write_table(struct i2c_client *client,
 
                err = imx091_write_reg(client, next->addr, val);
                if (err) {
-                       pr_err("[IMX091]:%s:imx091_write_table:%d", __func__, err);
+                       pr_err("%s:imx091_write_table:%d", __func__, err);
                        return err;
                }
        }
@@ -974,7 +972,7 @@ imx091_set_mode(struct imx091_info *info, struct imx091_mode *mode)
        int err;
        struct imx091_reg reg_list[5];
 
-       pr_info("[IMX091]:%s: xres %u yres %u framelength %u coarsetime %u gain %u\n",
+       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);
 
@@ -993,7 +991,7 @@ imx091_set_mode(struct imx091_info *info, struct imx091_mode *mode)
        else if (mode->xres == 1280 && mode->yres == 720)
                sensor_mode = IMX091_MODE_1308X736;
        else {
-               pr_err("[IMX091]:%s: invalid resolution supplied to set mode %d %d\n",
+               pr_err("%s: invalid resolution supplied to set mode %d %d\n",
                         __func__, mode->xres, mode->yres);
                return -EINVAL;
        }
@@ -1187,10 +1185,9 @@ imx091_ioctl(struct file *file,
        case IMX091_IOCTL_SET_MODE:
        {
                struct imx091_mode mode;
-               if (copy_from_user(&mode,
-                        (const void __user *)arg,
-                        sizeof(struct imx091_mode))) {
-                       pr_err("[IMX091]:%s:Failed to get mode from user.\n", __func__);
+               if (copy_from_user(&mode, (const void __user *)arg,
+                       sizeof(struct imx091_mode))) {
+                       pr_err("%s:Failed to get mode from user.\n", __func__);
                        return -EFAULT;
                }
                return imx091_set_mode(info, &mode);
@@ -1209,7 +1206,7 @@ imx091_ioctl(struct file *file,
                if (err)
                        return err;
                if (copy_to_user((void __user *)arg, &status, 1)) {
-                       pr_err("[IMX091]:%s:Failed to copy status to user.\n", __func__);
+                       pr_err("%s:Failed to copy status to user\n", __func__);
                        return -EFAULT;
                        }
                return 0;
@@ -1219,14 +1216,13 @@ imx091_ioctl(struct file *file,
                err = imx091_get_sensor_id(info);
 
                if (err) {
-                       pr_err("[IMX091]:%s:Failed to get fuse id info.\n", __func__);
+                       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 imx091_sensordata))) {
-                       pr_info("[IMX091]:%s:Failed to copy fuse id to user space\n",
-                                       __func__);
+               if (copy_to_user((void __user *)arg, &info->sensor_data,
+                               sizeof(struct imx091_sensordata))) {
+                       pr_info("%s:Failed to copy fuse id to user space\n",
+                               __func__);
                        return -EFAULT;
                }
                return 0;
@@ -1236,35 +1232,37 @@ imx091_ioctl(struct file *file,
          struct imx091_ae ae;
          if (copy_from_user(&ae, (const void __user *)arg,
                        sizeof(struct imx091_ae))) {
-               pr_info("[IMX091]:%s:fail group hold\n", __func__);
+               pr_info("%s:fail group hold\n", __func__);
                return -EFAULT;
          }
          return imx091_set_group_hold(info, &ae);
        }
        default:
-         pr_err("[IMX091]:%s:unknown cmd.\n", __func__);
+         pr_err("%s:unknown cmd.\n", __func__);
          return -EINVAL;
        }
        return 0;
 }
 
-static struct imx091_info *info;
-
 static int
 imx091_open(struct inode *inode, struct file *file)
 {
+       struct miscdevice       *miscdev = file->private_data;
+       struct imx091_info *info;
+
+       info = container_of(miscdev, struct imx091_info, miscdev_info);
        /* check if the device is in use */
        if (atomic_xchg(&info->in_use, 1)) {
-               pr_info("[IMX091]:%s:BUSY!\n", __func__);
+               pr_info("%s:BUSY!\n", __func__);
                return -EBUSY;
        }
 
        file->private_data = info;
 
        if (info->pdata && info->pdata->power_on)
-               info->pdata->power_on(&info->i2c_client->dev);
+               info->pdata->power_on(&info->power);
        else{
-               pr_err("[IMX091]:%s:no valid power_on function.\n", __func__);
+               pr_err("%s:no valid power_on function.\n", __func__);
                return -EEXIST;
        }
 
@@ -1274,8 +1272,10 @@ imx091_open(struct inode *inode, struct file *file)
 static int
 imx091_release(struct inode *inode, struct file *file)
 {
+       struct imx091_info *info = file->private_data;
+
        if (info->pdata && info->pdata->power_off)
-               info->pdata->power_off(&info->i2c_client->dev);
+               info->pdata->power_off(&info->power);
        file->private_data = NULL;
 
        /* warn if device is already released */
@@ -1283,6 +1283,57 @@ imx091_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int imx091_power_put(struct imx091_power_rail *pw)
+{
+       if (unlikely(!pw))
+               return -EFAULT;
+
+       if (likely(pw->avdd))
+               regulator_put(pw->avdd);
+
+       if (likely(pw->iovdd))
+               regulator_put(pw->iovdd);
+
+       if (likely(pw->dvdd))
+               regulator_put(pw->dvdd);
+
+       pw->avdd = NULL;
+       pw->iovdd = NULL;
+       pw->dvdd = NULL;
+
+       return 0;
+}
+
+static int imx091_regulator_get(struct imx091_info *info,
+       struct regulator **vreg, char vreg_name[])
+{
+       struct regulator *reg = NULL;
+       int err = 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 imx091_power_get(struct imx091_info *info)
+{
+       struct imx091_power_rail *pw = &info->power;
+
+       imx091_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */
+       imx091_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */
+       imx091_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */
+
+       return 0;
+}
 
 static const struct file_operations imx091_fileops = {
        .owner = THIS_MODULE,
@@ -1301,30 +1352,42 @@ static int
 imx091_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       struct imx091_info *info;
        int err;
 
        pr_info("[IMX091]: probing sensor.\n");
 
-       info = kzalloc(sizeof(struct imx091_info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev,
+                       sizeof(struct imx091_info), GFP_KERNEL);
        if (!info) {
-               pr_err("[IMX091]:%s:Unable to allocate memory!\n", __func__);
+               pr_err("%s:Unable to allocate memory!\n", __func__);
                return -ENOMEM;
        }
 
-       err = misc_register(&imx091_device);
-       if (err) {
-               pr_err("[IMX091]:%s:Unable to register misc device!\n", __func__);
-               kfree(info);
-               return err;
-       }
-
        info->pdata = client->dev.platform_data;
        info->i2c_client = client;
        atomic_set(&info->in_use, 0);
        info->mode = -1;
 
+       imx091_power_get(info);
+
+       memcpy(&info->miscdev_info,
+               &imx091_device,
+               sizeof(struct miscdevice));
+
+       err = misc_register(&info->miscdev_info);
+       if (err) {
+               pr_err("%s:Unable to register misc device!\n", __func__);
+               goto imx091_probe_fail;
+       }
+
        i2c_set_clientdata(client, info);
        return 0;
+
+imx091_probe_fail:
+       imx091_power_put(&info->power);
+
+       return err;
 }
 
 static int
@@ -1333,7 +1396,9 @@ imx091_remove(struct i2c_client *client)
        struct imx091_info *info;
        info = i2c_get_clientdata(client);
        misc_deregister(&imx091_device);
-       kfree(info);
+
+       imx091_power_put(&info->power);
+
        return 0;
 }
 
index f0b521c..fc1ac17 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
 #include <media/imx132.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
@@ -29,16 +30,17 @@ struct imx132_reg {
 };
 
 struct imx132_info {
-       int                         mode;
-       struct imx132_sensordata    sensor_data;
-       struct i2c_client           *i2c_client;
-       struct imx132_platform_data *pdata;
-       atomic_t                    in_use;
+       struct miscdevice               miscdev_info;
+       int                             mode;
+       struct imx132_power_rail        power;
+       struct imx132_sensordata        sensor_data;
+       struct i2c_client               *i2c_client;
+       struct imx132_platform_data     *pdata;
+       atomic_t                        in_use;
 };
 
 #define IMX132_TABLE_WAIT_MS 0
 #define IMX132_TABLE_END 1
-#define IMX132_MAX_RETRIES 3
 
 #define IMX132_WAIT_MS 5
 
@@ -232,7 +234,6 @@ imx132_write_reg(struct i2c_client *client, u16 addr, u8 val)
        int err;
        struct i2c_msg msg;
        unsigned char data[3];
-       int retry = 0;
 
        if (!client->adapter)
                return -ENODEV;
@@ -246,15 +247,12 @@ imx132_write_reg(struct i2c_client *client, u16 addr, u8 val)
        msg.len = 3;
        msg.buf = data;
 
-       do {
-               err = i2c_transfer(client->adapter, &msg, 1);
-               if (err == 1)
-                       return 0;
-               retry++;
-               pr_err("[imx132]:%s:i2c transfer failed, retrying %x %x\n",
-                               __func__, addr, val);
-               msleep_range(3);
-       } while (retry <= IMX132_MAX_RETRIES);
+       err = i2c_transfer(client->adapter, &msg, 1);
+       if (err == 1)
+               return 0;
+
+       dev_err(&client->dev, "%s:i2c write failed, %x = %x\n",
+                       __func__, addr, val);
 
        return err;
 }
@@ -293,7 +291,7 @@ imx132_write_table(struct i2c_client *client,
 
                err = imx132_write_reg(client, next->addr, val);
                if (err) {
-                       pr_err("[imx132]:%s:imx132_write_table:%d",
+                       dev_err(&client->dev, "%s:imx132_write_table:%d",
                                __func__, err);
                        return err;
                }
@@ -304,18 +302,19 @@ imx132_write_table(struct i2c_client *client,
 static int
 imx132_set_mode(struct imx132_info *info, struct imx132_mode *mode)
 {
+       struct device *dev = &info->i2c_client->dev;
        int sensor_mode;
        int err;
        struct imx132_reg reg_list[5];
 
-       pr_info("[imx132]:%s: res [%ux%u] framelen %u coarsetime %u gain %u\n",
+       dev_info(dev, "%s: res [%ux%u] framelen %u coarsetime %u gain %u\n",
                __func__, mode->xres, mode->yres,
                mode->frame_length, mode->coarse_time, mode->gain);
 
        if (mode->xres == 1920 && mode->yres == 1080)
                sensor_mode = IMX132_MODE_1920X1080;
        else {
-               pr_err("[imx132]:%s: invalid resolution to set mode %d %d\n",
+               dev_err(dev, "%s: invalid resolution to set mode %d %d\n",
                        __func__, mode->xres, mode->yres);
                return -EINVAL;
        }
@@ -334,7 +333,7 @@ imx132_set_mode(struct imx132_info *info, struct imx132_mode *mode)
                return err;
 
        info->mode = sensor_mode;
-       pr_info("[imx132]: stream on.\n");
+       dev_info(dev, "[imx132]: stream on.\n");
        return 0;
 }
 
@@ -517,6 +516,7 @@ imx132_ioctl(struct file *file,
 {
        int err;
        struct imx132_info *info = file->private_data;
+       struct device *dev = &info->i2c_client->dev;
 
        switch (cmd) {
        case IMX132_IOCTL_SET_MODE:
@@ -525,7 +525,7 @@ imx132_ioctl(struct file *file,
                if (copy_from_user(&mode,
                        (const void __user *)arg,
                        sizeof(struct imx132_mode))) {
-                       pr_err("[imx132]:%s:Failed to get mode from user.\n",
+                       dev_err(dev, "%s:Failed to get mode from user.\n",
                        __func__);
                        return -EFAULT;
                }
@@ -545,7 +545,7 @@ imx132_ioctl(struct file *file,
                if (err)
                        return err;
                if (copy_to_user((void __user *)arg, &status, 1)) {
-                       pr_err("[imx132]:%s:Failed to copy status to user.\n",
+                       dev_err(dev, "%s:Failed to copy status to user.\n",
                        __func__);
                        return -EFAULT;
                }
@@ -556,14 +556,14 @@ imx132_ioctl(struct file *file,
                err = imx132_get_sensor_id(info);
 
                if (err) {
-                       pr_err("[imx132]:%s:Failed to get fuse id info.\n",
+                       dev_err(dev, "%s:Failed to get fuse id info.\n",
                        __func__);
                        return err;
                }
                if (copy_to_user((void __user *)arg,
                                &info->sensor_data,
                                sizeof(struct imx132_sensordata))) {
-                       pr_info("[imx132]:%s:Fail copy fuse id to user space\n",
+                       dev_info(dev, "%s:Fail copy fuse id to user space\n",
                                __func__);
                        return -EFAULT;
                }
@@ -574,35 +574,38 @@ imx132_ioctl(struct file *file,
                struct imx132_ae ae;
                if (copy_from_user(&ae, (const void __user *)arg,
                                sizeof(struct imx132_ae))) {
-                       pr_info("[imx132]:%s:fail group hold\n", __func__);
+                       dev_info(dev, "%s:fail group hold\n", __func__);
                        return -EFAULT;
                }
                return imx132_set_group_hold(info, &ae);
        }
        default:
-               pr_err("[imx132]:%s:unknown cmd.\n", __func__);
+               dev_err(dev, "%s:unknown cmd.\n", __func__);
                return -EINVAL;
        }
        return 0;
 }
 
-static struct imx132_info *info;
-
 static int
 imx132_open(struct inode *inode, struct file *file)
 {
+       struct miscdevice       *miscdev = file->private_data;
+       struct imx132_info      *info;
+
+       info = container_of(miscdev, struct imx132_info, miscdev_info);
        /* check if the device is in use */
        if (atomic_xchg(&info->in_use, 1)) {
-               pr_info("[imx132]:%s:BUSY!\n", __func__);
+               dev_info(&info->i2c_client->dev, "%s:BUSY!\n", __func__);
                return -EBUSY;
        }
 
        file->private_data = info;
 
        if (info->pdata && info->pdata->power_on)
-               info->pdata->power_on(&info->i2c_client->dev);
+               info->pdata->power_on(&info->power);
        else {
-               pr_err("[imx132]:%s:no valid power_on function.\n", __func__);
+               dev_err(&info->i2c_client->dev,
+                       "%s:no valid power_on function.\n", __func__);
                return -EEXIST;
        }
 
@@ -612,8 +615,10 @@ imx132_open(struct inode *inode, struct file *file)
 static int
 imx132_release(struct inode *inode, struct file *file)
 {
+       struct imx132_info *info = file->private_data;
+
        if (info->pdata && info->pdata->power_off)
-               info->pdata->power_off(&info->i2c_client->dev);
+               info->pdata->power_off(&info->power);
        file->private_data = NULL;
 
        /* warn if device is already released */
@@ -621,6 +626,54 @@ imx132_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int imx132_power_put(struct imx132_power_rail *pw)
+{
+       if (likely(pw->dvdd))
+               regulator_put(pw->dvdd);
+
+       if (likely(pw->avdd))
+               regulator_put(pw->avdd);
+
+       if (likely(pw->iovdd))
+               regulator_put(pw->iovdd);
+
+       pw->dvdd = NULL;
+       pw->avdd = NULL;
+       pw->iovdd = NULL;
+
+       return 0;
+}
+
+static int imx132_regulator_get(struct imx132_info *info,
+       struct regulator **vreg, char vreg_name[])
+{
+       struct regulator *reg = NULL;
+       int err = 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 imx132_power_get(struct imx132_info *info)
+{
+       struct imx132_power_rail *pw = &info->power;
+
+       imx132_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */
+       imx132_regulator_get(info, &pw->avdd, "vana"); /* analog 2.7v */
+       imx132_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */
+
+       return 0;
+}
 
 static const struct file_operations imx132_fileops = {
        .owner = THIS_MODULE,
@@ -639,40 +692,48 @@ static int
 imx132_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       int err;
+       struct imx132_info *info;
+       int err = 0;
 
        pr_info("[imx132]: probing sensor.\n");
 
-       info = kzalloc(sizeof(struct imx132_info), GFP_KERNEL);
+       info = devm_kzalloc(&client->dev,
+               sizeof(struct imx132_info), GFP_KERNEL);
        if (!info) {
                pr_err("[imx132]:%s:Unable to allocate memory!\n", __func__);
                return -ENOMEM;
        }
 
-       err = misc_register(&imx132_device);
-       if (err) {
-               pr_err("[imx132]:%s:Unable to register misc device!\n",
-               __func__);
-               kfree(info);
-               return err;
-       }
-
        info->pdata = client->dev.platform_data;
        info->i2c_client = client;
        atomic_set(&info->in_use, 0);
        info->mode = -1;
 
        i2c_set_clientdata(client, info);
-       return 0;
+
+       imx132_power_get(info);
+
+       memcpy(&info->miscdev_info,
+               &imx132_device,
+               sizeof(struct miscdevice));
+
+       err = misc_register(&info->miscdev_info);
+       if (err) {
+               imx132_power_put(&info->power);
+               pr_err("[imx132]:%s:Unable to register misc device!\n",
+               __func__);
+       }
+
+       return err;
 }
 
 static int
 imx132_remove(struct i2c_client *client)
 {
-       struct imx132_info *info;
-       info = i2c_get_clientdata(client);
+       struct imx132_info *info = i2c_get_clientdata(client);
+
+       imx132_power_put(&info->power);
        misc_deregister(&imx132_device);
-       kfree(info);
        return 0;
 }
 
index bfea5fe..bd69526 100644 (file)
@@ -181,9 +181,8 @@ struct ov9772_info {
        int pwr_api;
        int pwr_dev;
        struct nvc_gpio gpio[ARRAY_SIZE(ov9772_gpio)];
-       struct nvc_regulator vreg_avdd;
-       struct nvc_regulator vreg_dvdd;
-       struct nvc_regulator vreg_dovdd;
+       struct ov9772_power_rail regulators;
+       bool power_on;
        u8 s_mode;
        struct ov9772_info *s_info;
        u32 mode_index;
@@ -853,68 +852,88 @@ static void ov9772_gpio_init(struct ov9772_info *info)
        }
 }
 
-static void ov9772_pm_regulator_put(struct nvc_regulator *sreg)
-{
-       regulator_put(sreg->vreg);
-       sreg->vreg = NULL;
-}
-
-static int ov9772_pm_regulator_get(struct ov9772_info *info,
-                               struct nvc_regulator *sreg,
-                               char vreg_name[])
+static int ov9772_power_off(struct ov9772_info *info)
 {
+       struct ov9772_power_rail *pw = &info->regulators;
        int err = 0;
 
-       sreg->vreg_flag = 0;
-       sreg->vreg = regulator_get(&info->i2c_client->dev, vreg_name);
-       if (IS_ERR(sreg->vreg)) {
-               dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
-                       __func__, vreg_name, (int)sreg->vreg);
-               err = PTR_ERR(sreg->vreg);
-               sreg->vreg = NULL;
-       } else {
-               sreg->vreg_name = vreg_name;
-               dev_dbg(&info->i2c_client->dev, "%s: %s\n",
-                       __func__, sreg->vreg_name);
-       }
-       return err;
-}
+       if (!info->power_on)
+               goto ov9772_poweroff_skip;
 
-static int ov9772_pm_regulator_en(struct ov9772_info *info,
-                               struct nvc_regulator *sreg)
-{
-       int err = 0;
+       if (info->pdata && info->pdata->power_off)
+               err = info->pdata->power_off(pw);
+       /* if customized design handles the power off process specifically,
+       * return is bigger than 0 (normally 1), otherwise 0 or error num.
+       */
+       if (err > 0) {
+               info->power_on = false;
+               return 0;
+       }
 
-       if (!sreg->vreg_flag && (sreg->vreg != NULL)) {
-               err = regulator_enable(sreg->vreg);
-               if (!err) {
-                       dev_dbg(&info->i2c_client->dev, "%s: %s\n",
-                               __func__, sreg->vreg_name);
-                       sreg->vreg_flag = 1;
-                       err = 1; /* flag regulator state change */
-               } else {
-                       dev_err(&info->i2c_client->dev, "%s %s ERR\n",
-                               __func__, sreg->vreg_name);
-               }
+       if (!err) {
+               ov9772_gpio_pwrdn(info, 1);
+               ov9772_gpio_shutdn(info, 1);
+               ov9772_gpio_able(info, 0);
+               if (pw->avdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err = regulator_disable(pw->avdd)));
+               if (pw->dvdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_disable(pw->dvdd)));
+               if (pw->dovdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_disable(pw->dovdd)));
        }
+
+       if (!err)
+               info->power_on = false;
+
+ov9772_poweroff_skip:
        return err;
 }
 
-static int ov9772_pm_regulator_dis(struct ov9772_info *info,
-                               struct nvc_regulator *sreg)
+static int ov9772_power_on(struct ov9772_info *info, bool standby)
 {
+       struct ov9772_power_rail *pw = &info->regulators;
        int err = 0;
 
-       if (sreg->vreg_flag && (sreg->vreg != NULL)) {
-               err = regulator_disable(sreg->vreg);
-               if (!err)
-                       dev_dbg(&info->i2c_client->dev, "%s: %s\n",
-                               __func__, sreg->vreg_name);
-               else
-                       dev_err(&info->i2c_client->dev, "%s %s ERR\n",
-                               __func__, sreg->vreg_name);
+       if (info->power_on)
+               goto ov9772_poweron_skip;
+
+       if (info->pdata && info->pdata->power_on)
+               err = info->pdata->power_on(pw);
+       /* if customized design handles the power on process specifically,
+       * return is bigger than 0 (normally 1), otherwise 0 or error num.
+       */
+       if (!err) {
+               if (pw->dvdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err = regulator_enable(pw->dvdd)));
+               if (pw->dovdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_enable(pw->dovdd)));
+               if (pw->avdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_enable(pw->avdd)));
+               ov9772_gpio_able(info, 1);
+               ov9772_gpio_shutdn(info, 0);
+               ov9772_gpio_pwrdn(info, 0); /* PWRDN off to access I2C */
+       }
+       if (IS_ERR_VALUE(err))
+               return err;
+       info->power_on = true;
+       err = 0;
+
+ov9772_poweron_skip:
+       if (standby) {
+               err |= ov9772_i2c_wr8(info, 0x3002, 0x18); /*avoid GPIO leak */
+               ov9772_gpio_pwrdn(info, 1); /* PWRDN on for standby */
+       } else {
+               err |= ov9772_i2c_wr8(info, 0x3002, 0x19);
+               err |= ov9772_i2c_wr8(info, 0x3025, 0x00); /* out of standby */
+               err |= ov9772_i2c_wr8(info, 0x4815, 0x20); /* out of standby */
        }
-       sreg->vreg_flag = 0;
+
        return err;
 }
 
@@ -933,38 +952,18 @@ static int ov9772_pm_wr(struct ov9772_info *info, int pwr)
        case NVC_PWR_OFF_FORCE:
        case NVC_PWR_OFF:
        case NVC_PWR_STDBY_OFF:
-               ov9772_gpio_pwrdn(info, 1);
-               ov9772_gpio_shutdn(info, 1);
-               ov9772_gpio_able(info, 0);
-               err = ov9772_pm_regulator_dis(info, &info->vreg_avdd);
-               err |= ov9772_pm_regulator_dis(info, &info->vreg_dvdd);
-               err |= ov9772_pm_regulator_dis(info, &info->vreg_dovdd);
+               err = ov9772_power_off(info);
                info->mode_valid = false;
                info->bin_en = 0;
                break;
 
        case NVC_PWR_STDBY:
-               err = ov9772_pm_regulator_en(info, &info->vreg_dvdd);
-               err |= ov9772_pm_regulator_en(info, &info->vreg_dovdd);
-               err |= ov9772_pm_regulator_en(info, &info->vreg_avdd);
-               ov9772_gpio_able(info, 1);
-               ov9772_gpio_shutdn(info, 0);
-               ov9772_gpio_pwrdn(info, 0); /* PWRDN off to access I2C */
-               err |= ov9772_i2c_wr8(info, 0x3002, 0x18); /* avoid GPIO leak */
-               ov9772_gpio_pwrdn(info, 1); /* PWRDN on for standby */
+               err = ov9772_power_on(info, true);
                break;
 
        case NVC_PWR_COMM:
        case NVC_PWR_ON:
-               err = ov9772_pm_regulator_en(info, &info->vreg_dvdd);
-               err |= ov9772_pm_regulator_en(info, &info->vreg_dovdd);
-               err |= ov9772_pm_regulator_en(info, &info->vreg_avdd);
-               ov9772_gpio_able(info, 1);
-               ov9772_gpio_shutdn(info, 0);
-               ov9772_gpio_pwrdn(info, 0);
-               err |= ov9772_i2c_wr8(info, 0x3002, 0x19);
-               err |= ov9772_i2c_wr8(info, 0x3025, 0x00); /* out of standby */
-               err |= ov9772_i2c_wr8(info, 0x4815, 0x20); /* out of standby */
+               err = ov9772_power_on(info, false);
                break;
 
        default:
@@ -1030,19 +1029,53 @@ static int ov9772_pm_dev_wr(struct ov9772_info *info, int pwr)
 
 static void ov9772_pm_exit(struct ov9772_info *info)
 {
+       struct ov9772_power_rail *pw = &info->regulators;
+
        ov9772_pm_wr(info, NVC_PWR_OFF_FORCE);
-       ov9772_pm_regulator_put(&info->vreg_avdd);
-       ov9772_pm_regulator_put(&info->vreg_dvdd);
-       ov9772_pm_regulator_put(&info->vreg_dovdd);
+
+       if (pw->avdd)
+               regulator_put(pw->avdd);
+       if (pw->dvdd)
+               regulator_put(pw->dvdd);
+       if (pw->dovdd)
+               regulator_put(pw->dovdd);
+       pw->avdd = NULL;
+       pw->dvdd = NULL;
+       pw->dovdd = NULL;
+
        ov9772_gpio_exit(info);
 }
 
+static int ov9772_regulator_get(
+       struct ov9772_info *info, struct regulator **vreg, char vreg_name[])
+{
+       struct regulator *reg = NULL;
+       int err = 0;
+
+       reg = regulator_get(&info->i2c_client->dev, vreg_name);
+       if (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 void ov9772_pm_init(struct ov9772_info *info)
 {
+       struct ov9772_power_rail *pw = &info->regulators;
+
        ov9772_gpio_init(info);
-       ov9772_pm_regulator_get(info, &info->vreg_avdd, "avdd");
-       ov9772_pm_regulator_get(info, &info->vreg_dvdd, "dvdd");
-       ov9772_pm_regulator_get(info, &info->vreg_dovdd, "dovdd");
+
+       ov9772_regulator_get(info, &pw->avdd, "avdd");
+       ov9772_regulator_get(info, &pw->dvdd, "dvdd");
+       ov9772_regulator_get(info, &pw->dovdd, "dovdd");
+       info->power_on = false;
 }
 
 static int ov9772_reset(struct ov9772_info *info, int level)
@@ -1052,9 +1085,8 @@ static int ov9772_reset(struct ov9772_info *info, int level)
        if (level == NVC_RESET_SOFT) {
                err = ov9772_pm_wr(info, NVC_PWR_COMM);
                err |= ov9772_i2c_wr8(info, 0x0103, 0x01); /* SW reset */
-       } else {
+       } else
                err = ov9772_pm_wr(info, NVC_PWR_OFF_FORCE);
-       }
        err |= ov9772_pm_wr(info, info->pwr_api);
        return err;
 }
@@ -1890,13 +1922,6 @@ static int ov9772_open(struct inode *inode, struct file *file)
                        return -EBUSY;
                info->sdata.stereo_cap = 1;
        }
-       if (info->pdata && info->pdata->power_on)
-               info->pdata->power_on(&info->i2c_client->dev);
-       else{
-               pr_err("[ov9772]:%s:no valid power_on function.\n",
-                      __func__);
-               return -EEXIST;
-       }
 
        file->private_data = info;
        dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
@@ -1907,8 +1932,6 @@ int ov9772_release(struct inode *inode, struct file *file)
 {
        struct ov9772_info *info = file->private_data;
 
-       if (info->pdata && info->pdata->power_off)
-               info->pdata->power_off(&info->i2c_client->dev);
        dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
        ov9772_pm_wr_s(info, NVC_PWR_OFF);
        file->private_data = NULL;
index 1e38dbc..e4adab2 100644 (file)
 
 #define IMX091_IOCTL_SET_MODE                  _IOW('o', 1, struct imx091_mode)
 #define IMX091_IOCTL_GET_STATUS                        _IOR('o', 2, __u8)
-#define IMX091_IOCTL_SET_FRAME_LENGTH  _IOW('o', 3, __u32)
-#define IMX091_IOCTL_SET_COARSE_TIME   _IOW('o', 4, __u32)
+#define IMX091_IOCTL_SET_FRAME_LENGTH          _IOW('o', 3, __u32)
+#define IMX091_IOCTL_SET_COARSE_TIME           _IOW('o', 4, __u32)
 #define IMX091_IOCTL_SET_GAIN                  _IOW('o', 5, __u16)
-#define IMX091_IOCTL_GET_SENSORDATA            _IOR('o', 6, struct imx091_sensordata)
+#define IMX091_IOCTL_GET_SENSORDATA            _IOR('o', 6, \
+                                               struct imx091_sensordata)
 #define IMX091_IOCTL_SET_GROUP_HOLD            _IOW('o', 7, struct imx091_ae)
 
 struct imx091_mode {
@@ -44,9 +45,15 @@ struct imx091_sensordata {
 };
 
 #ifdef __KERNEL__
+struct imx091_power_rail {
+       struct regulator *dvdd;
+       struct regulator *avdd;
+       struct regulator *iovdd;
+};
+
 struct imx091_platform_data {
-       int (*power_on)(struct device *);
-       int (*power_off)(struct device *);
+       int (*power_on)(struct imx091_power_rail *pw);
+       int (*power_off)(struct imx091_power_rail *pw);
 };
 #endif /* __KERNEL__ */
 
index 0c64a80..01d7c67 100644 (file)
@@ -55,9 +55,15 @@ struct imx132_sensordata {
 };
 
 #ifdef __KERNEL__
+struct imx132_power_rail {
+       struct regulator *dvdd;
+       struct regulator *avdd;
+       struct regulator *iovdd;
+};
+
 struct imx132_platform_data {
-       int (*power_on)(struct device *);
-       int (*power_off)(struct device *);
+       int (*power_on)(struct imx132_power_rail *pw);
+       int (*power_off)(struct imx132_power_rail *pw);
 };
 #endif /* __KERNEL__ */
 
index 6fe4194..82075b7 100644 (file)
@@ -27,6 +27,12 @@ enum ov9772_gpio_type {
        OV9772_GPIO_TYPE_GP3,
 };
 
+struct ov9772_power_rail {
+       struct regulator *dvdd;
+       struct regulator *avdd;
+       struct regulator *dovdd;
+};
+
 struct ov9772_platform_data {
        unsigned cfg;
        unsigned num;
@@ -41,7 +47,7 @@ struct ov9772_platform_data {
        unsigned lens_view_angle_h; /* / _INT2FLOAT_DIVISOR */
        unsigned lens_view_angle_v; /* / _INT2FLOAT_DIVISOR */
        int (*probe_clock)(unsigned long);
-       int (*power_on)(struct device *);
-       int (*power_off)(struct device *);
+       int (*power_on)(struct ov9772_power_rail *);
+       int (*power_off)(struct ov9772_power_rail *);
 };
 #endif  /* __OV9772_H__ */