diff options
Diffstat (limited to 'drivers/media/i2c/hi556.c')
-rw-r--r-- | drivers/media/i2c/hi556.c | 73 |
1 files changed, 42 insertions, 31 deletions
diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index aed258211b8a..076c19fcf99c 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -624,6 +624,12 @@ static const struct hi556_mode supported_modes[] = { }, }; +static const char * const hi556_supply_names[] = { + "dovdd", /* Digital I/O power */ + "avdd", /* Analog power */ + "dvdd", /* Digital core power */ +}; + struct hi556 { struct v4l2_subdev sd; struct media_pad pad; @@ -639,7 +645,7 @@ struct hi556 { /* GPIOs, clocks, etc. */ struct gpio_desc *reset_gpio; struct clk *clk; - struct regulator *avdd; + struct regulator_bulk_data supplies[ARRAY_SIZE(hi556_supply_names)]; /* Current mode */ const struct hi556_mode *cur_mode; @@ -756,21 +762,23 @@ static int hi556_test_pattern(struct hi556 *hi556, u32 pattern) int ret; u32 val; - if (pattern) { - ret = hi556_read_reg(hi556, HI556_REG_ISP, - HI556_REG_VALUE_08BIT, &val); - if (ret) - return ret; + ret = hi556_read_reg(hi556, HI556_REG_ISP, + HI556_REG_VALUE_08BIT, &val); + if (ret) + return ret; - ret = hi556_write_reg(hi556, HI556_REG_ISP, - HI556_REG_VALUE_08BIT, - val | HI556_REG_ISP_TPG_EN); - if (ret) - return ret; - } + val = pattern ? (val | HI556_REG_ISP_TPG_EN) : + (val & ~HI556_REG_ISP_TPG_EN); + + ret = hi556_write_reg(hi556, HI556_REG_ISP, + HI556_REG_VALUE_08BIT, val); + if (ret) + return ret; + + val = pattern ? BIT(pattern - 1) : 0; return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN, - HI556_REG_VALUE_08BIT, pattern); + HI556_REG_VALUE_08BIT, val); } static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) @@ -1289,17 +1297,10 @@ static int hi556_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hi556 *hi556 = to_hi556(sd); - int ret; gpiod_set_value_cansleep(hi556->reset_gpio, 1); - - ret = regulator_disable(hi556->avdd); - if (ret) { - dev_err(dev, "failed to disable avdd: %d\n", ret); - gpiod_set_value_cansleep(hi556->reset_gpio, 0); - return ret; - } - + regulator_bulk_disable(ARRAY_SIZE(hi556_supply_names), + hi556->supplies); clk_disable_unprepare(hi556->clk); return 0; } @@ -1314,14 +1315,20 @@ static int hi556_resume(struct device *dev) if (ret) return ret; - ret = regulator_enable(hi556->avdd); + ret = regulator_bulk_enable(ARRAY_SIZE(hi556_supply_names), + hi556->supplies); if (ret) { - dev_err(dev, "failed to enable avdd: %d\n", ret); + dev_err(dev, "failed to enable regulators: %d", ret); clk_disable_unprepare(hi556->clk); return ret; } - gpiod_set_value_cansleep(hi556->reset_gpio, 0); + if (hi556->reset_gpio) { + /* Assert reset for at least 2ms on back to back off-on */ + usleep_range(2000, 2200); + gpiod_set_value_cansleep(hi556->reset_gpio, 0); + } + usleep_range(5000, 5500); return 0; } @@ -1330,7 +1337,7 @@ static int hi556_probe(struct i2c_client *client) { struct hi556 *hi556; bool full_power; - int ret; + int i, ret; ret = hi556_check_hwcfg(&client->dev); if (ret) @@ -1353,11 +1360,15 @@ static int hi556_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), "failed to get clock\n"); - /* The regulator core will provide a "dummy" regulator if necessary */ - hi556->avdd = devm_regulator_get(&client->dev, "avdd"); - if (IS_ERR(hi556->avdd)) - return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd), - "failed to get avdd regulator\n"); + for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++) + hi556->supplies[i].supply = hi556_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(hi556_supply_names), + hi556->supplies); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to get regulators\n"); full_power = acpi_dev_state_d0(&client->dev); if (full_power) { |