summary refs log tree commit diff
path: root/drivers/media/i2c/mt9p031.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/mt9p031.c')
-rw-r--r--drivers/media/i2c/mt9p031.c87
1 files changed, 62 insertions, 25 deletions
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 28cf95b37285..4734836fe5a4 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -16,18 +16,19 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/gpio.h>
-#include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
 #include <media/mt9p031.h>
-#include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
 #include <media/v4l2-subdev.h>
 
 #include "aptina-pll.h"
@@ -124,9 +125,7 @@ struct mt9p031 {
 	int power_count;
 
 	struct clk *clk;
-	struct regulator *vaa;
-	struct regulator *vdd;
-	struct regulator *vdd_io;
+	struct regulator_bulk_data regulators[3];
 
 	enum mt9p031_model model;
 	struct aptina_pll pll;
@@ -271,23 +270,26 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
 
 static int mt9p031_power_on(struct mt9p031 *mt9p031)
 {
+	int ret;
+
 	/* Ensure RESET_BAR is low */
-	if (mt9p031->reset != -1) {
+	if (gpio_is_valid(mt9p031->reset)) {
 		gpio_set_value(mt9p031->reset, 0);
 		usleep_range(1000, 2000);
 	}
 
 	/* Bring up the supplies */
-	regulator_enable(mt9p031->vdd);
-	regulator_enable(mt9p031->vdd_io);
-	regulator_enable(mt9p031->vaa);
+	ret = regulator_bulk_enable(ARRAY_SIZE(mt9p031->regulators),
+				   mt9p031->regulators);
+	if (ret < 0)
+		return ret;
 
 	/* Emable clock */
 	if (mt9p031->clk)
 		clk_prepare_enable(mt9p031->clk);
 
 	/* Now RESET_BAR must be high */
-	if (mt9p031->reset != -1) {
+	if (gpio_is_valid(mt9p031->reset)) {
 		gpio_set_value(mt9p031->reset, 1);
 		usleep_range(1000, 2000);
 	}
@@ -297,14 +299,13 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
 
 static void mt9p031_power_off(struct mt9p031 *mt9p031)
 {
-	if (mt9p031->reset != -1) {
+	if (gpio_is_valid(mt9p031->reset)) {
 		gpio_set_value(mt9p031->reset, 0);
 		usleep_range(1000, 2000);
 	}
 
-	regulator_disable(mt9p031->vaa);
-	regulator_disable(mt9p031->vdd_io);
-	regulator_disable(mt9p031->vdd);
+	regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
+			       mt9p031->regulators);
 
 	if (mt9p031->clk)
 		clk_disable_unprepare(mt9p031->clk);
@@ -849,18 +850,18 @@ static int mt9p031_registered(struct v4l2_subdev *subdev)
 
 	/* Read out the chip version register */
 	data = mt9p031_read(client, MT9P031_CHIP_VERSION);
+	mt9p031_power_off(mt9p031);
+
 	if (data != MT9P031_CHIP_VERSION_VALUE) {
 		dev_err(&client->dev, "MT9P031 not detected, wrong version "
 			"0x%04x\n", data);
 		return -ENODEV;
 	}
 
-	mt9p031_power_off(mt9p031);
-
 	dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
 		 client->addr);
 
-	return ret;
+	return 0;
 }
 
 static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
@@ -928,10 +929,36 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
  * Driver initialization and probing
  */
 
+static struct mt9p031_platform_data *
+mt9p031_get_pdata(struct i2c_client *client)
+{
+	struct mt9p031_platform_data *pdata;
+	struct device_node *np;
+
+	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+		return client->dev.platform_data;
+
+	np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+	if (!np)
+		return NULL;
+
+	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		goto done;
+
+	pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
+	of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
+	of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
+
+done:
+	of_node_put(np);
+	return pdata;
+}
+
 static int mt9p031_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
-	struct mt9p031_platform_data *pdata = client->dev.platform_data;
+	struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct mt9p031 *mt9p031;
 	unsigned int i;
@@ -958,14 +985,14 @@ static int mt9p031_probe(struct i2c_client *client,
 	mt9p031->model = did->driver_data;
 	mt9p031->reset = -1;
 
-	mt9p031->vaa = devm_regulator_get(&client->dev, "vaa");
-	mt9p031->vdd = devm_regulator_get(&client->dev, "vdd");
-	mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io");
+	mt9p031->regulators[0].supply = "vdd";
+	mt9p031->regulators[1].supply = "vdd_io";
+	mt9p031->regulators[2].supply = "vaa";
 
-	if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) ||
-	    IS_ERR(mt9p031->vdd_io)) {
+	ret = devm_regulator_bulk_get(&client->dev, 3, mt9p031->regulators);
+	if (ret < 0) {
 		dev_err(&client->dev, "Unable to get regulators\n");
-		return -ENODEV;
+		return ret;
 	}
 
 	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
@@ -1031,7 +1058,7 @@ static int mt9p031_probe(struct i2c_client *client,
 	mt9p031->format.field = V4L2_FIELD_NONE;
 	mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-	if (pdata->reset != -1) {
+	if (gpio_is_valid(pdata->reset)) {
 		ret = devm_gpio_request_one(&client->dev, pdata->reset,
 					    GPIOF_OUT_INIT_LOW, "mt9p031_rst");
 		if (ret < 0)
@@ -1070,8 +1097,18 @@ static const struct i2c_device_id mt9p031_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mt9p031_id);
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt9p031_of_match[] = {
+	{ .compatible = "aptina,mt9p031", },
+	{ .compatible = "aptina,mt9p031m", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt9p031_of_match);
+#endif
+
 static struct i2c_driver mt9p031_i2c_driver = {
 	.driver = {
+		.of_match_table = of_match_ptr(mt9p031_of_match),
 		.name = "mt9p031",
 	},
 	.probe          = mt9p031_probe,