media: video: tegra: PCL update
Charlie Huang [Wed, 17 Jul 2013 16:14:42 +0000 (09:14 -0700)]
add edp client support.
add clock control.
add state report from sequence execution.

bug 1272149

Change-Id: Iafffce3294ddd92509521ec3b4335e93b5bb7e1a
Signed-off-by: Charlie Huang <chahuang@nvidia.com>
Reviewed-on: http://git-master/r/250318
(cherry picked from commit 1adb9cd0fedce19be53db716a14a385e9d878ac4)
Reviewed-on: http://git-master/r/261169
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Thomas Cherry <tcherry@nvidia.com>

drivers/media/video/tegra/cam_dev/Makefile
drivers/media/video/tegra/cam_dev/dev_access.c
drivers/media/video/tegra/cam_dev/edp.c [new file with mode: 0644]
drivers/media/video/tegra/cam_dev/virtual.c
drivers/media/video/tegra/camera.c
include/media/camera.h

index 994f964..691d685 100644 (file)
@@ -8,5 +8,6 @@ subdir-ccflags-y := -Werror
 obj-$(CONFIG_VIDEO_CAMERA)             += dev_access.o
 obj-$(CONFIG_VIDEO_CAMERA)             += debugfs.o
 obj-$(CONFIG_VIDEO_CAMERA)             += virtual.o
+obj-$(CONFIG_VIDEO_CAMERA)             += edp.o
 obj-$(CONFIG_CAMERA_DEV_AS364X)                += as364x.o
 obj-$(CONFIG_CAMERA_DEV_IMX135)                += imx135.o
index cdb7237..b4acec9 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
 
 #include <media/nvc.h>
 #include <media/camera.h>
