drivers: media: tegra: edp support
David Wang [Wed, 23 Oct 2013 22:34:09 +0000 (15:34 -0700)]
on ov5693 and mt9m114 (SOC1040)

bug 1391722
bug 1391719

Change-Id: Ic0830ea803cf8a50e8ef94d3c0c1393d0a29da10
Signed-off-by: David Wang <davidw@nvidia.com>
Reviewed-on: http://git-master/r/302932
Reviewed-by: Mitch Luban <mluban@nvidia.com>
Tested-by: Mitch Luban <mluban@nvidia.com>

drivers/media/platform/tegra/mt9m114.c
drivers/media/platform/tegra/ov5693.c
include/media/mt9m114.h
include/media/ov5693.h

index b6141db..50c2129 100644 (file)
@@ -353,6 +353,8 @@ struct mt9m114_info {
        const struct mt9m114_reg        *mode;
        u8                              i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
        struct clk *mclk;
+       struct edp_client *edpc;
+       unsigned int edp_state;
 };
 
 struct mt9m114_mode_desc {
@@ -380,6 +382,95 @@ static const struct regmap_config sensor_regmap_config = {
 static long mt9m114_ioctl(struct file *file,
                        unsigned int cmd, unsigned long arg);
 
+static void mt9m114_edp_lowest(struct mt9m114_info *info)
+{
+       if (!info->edpc)
+               return;
+
+       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 TO HAPPEN!\n");
+               dev_err(&info->i2c_client->dev,
+                       "UNABLE TO SET LOWEST EDP STATE!\n");
+       }
+}
+
+static void mt9m114_edp_throttle(unsigned int new_state, void *priv_data)
+{
+       struct mt9m114_info *info = priv_data;
+
+       if (info->pdata && info->pdata->power_off)
+               info->pdata->power_off(&info->power);
+}
+
+static void mt9m114_edp_register(struct mt9m114_info *info)
+{
+       struct edp_manager *edp_manager;
+       struct edp_client *edpc = &info->pdata->edpc_config;
+       int ret;
+
+       info->edpc = NULL;
+       if (!edpc->num_states) {
+               dev_warn(&info->i2c_client->dev,
+                       "%s: No edp states defined.\n", __func__);
+               return;
+       }
+
+       strncpy(edpc->name, "mt9m114", EDP_NAME_LEN - 1);
+       edpc->name[EDP_NAME_LEN - 1] = 0;
+       edpc->private_data = info;
+       edpc->throttle = mt9m114_edp_throttle;
+
+       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]);
+
+       edp_manager = edp_get_manager("battery");
+       if (!edp_manager) {
+               dev_err(&info->i2c_client->dev,
+                       "unable to get edp manager: battery\n");
+               return;
+       }
+
+       ret = edp_register_client(edp_manager, edpc);
+       if (ret) {
+               dev_err(&info->i2c_client->dev,
+                       "unable to register edp client\n");
+               return;
+       }
+
+       info->edpc = edpc;
+       /* set to lowest state at init */
+       mt9m114_edp_lowest(info);
+}
+
+static int mt9m114_edp_req(struct mt9m114_info *info, unsigned new_state)
+{
+       unsigned approved;
+       int ret = 0;
+
+       if (!info->edpc)
+               return 0;
+
+       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;
+       }
+
+       if (approved > new_state) {
+               dev_err(&info->i2c_client->dev, "EDP no enough current\n");
+               return -ENODEV;
+       }
+
+       info->edp_state = approved;
+       return 0;
+}
+
 static inline void mt9m114_msleep(u32 t)
 {
        usleep_range(t*1000, t*1000 + 500);
@@ -480,8 +571,10 @@ int mt9m114_release(struct inode *inode, struct file *file)
 {
        struct mt9m114_info *info = file->private_data;
 
-       if (info->pdata && info->pdata->power_off)
+       if (info->pdata && info->pdata->power_off) {
                info->pdata->power_off(&info->power);
+               mt9m114_edp_lowest(info);
+       }
        file->private_data = NULL;
 
        /* warn if device is already released */
@@ -606,6 +699,14 @@ static int mt9m114_set_mode(struct mt9m114_info *info,
                return -EINVAL;
        }
 
+       /* request highest edp state */
+       err = mt9m114_edp_req(info, 0);
+       if (err) {
+               dev_err(&info->i2c_client->dev,
+                       "%s: ERROR cannot set edp state! %d\n", __func__, err);
+               return err;
+       }
+
        err = mt9m114_write_table(
                info, sensor_mode->mode_tbl);
        if (err)
@@ -686,6 +787,7 @@ static int mt9m114_probe(struct i2c_client *client,
        }
 
        mt9m114_power_get(info);
+       mt9m114_edp_register(info);
        mt9m114_mode_info_init(info);
 
        memcpy(&info->miscdev_info,
index 671ce0d..645cda9 100644 (file)
@@ -72,6 +72,8 @@ struct ov5693_info {
        struct regmap *regmap;
        struct regulator *ext_vcm_vdd;
        struct ov5693_cal_data cal;
+       struct edp_client *edpc;
+       unsigned int edp_state;
 };
 
 struct ov5693_reg {
@@ -2129,6 +2131,95 @@ static const struct ov5693_reg *mode_table[] = {
        [OV5693_MODE_1280x720_HDR_60FPS] = ov5693_1280x720_HDR_60fps_i2c,
 };
 
+static void ov5693_edp_lowest(struct ov5693_info *info)
+{
+       if (!info->edpc)
+               return;
+
+       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 TO HAPPEN!\n");
+               dev_err(&info->i2c_client->dev,
+                       "UNABLE TO SET LOWEST EDP STATE!\n");
+       }
+}
+
+static void ov5693_edp_throttle(unsigned int new_state, void *priv_data)
+{
+       struct ov5693_info *info = priv_data;
+
+       if (info->pdata && info->pdata->power_off)
+               info->pdata->power_off(&info->regulators);
+}
+
+static void ov5693_edp_register(struct ov5693_info *info)
+{
+       struct edp_manager *edp_manager;
+       struct edp_client *edpc = &info->pdata->edpc_config;
+       int ret;
+
+       info->edpc = NULL;
+       if (!edpc->num_states) {
+               dev_warn(&info->i2c_client->dev,
+                       "%s: No edp states defined.\n", __func__);
+               return;
+       }
+
+       strncpy(edpc->name, "ov5693", EDP_NAME_LEN - 1);
+       edpc->name[EDP_NAME_LEN - 1] = 0;
+       edpc->private_data = info;
+       edpc->throttle = ov5693_edp_throttle;
+
+       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]);
+
+       edp_manager = edp_get_manager("battery");
+       if (!edp_manager) {
+               dev_err(&info->i2c_client->dev,
+                       "unable to get edp manager: battery\n");
+               return;
+       }
+
+       ret = edp_register_client(edp_manager, edpc);
+       if (ret) {
+               dev_err(&info->i2c_client->dev,
+                       "unable to register edp client\n");
+               return;
+       }
+
+       info->edpc = edpc;
+       /* set to lowest state at init */
+       ov5693_edp_lowest(info);
+}
+
+static int ov5693_edp_req(struct ov5693_info *info, unsigned new_state)
+{
+       unsigned approved;
+       int ret = 0;
+
+       if (!info->edpc)
+               return 0;
+
+       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;
+       }
+
+       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 ov5693_i2c_rd8(struct ov5693_info *info, u16 reg, u8 *val)
 {
        unsigned int data;
@@ -2636,6 +2727,7 @@ static int ov5693_power_off(struct ov5693_info *info)
                info->power_on = false;
                ov5693_gpio_pwrdn(info, 1);
                ov5693_mclk_disable(info);
+               ov5693_edp_lowest(info);
        } else {
                dev_err(&info->i2c_client->dev,
                        "%s ERR: has no power_off function\n", __func__);
@@ -2852,6 +2944,14 @@ static int ov5693_set_mode(struct ov5693_info *info,
                        mode_index = OV5693_MODE_1280x720_120FPS;
        }
 
+       /* request highest edp state */
+       err = ov5693_edp_req(info, 0);
+       if (err) {
+               dev_err(&info->i2c_client->dev,
+                       "%s: ERROR cannot set edp state! %d\n", __func__, err);
+               return err;
+       }
+
        if (!info->mode_valid || (info->mode_index != mode_index))
                err = ov5693_mode_wr_full(info, mode_index);
        else
@@ -3004,7 +3104,6 @@ static long ov5693_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return ret;
        }
 
-
        case OV5693_IOCTL_SET_GAIN:
                return ov5693_set_gain(info, (u32)arg, true);
 
@@ -3340,6 +3439,8 @@ static int ov5693_probe(
        if (!info->regulators.avdd || !info->regulators.dovdd)
                return -EFAULT;
 
+       ov5693_edp_register(info);
+
        ov5693_sdata_init(info);
        if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) {
                if (info->pdata->probe_clock) {
index d52aa0b..1f93611 100644 (file)
@@ -20,6 +20,7 @@
 #define __MT9M114_H__
 
 #include <linux/ioctl.h>  /* For IOCTL macros */
+#include <linux/edp.h>
 
 #define SENSOR_NAME     "mt9m114"
 #define DEV(x)          "/dev/"x
@@ -108,6 +109,7 @@ struct mt9m114_platform_data {
        int (*power_on)(struct mt9m114_power_rail *pw);
        int (*power_off)(struct mt9m114_power_rail *pw);
        const char *mclk_name;
+       struct edp_client edpc_config;
 };
 #endif /* __KERNEL__ */
 
index 2329956..27fc25a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <media/nvc.h>
 #include <media/nvc_image.h>
+#include <linux/edp.h>
 
 #define OV5693_IOCTL_SET_MODE               _IOW('o', 1, struct ov5693_mode)
 #define OV5693_IOCTL_SET_FRAME_LENGTH       _IOW('o', 2, __u32)
@@ -115,6 +116,7 @@ struct ov5693_platform_data {
        int (*power_on)(struct ov5693_power_rail *);
        int (*power_off)(struct ov5693_power_rail *);
        const char *mclk_name;
+       struct edp_client edpc_config;
 };
 
 #endif  /* __OV5693_H__ */