summaryrefslogtreecommitdiff
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 28cf95b..4734836 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,