@@ -114,11 +115,51 @@ static int camera_dev_wr_blk(
 }
 
 int camera_dev_parser(
-       struct camera_device *cdev, u32 addr, u32 val)
+       struct camera_device *cdev,
+       u32 command, u32 val,
+       struct camera_seq_status *pst)
 {
+       int err = 0;
        u8 flag = 0;
 
-       switch (addr) {
+       switch (command) {
+       case CAMERA_TABLE_EDP_STATE:
+               err = camera_edp_req(cdev, val);
+               if (pst)
+                       pst->status = cdev->edpc.edp_state;
+               if (err < 0)
+                       return err;
+               break;
+       case CAMERA_TABLE_INX_CGATE:
+       case CAMERA_TABLE_INX_CLOCK:
+       {
+               struct clk *ck;
+               int idx = val & CAMERA_TABLE_CLOCK_INDEX_MASK;
+
+               idx >>= CAMERA_TABLE_CLOCK_VALUE_BITS;
+               val &= CAMERA_TABLE_CLOCK_VALUE_MASK;
+               if (idx >= cdev->num_clk) {
+                       dev_err(cdev->dev,
+                               "clock index %d out of range.\n", idx);
+                       return -ENODEV;
+               }
+
+               ck = cdev->clks[idx];
+               dev_dbg(cdev->dev, "%s CAMERA_TABLE_INX_CLOCK %d %d, %d %p\n",
+                       __func__, idx, val, cdev->num_clk, ck);
+               if (ck) {
+                       if (val) {
+                               if (command == CAMERA_TABLE_INX_CLOCK)
+                                       err = clk_set_rate(ck, val * 1000);
+                               if (!err)
+                                       err = clk_prepare_enable(ck);
+                       } else
+                               clk_disable_unprepare(ck);
+               }
+               if (err)
+                       return err;
+               break;
+       }
        case CAMERA_TABLE_PWR:
        {
                struct nvc_regulator *preg;
@@ -145,7 +186,7 @@ int camera_dev_parser(
                        if (err) {
                                dev_err(cdev->dev, "%s %s err\n",
                                        __func__, preg->vreg_name);
-                               return -EFAULT;
+                               return -EIO;
                        }
                } else
                        dev_dbg(cdev->dev, "%s not available\n",
@@ -165,7 +206,7 @@ int camera_dev_parser(
                gpio = &cdev->gpios[val];
                if (gpio->valid) {
                        flag = gpio->active_high ? 0xff : 0;
-                       if (addr != CAMERA_TABLE_GPIO_INX_ACT)
+                       if (command != CAMERA_TABLE_GPIO_INX_ACT)
                                flag = !flag;
                        gpio_set_value(gpio->gpio, flag & 0x01);
                        dev_dbg(cdev->dev, "IDX %d(%d) %d\n", val,
@@ -182,7 +223,7 @@ int camera_dev_parser(
                }
 
                flag = 0xff;
-               if (addr != CAMERA_TABLE_GPIO_ACT)
+               if (command != CAMERA_TABLE_GPIO_ACT)
                        flag = !flag;
                gpio_set_value(val, flag & 0x01);
                dev_dbg(cdev->dev,
@@ -234,15 +275,17 @@ int camera_dev_parser(
                usleep_range(val, val + 20);
                break;
        default:
-               dev_err(cdev->dev, "unrecognized cmd %x.\n", addr);
+               dev_err(cdev->dev, "unrecognized cmd %x.\n", command);
                return -ENODEV;
-               break;
        }
 
        return 1;
 }
 
-int camera_dev_wr_table(struct camera_device *cdev, struct camera_reg *table)
+int camera_dev_wr_table(
+       struct camera_device *cdev,
+       struct camera_reg *table,
+       struct camera_seq_status *pst)
 {
        const struct camera_reg *next;
        u8 *b_ptr = cdev->i2c_buf;
@@ -253,27 +296,32 @@ int camera_dev_wr_table(struct camera_device *cdev, struct camera_reg *table)
 
        dev_dbg(cdev->dev, "%s\n", __func__);
        if (!cdev->chip) {
-               dev_err(cdev->dev, "%s chip?\n", "EMPTY");
-               return -EFAULT;
+               dev_err(cdev->dev, "EMPTY chip!\n");
+               return -EEXIST;
        }
 
        byte_num = cdev->chip->regmap_cfg.val_bits / 8;
        if (byte_num != 1 && byte_num != 2) {
                dev_err(cdev->dev,
                        "unsupported byte length %d.\n", byte_num);
-               return -EFAULT;
+               return -ENODEV;
        }
 
        for (next = table; next->addr != CAMERA_TABLE_END; next++) {
                dev_dbg(cdev->dev, "%x - %x\n", next->addr, next->val);
                if (next->addr & CAMERA_INT_MASK) {
-                       err = camera_dev_parser(cdev, next->addr, next->val);
+                       err = camera_dev_parser(
+                               cdev, next->addr, next->val, pst);
                        if (err > 0) { /* special cmd executed */
                                err = 0;
                                continue;
                        }
-                       if (err < 0) /* this is a real error */
+                       if (err < 0) { /* this is a real error */
+                               if (pst)
+                                       pst->idx = (next - table) /
+                                               sizeof(*table) + 1;
                                break;
+                       }
                }
 
                if (!buf_count) {
@@ -316,7 +364,7 @@ int camera_regulator_get(struct device *dev,
        dev_dbg(dev, "%s %s", __func__, vreg_name);
        if (vreg_name == NULL) {
                dev_err(dev, "%s NULL regulator name.\n", __func__);
-               return -EFAULT;
+               return -ENODEV;
        }
        reg = regulator_get(dev, vreg_name);
        if (unlikely(IS_ERR_OR_NULL(reg))) {
diff --git a/drivers/media/video/tegra/cam_dev/edp.c b/drivers/media/video/tegra/cam_dev/edp.c
new file mode 100644 (file)
index 0000000..e3ff6bb
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * edp.c
+ *
+ * Copyright (c) 2013, 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/>.
+ */
+
+#define CAMERA_DEVICE_INTERNAL
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/gpio.h>
+#include <linux/edp.h>
+
+#include <media/nvc.h>
+#include <media/camera.h>
+
+void camera_edp_lowest(struct camera_device *cdev)
+{
+       struct camera_edp_cfg *cam_edp = &cdev->edpc;
+       struct edp_client *edp_client = &cam_edp->edp_client;
+
+       if (!cam_edp->edpc_en)
+               return;
+
+       cam_edp->edp_state = edp_client->num_states - 1;
+       dev_dbg(cdev->dev, "%s %d\n", __func__, cam_edp->edp_state);
+       if (edp_update_client_request(edp_client, cam_edp->edp_state, NULL)) {
+               dev_err(cdev->dev, "THIS IS NOT LIKELY HAPPEN!\n");
+               dev_err(cdev->dev, "UNABLE TO SET LOWEST EDP STATE!\n");
+       }
+}
+
+static void camera_edp_throttle(unsigned int new_state, void *priv_data)
+{
+       struct camera_device *cdev = priv_data;
+
+       if (cdev->edpc.shutdown)
+               cdev->edpc.shutdown(cdev);
+}
+
+void camera_edp_register(struct camera_device *cdev)
+{
+       struct edp_manager *edp_manager;
+       struct camera_edp_cfg *cam_edp = &cdev->edpc;
+       struct edp_client *edp_client = &cam_edp->edp_client;
+       int ret;
+
+       if (!edp_client->num_states) {
+               dev_notice(cdev->dev, "%s: NO edp states defined.\n", __func__);
+               return;
+       }
+       cam_edp->edpc_en = 0;
+
+       snprintf(edp_client->name, sizeof(edp_client->name) - 1, "%x%02x%s",
+               cdev->client->adapter->nr, cdev->client->addr, cdev->name);
+       edp_client->name[EDP_NAME_LEN - 1] = 0;
+       edp_client->private_data = cdev;
+       edp_client->throttle = camera_edp_throttle;
+
+       dev_dbg(cdev->dev, "%s: %s, e0 = %d, p %d\n", __func__,
+               edp_client->name, edp_client->e0_index, edp_client->priority);
+       for (ret = 0; ret < edp_client->num_states; ret++)
+               dev_dbg(cdev->dev, "e%d = %d mA",
+                       ret - edp_client->e0_index, edp_client->states[ret]);
+
+       edp_manager = edp_get_manager("battery");
+       if (!edp_manager) {
+               dev_err(cdev->dev, "unable to get edp manager: battery\n");
+               return;
+       }
+
+       ret = edp_register_client(edp_manager, edp_client);
+       if (ret) {
+               dev_err(cdev->dev, "unable to register edp client\n");
+               return;
+       }
+
+       cam_edp->edpc_en = 1;
+       /* set to lowest state at init */
+       camera_edp_lowest(cdev);
+}
+
+int camera_edp_req(struct camera_device *cdev, unsigned new_state)
+{
+       struct camera_edp_cfg *cam_edp = &cdev->edpc;
+       unsigned approved;
+       int ret = 0;
+
+       if (!cam_edp->edpc_en)
+               return 0;
+
+       dev_dbg(cdev->dev, "%s %d\n", __func__, new_state);
+       ret = edp_update_client_request(
+               &cam_edp->edp_client, new_state, &approved);
+       if (ret) {
+               dev_err(cdev->dev, "E state transition failed\n");
+               return ret;
+       }
+
+       cam_edp->edp_state = approved;
+       if (approved > new_state) {
+               dev_err(cdev->dev, "EDP no enough current\n");
+               return -EAGAIN;
+       }
+
+       return 0;
+}
index 0610b48..a0ba3e7 100644 (file)
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/clk.h>
 
 #include <media/nvc.h>
 #include <media/camera.h>
 
 struct chip_config {
+       int clk_num;
        int gpio_num;
        int reg_num;
        struct camera_reg *seq_power_on;
@@ -41,8 +43,6 @@ struct chip_config {
 static int virtual_update(
        struct camera_device *cdev, struct cam_update *upd, int num)
 {
-       struct nvc_gpio *gpio;
-       u32 *pinmux;
        int err = 0;
        int idx;
 
@@ -50,7 +50,110 @@ static int virtual_update(
        mutex_lock(&cdev->mutex);
        for (idx = 0; idx < num; idx++) {
                switch (upd[idx].type) {
+               case UPDATE_EDP:
+               {
+                       struct edp_cfg ec;
+                       struct edp_client *pec = &cdev->edpc.edp_client;
+
+                       /* update edp throttle seq */
+                       if (upd[idx].index == CAMERA_SEQ_FLAG_EDP) {
+                               u32 sidx = upd[idx].arg;
+                               dev_dbg(cdev->dev, "%s UPDATE_EDP throttle %d\n",
+                                       __func__, sidx);
+                               if (sidx >= NUM_OF_SEQSTACK ||
+                                       !cdev->seq_stack[sidx]) {
+                                       dev_err(cdev->dev, "edp index err!\n");
+                                       err = -ENOENT;
+                                       break;
+                               }
+
+                               cdev->edpc.s_throttle = cdev->seq_stack[sidx];
+                               break;
+                       }
+
+                       dev_dbg(cdev->dev, "%s UPDATE_EDP config\n", __func__);
+                       if (cdev->edpc.edpc_en) {
+                               dev_err(cdev->dev, "edp client already set!\n");
+                               err = -EEXIST;
+                               break;
+                       }
+                       if (upd[idx].size != sizeof(ec)) {
+                               dev_err(cdev->dev, "Invalid edp cfg size!\n");
+                               err = -EINVAL;
+                               break;
+                       }
+                       memset(&ec, 0, sizeof(ec));
+                       if (copy_from_user(&ec,
+                               (const void __user *)upd[idx].arg,
+                               sizeof(ec))) {
+                               dev_err(cdev->dev,
+                                       "%s copy_from_user err line %d\n",
+                                       __func__, __LINE__);
+                               err = -EFAULT;
+                               break;
+                       }
+                       if (ec.num > CAMERA_MAX_EDP_ENTRIES) {
+                               dev_err(cdev->dev, "too many estate entries!\n");
+                               err = -E2BIG;
+                               break;
+                       }
+
+                       memcpy(cdev->estates, ec.estates,
+                               ec.num * sizeof(cdev->estates[0]));
+                       pec->states = cdev->estates;
+                       pec->num_states = ec.num;
+                       pec->e0_index = ec.e0_index;
+                       pec->priority = ec.priority;
+                       camera_edp_register(cdev);
+                       break;
+               }
+               case UPDATE_CLOCK:
+               {
+                       struct clk *ck;
+                       u8 buf[CAMERA_MAX_NAME_LENGTH];
+
+                       if (!cdev->num_clk) {
+                               dev_err(cdev->dev, "NO clock needed.\n");
+                               err = -ENODEV;
+                               break;
+                       }
+                       if (upd[idx].index >= cdev->num_clk) {
+                               dev_err(cdev->dev,
+                                       "clock index %d out of range.\n",
+                                       upd[idx].index);
+                               err = -ENODEV;
+                               break;
+                       }
+
+                       memset(buf, 0, sizeof(buf));
+                       if (copy_from_user(buf,
+                               (const void __user *)upd[idx].arg,
+                               sizeof(buf) - 1 < upd[idx].size ?
+                               sizeof(buf) - 1 : upd[idx].size)) {
+                               dev_err(cdev->dev,
+                                       "%s copy_from_user err line %d\n",
+                                       __func__, __LINE__);
+                               err = -EFAULT;
+                               break;
+                       }
+
+                       dev_dbg(cdev->dev, "%s UPDATE_CLOCK %d of %d, %s\n",
+                               __func__, upd[idx].index, cdev->num_clk, buf);
+                       ck = devm_clk_get(cdev->dev, buf);
+                       if (IS_ERR(ck)) {
+                               dev_err(cdev->dev, "%s: get clock %s FAILED.\n",
+                                       __func__, buf);
+                               return PTR_ERR(ck);
+                       }
+                       cdev->clks[upd[idx].index] = ck;
+                       dev_dbg(cdev->dev, "UPDATE_CLOCK: %d %s\n",
+                               upd[idx].index, buf);
+                       break;
+               }
                case UPDATE_PINMUX:
+               {
+                       u32 *pinmux;
+
                        if (!cdev->pinmux_num) {
                                dev_err(cdev->dev, "NO pinmux available.\n");
                                err = -ENODEV;
@@ -72,7 +175,11 @@ static int virtual_update(
                                pinmux = &cdev->mclk_disable_idx;
                        *pinmux = upd[idx].arg;
                        break;
+               }
                case UPDATE_GPIO:
+               {
+                       struct nvc_gpio *gpio;
+
                        if (upd[idx].index >= cdev->num_gpio) {
                                dev_err(cdev->dev,
                                        "gpio index %d out of range.\n",
@@ -94,6 +201,7 @@ static int virtual_update(
                        gpio->valid = true;
                        cdev->gpios[upd[idx].index] = *gpio;
                        break;
+               }
                default:
                        dev_err(cdev->dev,
                                "unsupported upd type %d\n", upd[idx].type);
@@ -119,7 +227,7 @@ static int virtual_power_on(struct camera_device *cdev)
                return 0;
 
        mutex_lock(&cdev->mutex);
-       err = camera_dev_wr_table(cdev, pwr_seq);
+       err = camera_dev_wr_table(cdev, pwr_seq, NULL);
        if (!err)
                cdev->is_power_on = 1;
        mutex_unlock(&cdev->mutex);
@@ -138,7 +246,7 @@ static int virtual_power_off(struct camera_device *cdev)
                return 0;
 
        mutex_lock(&cdev->mutex);
-       err = camera_dev_wr_table(cdev, pwr_seq);
+       err = camera_dev_wr_table(cdev, pwr_seq, NULL);
        if (!err)
                cdev->is_power_on = 0;
        mutex_unlock(&cdev->mutex);
@@ -146,6 +254,28 @@ static int virtual_power_off(struct camera_device *cdev)
        return err;
 }
 
+static int virtual_shutdown(struct camera_device *cdev)
+{
+       struct camera_reg *t_seq = cdev->edpc.s_throttle;
+       int err = 0;
+
+       dev_dbg(cdev->dev, "%s %x %p\n",
+               __func__, cdev->is_power_on, t_seq);
+       if (!cdev->is_power_on)
+               return 0;
+
+       if (t_seq) {
+               mutex_lock(&cdev->mutex);
+               err = camera_dev_wr_table(cdev, t_seq, NULL);
+               mutex_unlock(&cdev->mutex);
+       }
+
+       if (!err)
+               err = virtual_power_off(cdev);
+
+       return err;
+}
+
 static int virtual_instance_destroy(struct camera_device *cdev)
 {
        void *buf;
@@ -175,8 +305,9 @@ static int virtual_instance_create(struct camera_device *cdev, void *pdata)
        u32 idx;
 
        dev_dbg(cdev->dev, "%s\n", __func__);
-       cdev->gpios = kzalloc(c_info->gpio_num * sizeof(struct nvc_gpio) +
-               c_info->reg_num * sizeof(struct nvc_regulator),
+       cdev->gpios = kzalloc(c_info->gpio_num * sizeof(*cdev->gpios) +
+               c_info->reg_num * sizeof(*cdev->regs) +
+               c_info->clk_num * sizeof(*cdev->clks),
                GFP_KERNEL);
        if (cdev->gpios == NULL) {
                dev_err(cdev->dev, "%s memory low!\n", __func__);
@@ -187,8 +318,10 @@ static int virtual_instance_create(struct camera_device *cdev, void *pdata)
        cdev->pinmux_tbl = ((struct camera_platform_data *)pdata)->pinmux;
        cdev->num_gpio = c_info->gpio_num;
        cdev->regs = (void *)cdev->gpios +
-               c_info->gpio_num * sizeof(struct nvc_gpio);
+               c_info->gpio_num * sizeof(*cdev->gpios);
        cdev->num_reg = c_info->reg_num;
+       cdev->clks = (void *)cdev->regs + c_info->reg_num * sizeof(*cdev->regs);
+       cdev->num_clk = c_info->clk_num;
        cdev->mclk_enable_idx = CAMDEV_INVALID;
        cdev->mclk_disable_idx = CAMDEV_INVALID;
 
@@ -222,8 +355,8 @@ static int virtual_device_sanity_check(
        dev_dbg(dev, "%s: %s, bus type %d, addr bits %d, val bits %d\n",
                __func__, dev_info->name, dev_info->bus_type,
                dev_info->regmap_cfg.addr_bits, dev_info->regmap_cfg.val_bits);
-       dev_dbg(dev, "gpios %d, regs %d\n",
-               dev_info->gpio_num, dev_info->reg_num);
+       dev_dbg(dev, "gpios %d, regs %d, clks %d\n",
+               dev_info->gpio_num, dev_info->reg_num, dev_info->clk_num);
        if (dev_info->name[0] == '\0') {
                dev_err(dev, "%s need a device name!\n", __func__);
                return -ENODEV;
@@ -269,6 +402,11 @@ static int virtual_device_sanity_check(
                        __func__, dev_info->gpio_num);
        }
 
+       if (dev_info->clk_num >= 5) {
+               dev_notice(dev, "%s WHAT?! Are you sure you need %d clocks?\n",
+                       __func__, dev_info->clk_num);
+       }
+
        *len = 0;
        num = dev_info->reg_num;
        nptr = &dev_info->reg_names[0];
@@ -299,6 +437,7 @@ static int virtual_chip_config(
        u32 idx;
 
        dev_dbg(dev, "%s regulators:\n", __func__);
+       c_info->clk_num = dev_info->clk_num;
        c_info->gpio_num = dev_info->gpio_num;
        c_info->reg_num = dev_info->reg_num;
        rptr += sizeof(*c_info) + sizeof(char *) * c_info->reg_num;
@@ -392,6 +531,7 @@ int virtual_device_add(struct device *dev, unsigned long arg)
        v_chip->release = virtual_instance_destroy,
        v_chip->power_on = virtual_power_on,
        v_chip->power_off = virtual_power_off,
+       v_chip->shutdown = virtual_shutdown,
        v_chip->update = virtual_update,
 
        camera_chip_add(v_chip);
index b63e398..e6e07c5 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/clk.h>
 
 #include <media/camera.h>
 
@@ -109,7 +110,9 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
 {
        struct nvc_param params;
        struct camera_device *cdev = cam->cdev;
-       struct camera_reg *p_i2c_table;
+       struct camera_reg *p_i2c_table = NULL;
+       struct camera_seq_status seqs;
+       u8 pfree = 0;
        int err = 0;
        int idx;
 
@@ -125,19 +128,19 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
        dev_dbg(cam->dev, "param: %x, size %d\n", params.param,
                params.sizeofvalue);
        if (params.param == CAMERA_SEQ_EXIST) {
-               if (params.variant >= NUM_OF_SEQSTACK) {
+               idx = params.variant & CAMERA_SEQ_INDEX_MASK;
+               if (idx >= NUM_OF_SEQSTACK) {
                        dev_err(cam->dev, "%s seq index out of range %d\n",
-                               __func__, params.variant);
+                               __func__, idx);
                        return -EFAULT;
                }
-               p_i2c_table = cdev->seq_stack[params.variant];
+               p_i2c_table = cdev->seq_stack[idx];
                if (p_i2c_table == NULL) {
                        dev_err(cam->dev, "%s seq index empty! %d\n",
-                               __func__, params.variant);
+                               __func__, idx);
                        return -EEXIST;
                }
-               err = camera_dev_wr_table(cdev, p_i2c_table);
-               return err;
+               goto seq_wr_table;
        }
 
        p_i2c_table = devm_kzalloc(cdev->dev, params.sizeofvalue, GFP_KERNEL);
@@ -146,13 +149,14 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
                        __func__, __LINE__);
                return -ENOMEM;
        }
+       pfree = 1;
 
        if (copy_from_user(p_i2c_table,
                (const void __user *)params.p_value, params.sizeofvalue)) {
                dev_err(cam->dev, "%s copy_from_user err line %d\n",
                        __func__, __LINE__);
-               devm_kfree(cdev->dev, p_i2c_table);
-               return -EFAULT;
+               err = -EFAULT;
+               goto seq_wr_end;
        }
 
        switch (params.param) {
@@ -161,36 +165,54 @@ static int camera_seq_wr(struct camera_info *cam, unsigned long arg)
                for (idx = 0; idx < NUM_OF_SEQSTACK; idx++) {
                        if (!cdev->seq_stack[idx]) {
                                cdev->seq_stack[idx] = p_i2c_table;
+                               pfree = 0;
                                break;
                        }
                }
                if (idx >= NUM_OF_SEQSTACK) {
                        dev_err(cam->dev, "%s seq index full!\n", __func__);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto seq_wr_end;
                } else {
+                       if (params.variant & CAMERA_SEQ_FLAG_EDP)
+                               cdev->edpc.s_throttle = p_i2c_table;
                        params.variant = idx;
-                       if (copy_to_user((void __user *)arg,
-                               (const void *)&params, sizeof(params))) {
-                               dev_err(cam->dev,
-                                       "%s copy_to_user err line %d\n",
-                                       __func__, __LINE__);
-                               devm_kfree(cdev->dev, p_i2c_table);
-                               return -EFAULT;
-                       }
+                       goto seq_wr_upd;
                }
                if (params.param == CAMERA_SEQ_REGISTER_EXEC)
-                       err |= camera_dev_wr_table(cdev, p_i2c_table);
+                       goto seq_wr_table;
                break;
        case CAMERA_SEQ_EXEC:
-               err |= camera_dev_wr_table(cdev, p_i2c_table);
-               devm_kfree(cdev->dev, p_i2c_table);
                break;
        }
 
+seq_wr_table:
+       if (err < 0)
+               goto seq_wr_end;
+
+       mutex_lock(&cdev->mutex);
+       err = camera_dev_wr_table(cdev, p_i2c_table, &seqs);
+       mutex_unlock(&cdev->mutex);
+       if (err < 0) {
+               params.param = CAMERA_SEQ_STATUS_MASK | seqs.idx;
+               params.variant = seqs.status;
+       }
+
+seq_wr_upd:
+       if (copy_to_user((void __user *)arg,
+               (const void *)&params, sizeof(params))) {
+               dev_err(cam->dev, "%s copy_to_user err line %d\n",
+                       __func__, __LINE__);
+               err = -EFAULT;
+       }
+
+seq_wr_end:
+       if (pfree)
+               devm_kfree(cdev->dev, p_i2c_table);
        return err;
 }
 
-static int camera_dev_power(struct camera_info *cam, unsigned long pwr)
+static int camera_dev_pwr_set(struct camera_info *cam, unsigned long pwr)
 {
        struct camera_device *cdev = cam->cdev;
        struct camera_chip *chip = cdev->chip;
@@ -205,6 +227,7 @@ static int camera_dev_power(struct camera_info *cam, unsigned long pwr)
        case NVC_PWR_STDBY_OFF:
                if (chip->power_off)
                        err |= chip->power_off(cdev);
+               camera_edp_lowest(cdev);
                break;
        case NVC_PWR_STDBY:
        case NVC_PWR_COMM:
@@ -230,7 +253,7 @@ dev_power_end:
        return err;
 }
 
-static int camera_dev_pwrd(struct camera_info *cam, unsigned long arg)
+static int camera_dev_pwr_get(struct camera_info *cam, unsigned long arg)
 {
        int pwr;
        int err = 0;
@@ -302,12 +325,8 @@ static int camera_remove_device(struct camera_device *cdev, bool ref_dec)
        }
        if (cdev->chip)
                (cdev->chip->release)(cdev);
-       /*if (cdev->regmap)
-               regmap_exit(cdev->regmap);*/
        if (cdev->dev)
                i2c_unregister_device(to_i2c_client(cdev->dev));
-       /*for (idx = 0; idx < NUM_OF_SEQSTACK; idx++)
-               kfree(cdev->seq_stack[idx]);*/
        if (ref_dec)
                atomic_dec(&cdev->chip->ref_cnt);
        kfree(cdev);
@@ -601,7 +620,7 @@ static int camera_add_drivers(struct camera_info *cam, unsigned long arg)
                goto add_driver_end;
        }
 
-       if (param.sizeofvalue > sizeof(ref_name)) {
+       if (param.sizeofvalue > sizeof(ref_name) - 1) {
                dev_err(cam->dev, "%s driver name too long %d\n",
                        __func__, param.sizeofvalue);
                err = -EFAULT;
@@ -623,6 +642,7 @@ static int camera_add_drivers(struct camera_info *cam, unsigned long arg)
        while (cm && cm->sensor && strlen(cm->sensor->type)) {
                dev_dbg(cam->dev, "%s\n", cm->sensor->type);
                if (!strcmp(cm->sensor->type, ref_name)) {
+                       dev_dbg(cam->dev, "installing %s\n", cm->sensor->type);
                        client = i2c_new_device(adap, cm->sensor);
                        if (!client) {
                                dev_err(cam->dev, "%s add driver %s fail\n",
@@ -630,19 +650,10 @@ static int camera_add_drivers(struct camera_info *cam, unsigned long arg)
                                err = -EFAULT;
                                break;
                        }
-                       if (cm->sensor &&
-                               strlen(cm->sensor->type)) {
-                               i2c_new_device(adap, cm->sensor);
-                               if (!client) {
-                                       dev_err(cam->dev,
-                                               "%s add driver %s fail\n",
-                                               __func__, cm->sensor->type);
-                                       err = -EFAULT;
-                                       break;
-                               }
-                       }
                        if (cm->focuser && strlen(cm->focuser->type)) {
-                               i2c_new_device(adap, cm->focuser);
+                               dev_dbg(cam->dev, "installing %s\n",
+                                       cm->focuser->type);
+                               client = i2c_new_device(adap, cm->focuser);
                                if (!client) {
                                        dev_err(cam->dev,
                                                "%s add driver %s fail\n",
@@ -652,7 +663,9 @@ static int camera_add_drivers(struct camera_info *cam, unsigned long arg)
                                }
                        }
                        if (cm->flash && strlen(cm->flash->type)) {
-                               i2c_new_device(adap, cm->flash);
+                               dev_dbg(cam->dev, "installing %s\n",
+                                       cm->flash->type);
+                               client = i2c_new_device(adap, cm->flash);
                                if (!client) {
                                        dev_err(cam->dev,
                                                "%s add driver %s fail\n",
@@ -714,10 +727,10 @@ static long camera_ioctl(struct file *file,
                break;
        case PCLLK_IOCTL_PWR_WR:
                /* This is a Guaranteed Level of Service (GLOS) call */
-               err = camera_dev_power(cam, arg);
+               err = camera_dev_pwr_set(cam, arg);
                break;
        case PCLLK_IOCTL_PWR_RD:
-               err = camera_dev_pwrd(cam, arg);
+               err = camera_dev_pwr_get(cam, arg);
                break;
        case PCLLK_IOCTL_UPDATE:
                err = camera_update(cam, arg);
index 8ee55fb..deadd95 100644 (file)
@@ -20,7 +20,9 @@
 #ifdef __KERNEL__
 #include <linux/list.h>
 #include <linux/miscdevice.h>
+#include <linux/i2c.h>
 #include <linux/regmap.h>
+#include <linux/edp.h>
 #include <media/nvc.h>
 #endif
 
 #define CAMERA_TABLE_GPIO_INX_DEACT    (CAMERA_INT_MASK | 33)
 #define CAMERA_TABLE_REG_NEW_POWER     (CAMERA_INT_MASK | 40)
 #define CAMERA_TABLE_INX_POWER         (CAMERA_INT_MASK | 41)
+#define CAMERA_TABLE_INX_CLOCK         (CAMERA_INT_MASK | 50)
+#define CAMERA_TABLE_INX_CGATE         (CAMERA_INT_MASK | 51)
+#define CAMERA_TABLE_EDP_STATE         (CAMERA_INT_MASK | 60)
 
 #define CAMERA_TABLE_PWR_FLAG_MASK     0xf0000000
 #define CAMERA_TABLE_PWR_FLAG_ON       0x80000000
 #define CAMERA_TABLE_PINMUX_FLAG_MASK  0xf0000000
 #define CAMERA_TABLE_PINMUX_FLAG_ON    0x80000000
+#define CAMERA_TABLE_CLOCK_VALUE_BITS  24
+#define CAMERA_TABLE_CLOCK_VALUE_MASK  \
+                       ((u32)(-1) >> (32 - CAMERA_TABLE_CLOCK_VALUE_BITS))
+#define CAMERA_TABLE_CLOCK_INDEX_BITS  (32 - CAMERA_TABLE_CLOCK_VALUE_BITS)
+#define CAMERA_TABLE_CLOCK_INDEX_MASK  \
+                       ((u32)(-1) << (32 - CAMERA_TABLE_CLOCK_INDEX_BITS))
 
 #define PCLLK_IOCTL_CHIP_REG   _IOW('o', 100, struct virtual_device)
 #define PCLLK_IOCTL_DEV_REG    _IOW('o', 104, struct camera_device_info)
 #define PCLLK_IOCTL_PARAM_RD   _IOWR('o', 141, struct nvc_param)
 #define PCLLK_IOCTL_DRV_ADD    _IOW('o', 150, struct nvc_param)
 
+#define CAMERA_MAX_EDP_ENTRIES  16
 #define CAMERA_MAX_NAME_LENGTH 32
 #define CAMDEV_INVALID         0xffffffff
 
+#define        CAMERA_SEQ_STATUS_MASK  0xf0000000
+#define        CAMERA_SEQ_INDEX_MASK   0x0000ffff
+#define        CAMERA_SEQ_FLAG_MASK    (~CAMERA_SEQ_INDEX_MASK)
+#define        CAMERA_SEQ_FLAG_EDP     0x80000000
 enum {
        CAMERA_SEQ_EXEC,
        CAMERA_SEQ_REGISTER_EXEC,
        CAMERA_SEQ_REGISTER_ONLY,
        CAMERA_SEQ_EXIST,
+       CAMERA_SEQ_MAX_NUM,
 };
 
 enum {
        CAMERA_DEVICE_TYPE_I2C,
+       CAMERA_DEVICE_TYPE_MAX_NUM,
 };
 
 struct camera_device_info {
@@ -98,6 +116,13 @@ struct gpio_cfg {
        u8 reserved;
 };
 
+struct edp_cfg {
+       uint estates[CAMERA_MAX_EDP_ENTRIES];
+       uint num;
+       uint e0_index;
+       int priority;
+};
+
 #define VIRTUAL_DEV_MAX_REGULATORS     8
 #define VIRTUAL_DEV_MAX_GPIOS          8
 #define VIRTUAL_REGNAME_SIZE           (VIRTUAL_DEV_MAX_REGULATORS * \
@@ -114,12 +139,15 @@ struct virtual_device {
        struct camera_reg *power_on;
        u32 pwr_off_size;
        struct camera_reg *power_off;
+       u32 clk_num;
 };
 
 enum {
        UPDATE_PINMUX,
        UPDATE_GPIO,
        UPDATE_POWER,
+       UPDATE_CLOCK,
+       UPDATE_EDP,
        UPDATE_MAX_NUM,
 };
 
@@ -127,6 +155,7 @@ struct cam_update {
        u32 type;
        u32 index;
        u32 arg;
+       u32 size;
 };
 
 struct cam_device_layout {
@@ -146,6 +175,8 @@ struct cam_device_layout {
 #define NUM_OF_SEQSTACK                16
 #define SIZEOF_I2C_BUF         32
 
+struct camera_device;
+
 struct camera_module {
        struct i2c_board_info *sensor;
        struct i2c_board_info *focuser;
@@ -159,6 +190,19 @@ struct camera_platform_data {
        struct camera_module *modules;
 };
 
+struct camera_edp_cfg {
+       struct edp_client edp_client;
+       unsigned edp_state;
+       u8 edpc_en;
+       struct camera_reg *s_throttle;
+       int (*shutdown)(struct camera_device *cdev);
+};
+
+struct camera_seq_status {
+       u32 idx;
+       u32 status;
+};
+
 struct camera_device {
        struct list_head list;
        u8 name[CAMERA_MAX_NAME_LENGTH];
@@ -169,6 +213,10 @@ struct camera_device {
        struct camera_info *cam;
        atomic_t in_use;
        struct mutex mutex;
+       uint estates[CAMERA_MAX_EDP_ENTRIES];
+       struct camera_edp_cfg edpc;
+       struct clk **clks;
+       u32 num_clk;
        struct nvc_regulator *regs;
        u32 num_reg;
        struct nvc_gpio *gpios;
@@ -196,6 +244,7 @@ struct camera_chip {
        int     (*release)(struct camera_device *cdev);
        int     (*power_on)(struct camera_device *cdev);
        int     (*power_off)(struct camera_device *cdev);
+       int     (*shutdown)(struct camera_device *cdev);
        int     (*update)(struct camera_device *cdev,
                        struct cam_update *upd, int num);
 };
@@ -229,19 +278,40 @@ struct camera_platform_info {
        size_t size_layout;
 };
 
+/* common functions */
 extern int virtual_device_add(
-       struct device *dev, unsigned long arg);
-extern int camera_regulator_get(struct device *dev,
-       struct nvc_regulator *nvc_reg, char *vreg_name);
+       struct device *, unsigned long
+);
+extern int camera_regulator_get(
+       struct device *, struct nvc_regulator *, char *
+);
 
+/* device access functions */
 extern int camera_dev_parser(
-       struct camera_device *cdev, u32 addr, u32 val);
+       struct camera_device *, u32, u32, struct camera_seq_status *
+);
 extern int camera_dev_wr_table(
-       struct camera_device *cdev, struct camera_reg *table);
+       struct camera_device *, struct camera_reg *, struct camera_seq_status *
+);
 extern int camera_dev_rd_table(
-       struct camera_device *cdev, struct camera_reg *table);
-
-extern int camera_debugfs_init(struct camera_platform_info *info);
+       struct camera_device *, struct camera_reg *
+);
+
+/* edp functions */
+void camera_edp_register(
+       struct camera_device *
+);
+int camera_edp_req(
+       struct camera_device *, unsigned
+);
+void camera_edp_lowest(
+       struct camera_device *
+);
+
+/* debugfs functions */
+extern int camera_debugfs_init(
+       struct camera_platform_info *
+);
 extern int camera_debugfs_remove(void);
 
 #endif