media: video: tegra: Fix kernel warning for AD5816
Frank Chen [Tue, 11 Jun 2013 19:22:45 +0000 (12:22 -0700)]
Fix unbalanced reference count for power regulator to
prevent kernel from generating warning messages.

bug 1342770

Change-Id: I2e165a205ba58b0478c5f4db3c4b3bb74fa69e07
Signed-off-by: Frank Chen <frankc@nvidia.com>
Reviewed-on: http://git-master/r/258900
Reviewed-by: Charlie Huang <chahuang@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Sachin Nikam <snikam@nvidia.com>

drivers/media/video/tegra/ad5816.c

index ee925ab..ecad29c 100644 (file)
@@ -125,6 +125,7 @@ struct ad5816_info {
        atomic_t in_use;
        bool reset_flag;
        int pwr_dev;
+       int pwr_api;
        s32 pos;
        u16 dev_id;
 };
@@ -334,9 +335,35 @@ static int ad5816_power_get(struct ad5816_info *info)
        return 0;
 }
 
+static int ad5816_pm_api_wr(struct ad5816_info *info, int pwr)
+{
+       int err = 0;
+
+       if (!pwr || (pwr > NVC_PWR_ON))
+               return 0;
+
+       if (pwr > info->pwr_dev)
+               err = ad5816_pm_wr(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 ad5816_pm_dev_wr(struct ad5816_info *info, int pwr)
+{
+       if (pwr < info->pwr_api)
+               pwr = info->pwr_api;
+       return ad5816_pm_wr(info, pwr);
+}
+
 static inline void ad5816_pm_exit(struct ad5816_info *info)
 {
-       ad5816_pm_wr(info, NVC_PWR_OFF_FORCE);
+       ad5816_pm_dev_wr(info, NVC_PWR_OFF_FORCE);
        ad5816_power_put(&info->power);
 }
 
@@ -352,8 +379,9 @@ static int ad5816_reset(struct ad5816_info *info, u32 level)
        if (level == NVC_RESET_SOFT)
                err |= ad5816_i2c_wr8(info, CONTROL, 0x01); /* SW reset */
        else
-               err = ad5816_pm_wr(info, NVC_PWR_OFF_FORCE);
+               err = ad5816_pm_dev_wr(info, NVC_PWR_OFF_FORCE);
 
+       err |= ad5816_pm_wr(info, info->pwr_api);
        return err;
 }
 
@@ -661,10 +689,10 @@ static long ad5816_ioctl(struct file *file,
                /* This is a Guaranteed Level of Service (GLOS) call */
                pwr = (int)arg * 2;
                dev_dbg(info->dev, "%s PWR_WR: %d\n", __func__, pwr);
-               err = ad5816_pm_wr(info, pwr);
+               err = ad5816_pm_api_wr(info, pwr);
                return err;
        case NVC_IOCTL_PWR_RD:
-               pwr = info->pwr_dev;
+               pwr = info->pwr_api / 2;
                dev_dbg(info->dev, "%s PWR_RD: %d\n", __func__, pwr);
                if (copy_to_user((void __user *)arg,
                        (const void *)&pwr, sizeof(pwr))) {
@@ -810,11 +838,11 @@ static int ad5816_probe(
        list_add_rcu(&info->list, &ad5816_info_list);
        spin_unlock(&ad5816_spinlock);
        ad5816_pm_init(info);
-
+       info->pwr_api = NVC_PWR_OFF;
        if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) {
-               ad5816_pm_wr(info, NVC_PWR_COMM);
+               ad5816_pm_dev_wr(info, NVC_PWR_COMM);
                err = ad5816_dev_id(info);
-               ad5816_pm_wr(info, NVC_PWR_OFF);
+               ad5816_pm_dev_wr(info, NVC_PWR_OFF);
                if (err < 0) {
                        dev_err(info->dev, "%s device not found\n",
                                __func__);