Skip to content

Commit 96ed740

Browse files
flamingradian6by9
authored andcommitted
media: i2c: imx355: Support devicetree and power management
A device tree compatible makes it possible for this driver to be used on Open Firmware devices. Initialization of power-managed resources such as the reset GPIO and voltage regulators can be specified in the device tree and handled by the driver. Add support for this so the Pixel 3a can use the driver. Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
1 parent f5f92ca commit 96ed740

1 file changed

Lines changed: 103 additions & 8 deletions

File tree

drivers/media/i2c/imx355.c

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33

44
#include <linux/acpi.h>
55
#include <linux/clk.h>
6+
#include <linux/delay.h>
7+
#include <linux/gpio/consumer.h>
68
#include <linux/i2c.h>
79
#include <linux/module.h>
10+
#include <linux/of.h>
811
#include <linux/pm_runtime.h>
12+
#include <linux/regulator/consumer.h>
913
#include <linux/unaligned.h>
1014

1115
#include <media/v4l2-ctrls.h>
@@ -125,6 +129,15 @@ struct imx355 {
125129
* Protect access to sensor v4l2 controls.
126130
*/
127131
struct mutex mutex;
132+
133+
struct gpio_desc *reset_gpio;
134+
struct regulator_bulk_data *supplies;
135+
};
136+
137+
static const struct regulator_bulk_data imx355_supplies[] = {
138+
{ .supply = "avdd" },
139+
{ .supply = "dvdd" },
140+
{ .supply = "dovdd" },
128141
};
129142

130143
static const struct imx355_reg imx355_global_regs[] = {
@@ -1515,6 +1528,52 @@ static const struct v4l2_subdev_internal_ops imx355_internal_ops = {
15151528
.open = imx355_open,
15161529
};
15171530

1531+
static int imx355_power_off(struct device *dev)
1532+
{
1533+
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1534+
struct v4l2_subdev *sd = i2c_get_clientdata(client);
1535+
struct imx355 *imx355 = to_imx355(sd);
1536+
1537+
gpiod_set_value_cansleep(imx355->reset_gpio, 1);
1538+
1539+
regulator_bulk_disable(ARRAY_SIZE(imx355_supplies), imx355->supplies);
1540+
clk_disable_unprepare(imx355->clk);
1541+
1542+
return 0;
1543+
}
1544+
1545+
static int imx355_power_on(struct device *dev)
1546+
{
1547+
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1548+
struct v4l2_subdev *sd = i2c_get_clientdata(client);
1549+
struct imx355 *imx355 = to_imx355(sd);
1550+
int ret;
1551+
1552+
ret = clk_prepare_enable(imx355->clk);
1553+
if (ret)
1554+
return dev_err_probe(dev, ret, "failed to enable clocks");
1555+
1556+
ret = regulator_bulk_enable(ARRAY_SIZE(imx355_supplies),
1557+
imx355->supplies);
1558+
if (ret) {
1559+
dev_err_probe(dev, ret, "failed to enable regulators");
1560+
goto error_disable_clocks;
1561+
}
1562+
1563+
usleep_range(1000, 2000);
1564+
gpiod_set_value_cansleep(imx355->reset_gpio, 0);
1565+
usleep_range(10000, 11000);
1566+
1567+
return 0;
1568+
1569+
error_disable_clocks:
1570+
clk_disable_unprepare(imx355->clk);
1571+
return ret;
1572+
}
1573+
1574+
static DEFINE_RUNTIME_DEV_PM_OPS(imx355_pm_ops, imx355_power_off,
1575+
imx355_power_on, NULL);
1576+
15181577
/* Initialize control handlers */
15191578
static int imx355_init_controls(struct imx355 *imx355)
15201579
{
@@ -1689,30 +1748,51 @@ static int imx355_probe(struct i2c_client *client)
16891748
"external clock %lu is not supported\n",
16901749
freq);
16911750

1692-
/* Initialize subdev */
1693-
v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
1694-
1695-
/* Check module identity */
1696-
ret = imx355_identify_module(imx355);
1751+
ret = devm_regulator_bulk_get_const(imx355->dev,
1752+
ARRAY_SIZE(imx355_supplies),
1753+
imx355_supplies,
1754+
&imx355->supplies);
16971755
if (ret) {
1698-
dev_err(imx355->dev, "failed to find sensor: %d", ret);
1756+
dev_err_probe(imx355->dev, ret, "could not get regulators");
16991757
goto error_probe;
17001758
}
17011759

1760+
imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset",
1761+
GPIOD_OUT_HIGH);
1762+
if (IS_ERR(imx355->reset_gpio)) {
1763+
ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio),
1764+
"failed to get gpios");
1765+
goto error_probe;
1766+
}
1767+
1768+
/* Initialize subdev */
1769+
v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
1770+
17021771
imx355->hwcfg = imx355_get_hwcfg(imx355->dev);
17031772
if (!imx355->hwcfg) {
17041773
dev_err(imx355->dev, "failed to get hwcfg");
17051774
ret = -ENODEV;
17061775
goto error_probe;
17071776
}
17081777

1778+
ret = imx355_power_on(imx355->dev);
1779+
if (ret)
1780+
goto error_probe;
1781+
1782+
/* Check module identity */
1783+
ret = imx355_identify_module(imx355);
1784+
if (ret) {
1785+
dev_err(imx355->dev, "failed to find sensor: %d", ret);
1786+
goto error_power_off;
1787+
}
1788+
17091789
/* Set default mode to max resolution */
17101790
imx355->cur_mode = &supported_modes[0];
17111791

17121792
ret = imx355_init_controls(imx355);
17131793
if (ret) {
17141794
dev_err(imx355->dev, "failed to init controls: %d", ret);
1715-
goto error_probe;
1795+
goto error_power_off;
17161796
}
17171797

17181798
/* Initialize subdev */
@@ -1752,6 +1832,9 @@ static int imx355_probe(struct i2c_client *client)
17521832
error_handler_free:
17531833
v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);
17541834

1835+
error_power_off:
1836+
imx355_power_off(imx355->dev);
1837+
17551838
error_probe:
17561839
mutex_destroy(&imx355->mutex);
17571840

@@ -1768,7 +1851,11 @@ static void imx355_remove(struct i2c_client *client)
17681851
v4l2_ctrl_handler_free(sd->ctrl_handler);
17691852

17701853
pm_runtime_disable(imx355->dev);
1771-
pm_runtime_set_suspended(imx355->dev);
1854+
1855+
if (!pm_runtime_status_suspended(imx355->dev)) {
1856+
imx355_power_off(imx355->dev);
1857+
pm_runtime_set_suspended(imx355->dev);
1858+
}
17721859

17731860
mutex_destroy(&imx355->mutex);
17741861
}
@@ -1779,10 +1866,18 @@ static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = {
17791866
};
17801867
MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids);
17811868

1869+
static const struct of_device_id imx355_match_table[] = {
1870+
{ .compatible = "sony,imx355", },
1871+
{ /* sentinel */ }
1872+
};
1873+
MODULE_DEVICE_TABLE(of, imx355_match_table);
1874+
17821875
static struct i2c_driver imx355_i2c_driver = {
17831876
.driver = {
17841877
.name = "imx355",
17851878
.acpi_match_table = ACPI_PTR(imx355_acpi_ids),
1879+
.of_match_table = imx355_match_table,
1880+
.pm = &imx355_pm_ops,
17861881
},
17871882
.probe = imx355_probe,
17881883
.remove = imx355_remove,

0 commit comments

Comments
 (0)