]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
media: video: tegra: Add OV9772 DT support
authorSudhir Vyas <svyas@nvidia.com>
Mon, 19 Aug 2013 06:31:00 +0000 (12:01 +0530)
committerDan Willemsen <dwillemsen@nvidia.com>
Sat, 14 Sep 2013 20:41:33 +0000 (13:41 -0700)
Add DT support for OV9772 sensor.

Bug 1242883

Change-Id: Ic22b85c79d186c520e216717e6f1e1322e7f0a16
Signed-off-by: Sudhir Vyas <svyas@nvidia.com>
Reviewed-on: http://git-master/r/263058
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
drivers/media/video/tegra/ov9772.c
include/media/ov9772.h

index e24ca95c8c20ec64743d4b78f966faac171e86e8..fc218ec7cbc28dd671e54ab0b10e738d35bacb14 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 #include <media/ov9772.h>
 #include "nvc_utilities.h"
@@ -1216,6 +1219,9 @@ static int ov9772_power_off(struct ov9772_info *info)
                if (pw->dovdd)
                        WARN_ON(IS_ERR_VALUE(
                                err |= regulator_disable(pw->dovdd)));
+               if (pw->afvdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_disable(pw->afvdd)));
        }
 
        if (!err)
@@ -1252,12 +1258,16 @@ static int ov9772_power_on(struct ov9772_info *info, bool standby)
                if (pw->dvdd)
                        WARN_ON(IS_ERR_VALUE(
                                err = regulator_enable(pw->dvdd)));
+               if (pw->avdd)
+                       WARN_ON(IS_ERR_VALUE(
+                               err |= regulator_enable(pw->avdd)));
                if (pw->dovdd)
                        WARN_ON(IS_ERR_VALUE(
                                err |= regulator_enable(pw->dovdd)));
-               if (pw->avdd)
+               if (pw->afvdd)
                        WARN_ON(IS_ERR_VALUE(
-                               err |= regulator_enable(pw->avdd)));
+                               err |= regulator_enable(pw->afvdd)));
+
                ov9772_gpio_able(info, 1);
                ov9772_gpio_shutdn(info, 0);
                ov9772_gpio_pwrdn(info, 0); /* PWRDN off to access I2C */
@@ -1391,9 +1401,13 @@ static void ov9772_pm_exit(struct ov9772_info *info)
                regulator_put(pw->dvdd);
        if (pw->dovdd)
                regulator_put(pw->dovdd);
+       if (pw->afvdd)
+               regulator_put(pw->afvdd);
+
        pw->avdd = NULL;
        pw->dvdd = NULL;
        pw->dovdd = NULL;
+       pw->afvdd = NULL;
 
        ov9772_gpio_exit(info);
 }
@@ -1427,6 +1441,8 @@ static void ov9772_pm_init(struct ov9772_info *info)
        ov9772_regulator_get(info, &pw->avdd, "avdd");
        ov9772_regulator_get(info, &pw->dvdd, "dvdd");
        ov9772_regulator_get(info, &pw->dovdd, "dovdd");
+       ov9772_regulator_get(info, &pw->afvdd, "vdd_af_cam1");
+
        info->power_on = false;
 }
 
@@ -2363,6 +2379,84 @@ static int ov9772_remove(struct i2c_client *client)
        return 0;
 }
 
