diff options
Diffstat (limited to 'drivers/media/i2c/ad5820.c')
| -rw-r--r-- | drivers/media/i2c/ad5820.c | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c index 907323f0ca3b..f60271082fb5 100644 --- a/drivers/media/i2c/ad5820.c +++ b/drivers/media/i2c/ad5820.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/media/i2c/ad5820.c * @@ -11,15 +12,6 @@ * Sakari Ailus <sakari.ailus@iki.fi> * * Based on af_d88.c by Texas Instruments. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include <linux/errno.h> @@ -27,13 +19,12 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#define AD5820_NAME "ad5820" - /* Register definitions */ #define AD5820_POWER_DOWN (1 << 15) #define AD5820_DAC_SHIFT 4 @@ -55,6 +46,8 @@ struct ad5820_device { u32 focus_ramp_time; u32 focus_ramp_mode; + struct gpio_desc *enable_gpio; + struct mutex power_lock; int power_count; @@ -122,6 +115,8 @@ static int ad5820_power_off(struct ad5820_device *coil, bool standby) ret = ad5820_update_hw(coil); } + gpiod_set_value_cansleep(coil->enable_gpio, 0); + ret2 = regulator_disable(coil->vana); if (ret) return ret; @@ -136,6 +131,8 @@ static int ad5820_power_on(struct ad5820_device *coil, bool restore) if (ret < 0) return ret; + gpiod_set_value_cansleep(coil->enable_gpio, 1); + if (restore) { /* Restore the hardware settings. */ coil->standby = false; @@ -146,6 +143,7 @@ static int ad5820_power_on(struct ad5820_device *coil, bool restore) return 0; fail: + gpiod_set_value_cansleep(coil->enable_gpio, 0); coil->standby = true; regulator_disable(coil->vana); @@ -272,8 +270,7 @@ static const struct v4l2_subdev_internal_ops ad5820_internal_ops = { */ static int __maybe_unused ad5820_suspend(struct device *dev) { - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct ad5820_device *coil = to_ad5820_device(subdev); if (!coil->power_count) @@ -284,8 +281,7 @@ static int __maybe_unused ad5820_suspend(struct device *dev) static int __maybe_unused ad5820_resume(struct device *dev) { - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct ad5820_device *coil = to_ad5820_device(subdev); if (!coil->power_count) @@ -294,8 +290,7 @@ static int __maybe_unused ad5820_resume(struct device *dev) return ad5820_power_on(coil, true); } -static int ad5820_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int ad5820_probe(struct i2c_client *client) { struct ad5820_device *coil; int ret; @@ -305,38 +300,42 @@ static int ad5820_probe(struct i2c_client *client, return -ENOMEM; coil->vana = devm_regulator_get(&client->dev, "VANA"); - if (IS_ERR(coil->vana)) { - ret = PTR_ERR(coil->vana); - if (ret != -EPROBE_DEFER) - dev_err(&client->dev, "could not get regulator for vana\n"); - return ret; - } + if (IS_ERR(coil->vana)) + return dev_err_probe(&client->dev, PTR_ERR(coil->vana), + "could not get regulator for vana\n"); + + coil->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(coil->enable_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(coil->enable_gpio), + "could not get enable gpio\n"); mutex_init(&coil->power_lock); v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops); coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; coil->subdev.internal_ops = &ad5820_internal_ops; + coil->subdev.entity.function = MEDIA_ENT_F_LENS; strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name)); ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL); if (ret < 0) - goto cleanup2; + goto clean_mutex; ret = v4l2_async_register_subdev(&coil->subdev); if (ret < 0) - goto cleanup; + goto clean_entity; return ret; -cleanup2: - mutex_destroy(&coil->power_lock); -cleanup: +clean_entity: media_entity_cleanup(&coil->subdev.entity); +clean_mutex: + mutex_destroy(&coil->power_lock); return ret; } -static int ad5820_remove(struct i2c_client *client) +static void ad5820_remove(struct i2c_client *client) { struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct ad5820_device *coil = to_ad5820_device(subdev); @@ -345,21 +344,29 @@ static int ad5820_remove(struct i2c_client *client) v4l2_ctrl_handler_free(&coil->ctrls); media_entity_cleanup(&coil->subdev.entity); mutex_destroy(&coil->power_lock); - return 0; } static const struct i2c_device_id ad5820_id_table[] = { - { AD5820_NAME, 0 }, + { "ad5820" }, + { "ad5821" }, { } }; MODULE_DEVICE_TABLE(i2c, ad5820_id_table); +static const struct of_device_id ad5820_of_table[] = { + { .compatible = "adi,ad5820" }, + { .compatible = "adi,ad5821" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5820_of_table); + static SIMPLE_DEV_PM_OPS(ad5820_pm, ad5820_suspend, ad5820_resume); static struct i2c_driver ad5820_i2c_driver = { .driver = { - .name = AD5820_NAME, + .name = "ad5820", .pm = &ad5820_pm, + .of_match_table = ad5820_of_table, }, .probe = ad5820_probe, .remove = ad5820_remove, |
