cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ad5820.c (9040B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/media/i2c/ad5820.c
      4 *
      5 * AD5820 DAC driver for camera voice coil focus.
      6 *
      7 * Copyright (C) 2008 Nokia Corporation
      8 * Copyright (C) 2007 Texas Instruments
      9 * Copyright (C) 2016 Pavel Machek <pavel@ucw.cz>
     10 *
     11 * Contact: Tuukka Toivonen <tuukkat76@gmail.com>
     12 *	    Sakari Ailus <sakari.ailus@iki.fi>
     13 *
     14 * Based on af_d88.c by Texas Instruments.
     15 */
     16
     17#include <linux/errno.h>
     18#include <linux/i2c.h>
     19#include <linux/kernel.h>
     20#include <linux/module.h>
     21#include <linux/regulator/consumer.h>
     22#include <linux/gpio/consumer.h>
     23
     24#include <media/v4l2-ctrls.h>
     25#include <media/v4l2-device.h>
     26#include <media/v4l2-subdev.h>
     27
     28/* Register definitions */
     29#define AD5820_POWER_DOWN		(1 << 15)
     30#define AD5820_DAC_SHIFT		4
     31#define AD5820_RAMP_MODE_LINEAR		(0 << 3)
     32#define AD5820_RAMP_MODE_64_16		(1 << 3)
     33
     34#define CODE_TO_RAMP_US(s)	((s) == 0 ? 0 : (1 << ((s) - 1)) * 50)
     35#define RAMP_US_TO_CODE(c)	fls(((c) + ((c)>>1)) / 50)
     36
     37#define to_ad5820_device(sd)	container_of(sd, struct ad5820_device, subdev)
     38
     39struct ad5820_device {
     40	struct v4l2_subdev subdev;
     41	struct ad5820_platform_data *platform_data;
     42	struct regulator *vana;
     43
     44	struct v4l2_ctrl_handler ctrls;
     45	u32 focus_absolute;
     46	u32 focus_ramp_time;
     47	u32 focus_ramp_mode;
     48
     49	struct gpio_desc *enable_gpio;
     50
     51	struct mutex power_lock;
     52	int power_count;
     53
     54	bool standby;
     55};
     56
     57static int ad5820_write(struct ad5820_device *coil, u16 data)
     58{
     59	struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev);
     60	struct i2c_msg msg;
     61	__be16 be_data;
     62	int r;
     63
     64	if (!client->adapter)
     65		return -ENODEV;
     66
     67	be_data = cpu_to_be16(data);
     68	msg.addr  = client->addr;
     69	msg.flags = 0;
     70	msg.len   = 2;
     71	msg.buf   = (u8 *)&be_data;
     72
     73	r = i2c_transfer(client->adapter, &msg, 1);
     74	if (r < 0) {
     75		dev_err(&client->dev, "write failed, error %d\n", r);
     76		return r;
     77	}
     78
     79	return 0;
     80}
     81
     82/*
     83 * Calculate status word and write it to the device based on current
     84 * values of V4L2 controls. It is assumed that the stored V4L2 control
     85 * values are properly limited and rounded.
     86 */
     87static int ad5820_update_hw(struct ad5820_device *coil)
     88{
     89	u16 status;
     90
     91	status = RAMP_US_TO_CODE(coil->focus_ramp_time);
     92	status |= coil->focus_ramp_mode
     93		? AD5820_RAMP_MODE_64_16 : AD5820_RAMP_MODE_LINEAR;
     94	status |= coil->focus_absolute << AD5820_DAC_SHIFT;
     95
     96	if (coil->standby)
     97		status |= AD5820_POWER_DOWN;
     98
     99	return ad5820_write(coil, status);
    100}
    101
    102/*
    103 * Power handling
    104 */
    105static int ad5820_power_off(struct ad5820_device *coil, bool standby)
    106{
    107	int ret = 0, ret2;
    108
    109	/*
    110	 * Go to standby first as real power off my be denied by the hardware
    111	 * (single power line control for both coil and sensor).
    112	 */
    113	if (standby) {
    114		coil->standby = true;
    115		ret = ad5820_update_hw(coil);
    116	}
    117
    118	gpiod_set_value_cansleep(coil->enable_gpio, 0);
    119
    120	ret2 = regulator_disable(coil->vana);
    121	if (ret)
    122		return ret;
    123	return ret2;
    124}
    125
    126static int ad5820_power_on(struct ad5820_device *coil, bool restore)
    127{
    128	int ret;
    129
    130	ret = regulator_enable(coil->vana);
    131	if (ret < 0)
    132		return ret;
    133
    134	gpiod_set_value_cansleep(coil->enable_gpio, 1);
    135
    136	if (restore) {
    137		/* Restore the hardware settings. */
    138		coil->standby = false;
    139		ret = ad5820_update_hw(coil);
    140		if (ret)
    141			goto fail;
    142	}
    143	return 0;
    144
    145fail:
    146	gpiod_set_value_cansleep(coil->enable_gpio, 0);
    147	coil->standby = true;
    148	regulator_disable(coil->vana);
    149
    150	return ret;
    151}
    152
    153/*
    154 * V4L2 controls
    155 */
    156static int ad5820_set_ctrl(struct v4l2_ctrl *ctrl)
    157{
    158	struct ad5820_device *coil =
    159		container_of(ctrl->handler, struct ad5820_device, ctrls);
    160
    161	switch (ctrl->id) {
    162	case V4L2_CID_FOCUS_ABSOLUTE:
    163		coil->focus_absolute = ctrl->val;
    164		return ad5820_update_hw(coil);
    165	}
    166
    167	return 0;
    168}
    169
    170static const struct v4l2_ctrl_ops ad5820_ctrl_ops = {
    171	.s_ctrl = ad5820_set_ctrl,
    172};
    173
    174
    175static int ad5820_init_controls(struct ad5820_device *coil)
    176{
    177	v4l2_ctrl_handler_init(&coil->ctrls, 1);
    178
    179	/*
    180	 * V4L2_CID_FOCUS_ABSOLUTE
    181	 *
    182	 * Minimum current is 0 mA, maximum is 100 mA. Thus, 1 code is
    183	 * equivalent to 100/1023 = 0.0978 mA. Nevertheless, we do not use [mA]
    184	 * for focus position, because it is meaningless for user. Meaningful
    185	 * would be to use focus distance or even its inverse, but since the
    186	 * driver doesn't have sufficiently knowledge to do the conversion, we
    187	 * will just use abstract codes here. In any case, smaller value = focus
    188	 * position farther from camera. The default zero value means focus at
    189	 * infinity, and also least current consumption.
    190	 */
    191	v4l2_ctrl_new_std(&coil->ctrls, &ad5820_ctrl_ops,
    192			  V4L2_CID_FOCUS_ABSOLUTE, 0, 1023, 1, 0);
    193
    194	if (coil->ctrls.error)
    195		return coil->ctrls.error;
    196
    197	coil->focus_absolute = 0;
    198	coil->focus_ramp_time = 0;
    199	coil->focus_ramp_mode = 0;
    200
    201	coil->subdev.ctrl_handler = &coil->ctrls;
    202
    203	return 0;
    204}
    205
    206/*
    207 * V4L2 subdev operations
    208 */
    209static int ad5820_registered(struct v4l2_subdev *subdev)
    210{
    211	struct ad5820_device *coil = to_ad5820_device(subdev);
    212
    213	return ad5820_init_controls(coil);
    214}
    215
    216static int
    217ad5820_set_power(struct v4l2_subdev *subdev, int on)
    218{
    219	struct ad5820_device *coil = to_ad5820_device(subdev);
    220	int ret = 0;
    221
    222	mutex_lock(&coil->power_lock);
    223
    224	/*
    225	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
    226	 * update the power state.
    227	 */
    228	if (coil->power_count == !on) {
    229		ret = on ? ad5820_power_on(coil, true) :
    230			ad5820_power_off(coil, true);
    231		if (ret < 0)
    232			goto done;
    233	}
    234
    235	/* Update the power count. */
    236	coil->power_count += on ? 1 : -1;
    237	WARN_ON(coil->power_count < 0);
    238
    239done:
    240	mutex_unlock(&coil->power_lock);
    241	return ret;
    242}
    243
    244static int ad5820_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
    245{
    246	return ad5820_set_power(sd, 1);
    247}
    248
    249static int ad5820_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
    250{
    251	return ad5820_set_power(sd, 0);
    252}
    253
    254static const struct v4l2_subdev_core_ops ad5820_core_ops = {
    255	.s_power = ad5820_set_power,
    256};
    257
    258static const struct v4l2_subdev_ops ad5820_ops = {
    259	.core = &ad5820_core_ops,
    260};
    261
    262static const struct v4l2_subdev_internal_ops ad5820_internal_ops = {
    263	.registered = ad5820_registered,
    264	.open = ad5820_open,
    265	.close = ad5820_close,
    266};
    267
    268/*
    269 * I2C driver
    270 */
    271static int __maybe_unused ad5820_suspend(struct device *dev)
    272{
    273	struct v4l2_subdev *subdev = dev_get_drvdata(dev);
    274	struct ad5820_device *coil = to_ad5820_device(subdev);
    275
    276	if (!coil->power_count)
    277		return 0;
    278
    279	return ad5820_power_off(coil, false);
    280}
    281
    282static int __maybe_unused ad5820_resume(struct device *dev)
    283{
    284	struct v4l2_subdev *subdev = dev_get_drvdata(dev);
    285	struct ad5820_device *coil = to_ad5820_device(subdev);
    286
    287	if (!coil->power_count)
    288		return 0;
    289
    290	return ad5820_power_on(coil, true);
    291}
    292
    293static int ad5820_probe(struct i2c_client *client,
    294			const struct i2c_device_id *devid)
    295{
    296	struct ad5820_device *coil;
    297	int ret;
    298
    299	coil = devm_kzalloc(&client->dev, sizeof(*coil), GFP_KERNEL);
    300	if (!coil)
    301		return -ENOMEM;
    302
    303	coil->vana = devm_regulator_get(&client->dev, "VANA");
    304	if (IS_ERR(coil->vana)) {
    305		ret = PTR_ERR(coil->vana);
    306		if (ret != -EPROBE_DEFER)
    307			dev_err(&client->dev, "could not get regulator for vana\n");
    308		return ret;
    309	}
    310
    311	coil->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
    312						    GPIOD_OUT_LOW);
    313	if (IS_ERR(coil->enable_gpio)) {
    314		ret = PTR_ERR(coil->enable_gpio);
    315		if (ret != -EPROBE_DEFER)
    316			dev_err(&client->dev, "could not get enable gpio\n");
    317		return ret;
    318	}
    319
    320	mutex_init(&coil->power_lock);
    321
    322	v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops);
    323	coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
    324	coil->subdev.internal_ops = &ad5820_internal_ops;
    325	coil->subdev.entity.function = MEDIA_ENT_F_LENS;
    326	strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name));
    327
    328	ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL);
    329	if (ret < 0)
    330		goto cleanup2;
    331
    332	ret = v4l2_async_register_subdev(&coil->subdev);
    333	if (ret < 0)
    334		goto cleanup;
    335
    336	return ret;
    337
    338cleanup2:
    339	mutex_destroy(&coil->power_lock);
    340cleanup:
    341	media_entity_cleanup(&coil->subdev.entity);
    342	return ret;
    343}
    344
    345static int ad5820_remove(struct i2c_client *client)
    346{
    347	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
    348	struct ad5820_device *coil = to_ad5820_device(subdev);
    349
    350	v4l2_async_unregister_subdev(&coil->subdev);
    351	v4l2_ctrl_handler_free(&coil->ctrls);
    352	media_entity_cleanup(&coil->subdev.entity);
    353	mutex_destroy(&coil->power_lock);
    354	return 0;
    355}
    356
    357static const struct i2c_device_id ad5820_id_table[] = {
    358	{ "ad5820", 0 },
    359	{ "ad5821", 0 },
    360	{ "ad5823", 0 },
    361	{ }
    362};
    363MODULE_DEVICE_TABLE(i2c, ad5820_id_table);
    364
    365static const struct of_device_id ad5820_of_table[] = {
    366	{ .compatible = "adi,ad5820" },
    367	{ .compatible = "adi,ad5821" },
    368	{ .compatible = "adi,ad5823" },
    369	{ }
    370};
    371MODULE_DEVICE_TABLE(of, ad5820_of_table);
    372
    373static SIMPLE_DEV_PM_OPS(ad5820_pm, ad5820_suspend, ad5820_resume);
    374
    375static struct i2c_driver ad5820_i2c_driver = {
    376	.driver		= {
    377		.name	= "ad5820",
    378		.pm	= &ad5820_pm,
    379		.of_match_table = ad5820_of_table,
    380	},
    381	.probe		= ad5820_probe,
    382	.remove		= ad5820_remove,
    383	.id_table	= ad5820_id_table,
    384};
    385
    386module_i2c_driver(ad5820_i2c_driver);
    387
    388MODULE_AUTHOR("Tuukka Toivonen");
    389MODULE_DESCRIPTION("AD5820 camera lens driver");
    390MODULE_LICENSE("GPL");