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

lm3560.c (12159B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/media/i2c/lm3560.c
      4 * General device driver for TI lm3559, lm3560, FLASH LED Driver
      5 *
      6 * Copyright (C) 2013 Texas Instruments
      7 *
      8 * Contact: Daniel Jeong <gshark.jeong@gmail.com>
      9 *			Ldd-Mlp <ldd-mlp@list.ti.com>
     10 */
     11
     12#include <linux/delay.h>
     13#include <linux/module.h>
     14#include <linux/i2c.h>
     15#include <linux/slab.h>
     16#include <linux/mutex.h>
     17#include <linux/regmap.h>
     18#include <linux/videodev2.h>
     19#include <media/i2c/lm3560.h>
     20#include <media/v4l2-ctrls.h>
     21#include <media/v4l2-device.h>
     22
     23/* registers definitions */
     24#define REG_ENABLE		0x10
     25#define REG_TORCH_BR	0xa0
     26#define REG_FLASH_BR	0xb0
     27#define REG_FLASH_TOUT	0xc0
     28#define REG_FLAG		0xd0
     29#define REG_CONFIG1		0xe0
     30
     31/* fault mask */
     32#define FAULT_TIMEOUT	(1<<0)
     33#define FAULT_OVERTEMP	(1<<1)
     34#define FAULT_SHORT_CIRCUIT	(1<<2)
     35
     36enum led_enable {
     37	MODE_SHDN = 0x0,
     38	MODE_TORCH = 0x2,
     39	MODE_FLASH = 0x3,
     40};
     41
     42/**
     43 * struct lm3560_flash
     44 *
     45 * @dev: pointer to &struct device
     46 * @pdata: platform data
     47 * @regmap: reg. map for i2c
     48 * @lock: muxtex for serial access.
     49 * @led_mode: V4L2 LED mode
     50 * @ctrls_led: V4L2 controls
     51 * @subdev_led: V4L2 subdev
     52 */
     53struct lm3560_flash {
     54	struct device *dev;
     55	struct lm3560_platform_data *pdata;
     56	struct regmap *regmap;
     57	struct mutex lock;
     58
     59	enum v4l2_flash_led_mode led_mode;
     60	struct v4l2_ctrl_handler ctrls_led[LM3560_LED_MAX];
     61	struct v4l2_subdev subdev_led[LM3560_LED_MAX];
     62};
     63
     64#define to_lm3560_flash(_ctrl, _no)	\
     65	container_of(_ctrl->handler, struct lm3560_flash, ctrls_led[_no])
     66
     67/* enable mode control */
     68static int lm3560_mode_ctrl(struct lm3560_flash *flash)
     69{
     70	int rval = -EINVAL;
     71
     72	switch (flash->led_mode) {
     73	case V4L2_FLASH_LED_MODE_NONE:
     74		rval = regmap_update_bits(flash->regmap,
     75					  REG_ENABLE, 0x03, MODE_SHDN);
     76		break;
     77	case V4L2_FLASH_LED_MODE_TORCH:
     78		rval = regmap_update_bits(flash->regmap,
     79					  REG_ENABLE, 0x03, MODE_TORCH);
     80		break;
     81	case V4L2_FLASH_LED_MODE_FLASH:
     82		rval = regmap_update_bits(flash->regmap,
     83					  REG_ENABLE, 0x03, MODE_FLASH);
     84		break;
     85	}
     86	return rval;
     87}
     88
     89/* led1/2 enable/disable */
     90static int lm3560_enable_ctrl(struct lm3560_flash *flash,
     91			      enum lm3560_led_id led_no, bool on)
     92{
     93	int rval;
     94
     95	if (led_no == LM3560_LED0) {
     96		if (on)
     97			rval = regmap_update_bits(flash->regmap,
     98						  REG_ENABLE, 0x08, 0x08);
     99		else
    100			rval = regmap_update_bits(flash->regmap,
    101						  REG_ENABLE, 0x08, 0x00);
    102	} else {
    103		if (on)
    104			rval = regmap_update_bits(flash->regmap,
    105						  REG_ENABLE, 0x10, 0x10);
    106		else
    107			rval = regmap_update_bits(flash->regmap,
    108						  REG_ENABLE, 0x10, 0x00);
    109	}
    110	return rval;
    111}
    112
    113/* torch1/2 brightness control */
    114static int lm3560_torch_brt_ctrl(struct lm3560_flash *flash,
    115				 enum lm3560_led_id led_no, unsigned int brt)
    116{
    117	int rval;
    118	u8 br_bits;
    119
    120	if (brt < LM3560_TORCH_BRT_MIN)
    121		return lm3560_enable_ctrl(flash, led_no, false);
    122	else
    123		rval = lm3560_enable_ctrl(flash, led_no, true);
    124
    125	br_bits = LM3560_TORCH_BRT_uA_TO_REG(brt);
    126	if (led_no == LM3560_LED0)
    127		rval = regmap_update_bits(flash->regmap,
    128					  REG_TORCH_BR, 0x07, br_bits);
    129	else
    130		rval = regmap_update_bits(flash->regmap,
    131					  REG_TORCH_BR, 0x38, br_bits << 3);
    132
    133	return rval;
    134}
    135
    136/* flash1/2 brightness control */
    137static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
    138				 enum lm3560_led_id led_no, unsigned int brt)
    139{
    140	int rval;
    141	u8 br_bits;
    142
    143	if (brt < LM3560_FLASH_BRT_MIN)
    144		return lm3560_enable_ctrl(flash, led_no, false);
    145	else
    146		rval = lm3560_enable_ctrl(flash, led_no, true);
    147
    148	br_bits = LM3560_FLASH_BRT_uA_TO_REG(brt);
    149	if (led_no == LM3560_LED0)
    150		rval = regmap_update_bits(flash->regmap,
    151					  REG_FLASH_BR, 0x0f, br_bits);
    152	else
    153		rval = regmap_update_bits(flash->regmap,
    154					  REG_FLASH_BR, 0xf0, br_bits << 4);
    155
    156	return rval;
    157}
    158
    159/* v4l2 controls  */
    160static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
    161{
    162	struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
    163	int rval = -EINVAL;
    164
    165	mutex_lock(&flash->lock);
    166
    167	if (ctrl->id == V4L2_CID_FLASH_FAULT) {
    168		s32 fault = 0;
    169		unsigned int reg_val;
    170		rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
    171		if (rval < 0)
    172			goto out;
    173		if (reg_val & FAULT_SHORT_CIRCUIT)
    174			fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
    175		if (reg_val & FAULT_OVERTEMP)
    176			fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
    177		if (reg_val & FAULT_TIMEOUT)
    178			fault |= V4L2_FLASH_FAULT_TIMEOUT;
    179		ctrl->cur.val = fault;
    180	}
    181
    182out:
    183	mutex_unlock(&flash->lock);
    184	return rval;
    185}
    186
    187static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
    188{
    189	struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
    190	u8 tout_bits;
    191	int rval = -EINVAL;
    192
    193	mutex_lock(&flash->lock);
    194
    195	switch (ctrl->id) {
    196	case V4L2_CID_FLASH_LED_MODE:
    197		flash->led_mode = ctrl->val;
    198		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
    199			rval = lm3560_mode_ctrl(flash);
    200		break;
    201
    202	case V4L2_CID_FLASH_STROBE_SOURCE:
    203		rval = regmap_update_bits(flash->regmap,
    204					  REG_CONFIG1, 0x04, (ctrl->val) << 2);
    205		if (rval < 0)
    206			goto err_out;
    207		break;
    208
    209	case V4L2_CID_FLASH_STROBE:
    210		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
    211			rval = -EBUSY;
    212			goto err_out;
    213		}
    214		flash->led_mode = V4L2_FLASH_LED_MODE_FLASH;
    215		rval = lm3560_mode_ctrl(flash);
    216		break;
    217
    218	case V4L2_CID_FLASH_STROBE_STOP:
    219		if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
    220			rval = -EBUSY;
    221			goto err_out;
    222		}
    223		flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
    224		rval = lm3560_mode_ctrl(flash);
    225		break;
    226
    227	case V4L2_CID_FLASH_TIMEOUT:
    228		tout_bits = LM3560_FLASH_TOUT_ms_TO_REG(ctrl->val);
    229		rval = regmap_update_bits(flash->regmap,
    230					  REG_FLASH_TOUT, 0x1f, tout_bits);
    231		break;
    232
    233	case V4L2_CID_FLASH_INTENSITY:
    234		rval = lm3560_flash_brt_ctrl(flash, led_no, ctrl->val);
    235		break;
    236
    237	case V4L2_CID_FLASH_TORCH_INTENSITY:
    238		rval = lm3560_torch_brt_ctrl(flash, led_no, ctrl->val);
    239		break;
    240	}
    241
    242err_out:
    243	mutex_unlock(&flash->lock);
    244	return rval;
    245}
    246
    247static int lm3560_led1_get_ctrl(struct v4l2_ctrl *ctrl)
    248{
    249	return lm3560_get_ctrl(ctrl, LM3560_LED1);
    250}
    251
    252static int lm3560_led1_set_ctrl(struct v4l2_ctrl *ctrl)
    253{
    254	return lm3560_set_ctrl(ctrl, LM3560_LED1);
    255}
    256
    257static int lm3560_led0_get_ctrl(struct v4l2_ctrl *ctrl)
    258{
    259	return lm3560_get_ctrl(ctrl, LM3560_LED0);
    260}
    261
    262static int lm3560_led0_set_ctrl(struct v4l2_ctrl *ctrl)
    263{
    264	return lm3560_set_ctrl(ctrl, LM3560_LED0);
    265}
    266
    267static const struct v4l2_ctrl_ops lm3560_led_ctrl_ops[LM3560_LED_MAX] = {
    268	[LM3560_LED0] = {
    269			 .g_volatile_ctrl = lm3560_led0_get_ctrl,
    270			 .s_ctrl = lm3560_led0_set_ctrl,
    271			 },
    272	[LM3560_LED1] = {
    273			 .g_volatile_ctrl = lm3560_led1_get_ctrl,
    274			 .s_ctrl = lm3560_led1_set_ctrl,
    275			 }
    276};
    277
    278static int lm3560_init_controls(struct lm3560_flash *flash,
    279				enum lm3560_led_id led_no)
    280{
    281	struct v4l2_ctrl *fault;
    282	u32 max_flash_brt = flash->pdata->max_flash_brt[led_no];
    283	u32 max_torch_brt = flash->pdata->max_torch_brt[led_no];
    284	struct v4l2_ctrl_handler *hdl = &flash->ctrls_led[led_no];
    285	const struct v4l2_ctrl_ops *ops = &lm3560_led_ctrl_ops[led_no];
    286
    287	v4l2_ctrl_handler_init(hdl, 8);
    288
    289	/* flash mode */
    290	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE,
    291			       V4L2_FLASH_LED_MODE_TORCH, ~0x7,
    292			       V4L2_FLASH_LED_MODE_NONE);
    293	flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
    294
    295	/* flash source */
    296	v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_STROBE_SOURCE,
    297			       0x1, ~0x3, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
    298
    299	/* flash strobe */
    300	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
    301
    302	/* flash strobe stop */
    303	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
    304
    305	/* flash strobe timeout */
    306	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TIMEOUT,
    307			  LM3560_FLASH_TOUT_MIN,
    308			  flash->pdata->max_flash_timeout,
    309			  LM3560_FLASH_TOUT_STEP,
    310			  flash->pdata->max_flash_timeout);
    311
    312	/* flash brt */
    313	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_INTENSITY,
    314			  LM3560_FLASH_BRT_MIN, max_flash_brt,
    315			  LM3560_FLASH_BRT_STEP, max_flash_brt);
    316
    317	/* torch brt */
    318	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_TORCH_INTENSITY,
    319			  LM3560_TORCH_BRT_MIN, max_torch_brt,
    320			  LM3560_TORCH_BRT_STEP, max_torch_brt);
    321
    322	/* fault */
    323	fault = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FLASH_FAULT, 0,
    324				  V4L2_FLASH_FAULT_OVER_VOLTAGE
    325				  | V4L2_FLASH_FAULT_OVER_TEMPERATURE
    326				  | V4L2_FLASH_FAULT_SHORT_CIRCUIT
    327				  | V4L2_FLASH_FAULT_TIMEOUT, 0, 0);
    328	if (fault != NULL)
    329		fault->flags |= V4L2_CTRL_FLAG_VOLATILE;
    330
    331	if (hdl->error)
    332		return hdl->error;
    333
    334	flash->subdev_led[led_no].ctrl_handler = hdl;
    335	return 0;
    336}
    337
    338/* initialize device */
    339static const struct v4l2_subdev_ops lm3560_ops = {
    340	.core = NULL,
    341};
    342
    343static const struct regmap_config lm3560_regmap = {
    344	.reg_bits = 8,
    345	.val_bits = 8,
    346	.max_register = 0xFF,
    347};
    348
    349static int lm3560_subdev_init(struct lm3560_flash *flash,
    350			      enum lm3560_led_id led_no, char *led_name)
    351{
    352	struct i2c_client *client = to_i2c_client(flash->dev);
    353	int rval;
    354
    355	v4l2_i2c_subdev_init(&flash->subdev_led[led_no], client, &lm3560_ops);
    356	flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
    357	strscpy(flash->subdev_led[led_no].name, led_name,
    358		sizeof(flash->subdev_led[led_no].name));
    359	rval = lm3560_init_controls(flash, led_no);
    360	if (rval)
    361		goto err_out;
    362	rval = media_entity_pads_init(&flash->subdev_led[led_no].entity, 0, NULL);
    363	if (rval < 0)
    364		goto err_out;
    365	flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH;
    366
    367	return rval;
    368
    369err_out:
    370	v4l2_ctrl_handler_free(&flash->ctrls_led[led_no]);
    371	return rval;
    372}
    373
    374static int lm3560_init_device(struct lm3560_flash *flash)
    375{
    376	int rval;
    377	unsigned int reg_val;
    378
    379	/* set peak current */
    380	rval = regmap_update_bits(flash->regmap,
    381				  REG_FLASH_TOUT, 0x60, flash->pdata->peak);
    382	if (rval < 0)
    383		return rval;
    384	/* output disable */
    385	flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
    386	rval = lm3560_mode_ctrl(flash);
    387	if (rval < 0)
    388		return rval;
    389	/* reset faults */
    390	rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
    391	return rval;
    392}
    393
    394static int lm3560_probe(struct i2c_client *client,
    395			const struct i2c_device_id *devid)
    396{
    397	struct lm3560_flash *flash;
    398	struct lm3560_platform_data *pdata = dev_get_platdata(&client->dev);
    399	int rval;
    400
    401	flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
    402	if (flash == NULL)
    403		return -ENOMEM;
    404
    405	flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap);
    406	if (IS_ERR(flash->regmap)) {
    407		rval = PTR_ERR(flash->regmap);
    408		return rval;
    409	}
    410
    411	/* if there is no platform data, use chip default value */
    412	if (pdata == NULL) {
    413		pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
    414		if (pdata == NULL)
    415			return -ENODEV;
    416		pdata->peak = LM3560_PEAK_3600mA;
    417		pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;
    418		/* led 1 */
    419		pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX;
    420		pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX;
    421		/* led 2 */
    422		pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX;
    423		pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX;
    424	}
    425	flash->pdata = pdata;
    426	flash->dev = &client->dev;
    427	mutex_init(&flash->lock);
    428
    429	rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");
    430	if (rval < 0)
    431		return rval;
    432
    433	rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");
    434	if (rval < 0)
    435		return rval;
    436
    437	rval = lm3560_init_device(flash);
    438	if (rval < 0)
    439		return rval;
    440
    441	i2c_set_clientdata(client, flash);
    442
    443	return 0;
    444}
    445
    446static int lm3560_remove(struct i2c_client *client)
    447{
    448	struct lm3560_flash *flash = i2c_get_clientdata(client);
    449	unsigned int i;
    450
    451	for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {
    452		v4l2_device_unregister_subdev(&flash->subdev_led[i]);
    453		v4l2_ctrl_handler_free(&flash->ctrls_led[i]);
    454		media_entity_cleanup(&flash->subdev_led[i].entity);
    455	}
    456
    457	return 0;
    458}
    459
    460static const struct i2c_device_id lm3560_id_table[] = {
    461	{LM3559_NAME, 0},
    462	{LM3560_NAME, 0},
    463	{}
    464};
    465
    466MODULE_DEVICE_TABLE(i2c, lm3560_id_table);
    467
    468static struct i2c_driver lm3560_i2c_driver = {
    469	.driver = {
    470		   .name = LM3560_NAME,
    471		   .pm = NULL,
    472		   },
    473	.probe = lm3560_probe,
    474	.remove = lm3560_remove,
    475	.id_table = lm3560_id_table,
    476};
    477
    478module_i2c_driver(lm3560_i2c_driver);
    479
    480MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
    481MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
    482MODULE_DESCRIPTION("Texas Instruments LM3560 LED flash driver");
    483MODULE_LICENSE("GPL");