+static struct of_device_id ov9772_of_match[] = {
+       { .compatible = "nvidia,ov9772", },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, ov9772_of_match);
+
+static int ov9772_parse_dt_gpio(struct device_node *np, const char *name,
+                       enum ov9772_gpio_type type,
+                       struct nvc_gpio_pdata *pdata)
+{
+       enum of_gpio_flags gpio_flags;
+
+       if (of_find_property(np, name, NULL)) {
+               pdata->gpio = of_get_named_gpio_flags(np, name, 0, &gpio_flags);
+               pdata->gpio_type = type;
+               pdata->init_en = true;
+               pdata->active_high = !(gpio_flags & OF_GPIO_ACTIVE_LOW);
+               return 1;
+       }
+       return 0;
+}
+
+static struct ov9772_platform_data *ov9772_parse_dt(struct i2c_client *client)
+{
+       struct device_node *np = client->dev.of_node;
+       struct ov9772_platform_data *board_info_pdata;
+       struct nvc_gpio_pdata *gpio_pdata = NULL;
+       const struct of_device_id *match;
+
+       match = of_match_device(ov9772_of_match, &client->dev);
+       if (!match) {
+               dev_err(&client->dev, "Failed to find matching dt id\n");
+               return NULL;
+       }
+
+       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 ERR_PTR(-ENOMEM);
+       }
+
+       gpio_pdata = devm_kzalloc(&client->dev,
+               sizeof(*gpio_pdata) * ARRAY_SIZE(ov9772_gpio),
+               GFP_KERNEL);
+       if (!gpio_pdata) {
+               dev_err(&client->dev, "cannot allocate gpio data memory\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* init with default platform data values */
+       memcpy(board_info_pdata, &ov9772_dflt_pdata, sizeof(*board_info_pdata));
+
+       /* generic info */
+       of_property_read_u32(np, "nvidia,num", &board_info_pdata->num);
+       of_property_read_string(np, "nvidia,dev_name",
+                               &board_info_pdata->dev_name);
+       board_info_pdata->vcm_vdd = of_property_read_bool(np, "nvidia,vcm_vdd");
+
+       /* ov9772 gpios */
+       board_info_pdata->gpio_count = 0;
+       board_info_pdata->gpio_count += ov9772_parse_dt_gpio(np,
+                               "power-gpios", OV9772_GPIO_TYPE_SHTDN,
+                               &gpio_pdata[board_info_pdata->gpio_count]);
+       board_info_pdata->gpio_count += ov9772_parse_dt_gpio(np,
+                               "reset-gpios", OV9772_GPIO_TYPE_PWRDN,
+                               &gpio_pdata[board_info_pdata->gpio_count]);
+
+       board_info_pdata->gpio = gpio_pdata;
+
+       /* Use driver's default power functions */
+       board_info_pdata->power_on = NULL;
+       board_info_pdata->power_off = NULL;
+
+       return board_info_pdata;
+}
+
 static int ov9772_probe(
        struct i2c_client *client,
        const struct i2c_device_id *id)
@@ -2381,20 +2475,24 @@ static int ov9772_probe(
        }
 
        info->i2c_client = client;
-       if (client->dev.platform_data) {
+
+       if (client->dev.of_node) {
+               info->pdata = ov9772_parse_dt(client);
+       } else if (client->dev.platform_data) {
                info->pdata = client->dev.platform_data;
        } else {
                info->pdata = &ov9772_dflt_pdata;
                dev_dbg(&client->dev,
                        "%s No platform data.  Using defaults.\n", __func__);
        }
+
        if (info->pdata->cap)
                info->cap = info->pdata->cap;
        else
                info->cap = &ov9772_dflt_cap;
 
        mclk_name = info->pdata->mclk_name ?
-                   info->pdata->mclk_name : "default_mclk";
+                       info->pdata->mclk_name : "default_mclk";
        info->mclk = devm_clk_get(&client->dev, mclk_name);
        if (IS_ERR(info->mclk)) {
                dev_err(&client->dev, "%s: unable to get clock %s\n",
index 161083a60604361e9812600717441baae9523741..454a74d912029b6905eb372f0fd3c5aa2fcd6809 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * nvc_ov9772.h - ov9772 sensor driver
  *
- *  * Copyright (c) 2012 NVIDIA Corporation.  All rights reserved.
+ *  * Copyright (c) 2012-2013 NVIDIA Corporation.  All rights reserved.
  *
  * Contributors:
  *     Phil Breczinski <pbreczinski@nvidia.com>
@@ -31,6 +31,7 @@ struct ov9772_power_rail {
        struct regulator *dvdd;
        struct regulator *avdd;
        struct regulator *dovdd;
+       struct regulator *afvdd;
 };
 
 struct ov9772_platform_data {
@@ -48,6 +49,7 @@ struct ov9772_platform_data {
        unsigned lens_view_angle_v; /* / _INT2FLOAT_DIVISOR */
        const char *mclk_name;
        int (*probe_clock)(unsigned long);
+       bool vcm_vdd;
        int (*power_on)(struct ov9772_power_rail *);
        int (*power_off)(struct ov9772_power_rail *);
 };