brintos

brintos / linux-shallow public Read only

0
0
Text · 11.8 KiB · f4cc844 Raw
481 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * drivers/media/i2c/lm3560.c4 * General device driver for TI lm3559, lm3560, FLASH LED Driver5 *6 * Copyright (C) 2013 Texas Instruments7 *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		0x1025#define REG_TORCH_BR	0xa026#define REG_FLASH_BR	0xb027#define REG_FLASH_TOUT	0xc028#define REG_FLAG		0xd029#define REG_CONFIG1		0xe030 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_flash44 *45 * @dev: pointer to &struct device46 * @pdata: platform data47 * @regmap: reg. map for i2c48 * @lock: muxtex for serial access.49 * @led_mode: V4L2 LED mode50 * @ctrls_led: V4L2 controls51 * @subdev_led: V4L2 subdev52 */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		else100			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		else107			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	else123		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	else130		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	else146		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	else153		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_VOLTAGE325				  | V4L2_FLASH_FAULT_OVER_TEMPERATURE326				  | V4L2_FLASH_FAULT_SHORT_CIRCUIT327				  | 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{396	struct lm3560_flash *flash;397	struct lm3560_platform_data *pdata = dev_get_platdata(&client->dev);398	int rval;399 400	flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);401	if (flash == NULL)402		return -ENOMEM;403 404	flash->regmap = devm_regmap_init_i2c(client, &lm3560_regmap);405	if (IS_ERR(flash->regmap)) {406		rval = PTR_ERR(flash->regmap);407		return rval;408	}409 410	/* if there is no platform data, use chip default value */411	if (pdata == NULL) {412		pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);413		if (pdata == NULL)414			return -ENODEV;415		pdata->peak = LM3560_PEAK_3600mA;416		pdata->max_flash_timeout = LM3560_FLASH_TOUT_MAX;417		/* led 1 */418		pdata->max_flash_brt[LM3560_LED0] = LM3560_FLASH_BRT_MAX;419		pdata->max_torch_brt[LM3560_LED0] = LM3560_TORCH_BRT_MAX;420		/* led 2 */421		pdata->max_flash_brt[LM3560_LED1] = LM3560_FLASH_BRT_MAX;422		pdata->max_torch_brt[LM3560_LED1] = LM3560_TORCH_BRT_MAX;423	}424	flash->pdata = pdata;425	flash->dev = &client->dev;426	mutex_init(&flash->lock);427 428	rval = lm3560_subdev_init(flash, LM3560_LED0, "lm3560-led0");429	if (rval < 0)430		return rval;431 432	rval = lm3560_subdev_init(flash, LM3560_LED1, "lm3560-led1");433	if (rval < 0)434		return rval;435 436	rval = lm3560_init_device(flash);437	if (rval < 0)438		return rval;439 440	i2c_set_clientdata(client, flash);441 442	return 0;443}444 445static void lm3560_remove(struct i2c_client *client)446{447	struct lm3560_flash *flash = i2c_get_clientdata(client);448	unsigned int i;449 450	for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {451		v4l2_device_unregister_subdev(&flash->subdev_led[i]);452		v4l2_ctrl_handler_free(&flash->ctrls_led[i]);453		media_entity_cleanup(&flash->subdev_led[i].entity);454	}455}456 457static const struct i2c_device_id lm3560_id_table[] = {458	{ LM3559_NAME },459	{ LM3560_NAME },460	{}461};462 463MODULE_DEVICE_TABLE(i2c, lm3560_id_table);464 465static struct i2c_driver lm3560_i2c_driver = {466	.driver = {467		   .name = LM3560_NAME,468		   .pm = NULL,469		   },470	.probe = lm3560_probe,471	.remove = lm3560_remove,472	.id_table = lm3560_id_table,473};474 475module_i2c_driver(lm3560_i2c_driver);476 477MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");478MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");479MODULE_DESCRIPTION("Texas Instruments LM3560 LED flash driver");480MODULE_LICENSE("GPL");481