brintos

brintos / linux-shallow public Read only

0
0
Text · 27.0 KiB · 90d78b3 Raw
1058 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * LED Flash class driver for the flash cell of max77693 mfd.4 *5 *	Copyright (C) 2015, Samsung Electronics Co., Ltd.6 *7 *	Authors: Jacek Anaszewski <j.anaszewski@samsung.com>8 *		 Andrzej Hajda <a.hajda@samsung.com>9 */10 11#include <linux/led-class-flash.h>12#include <linux/mfd/max77693.h>13#include <linux/mfd/max77693-common.h>14#include <linux/mfd/max77693-private.h>15#include <linux/module.h>16#include <linux/mutex.h>17#include <linux/platform_device.h>18#include <linux/regmap.h>19#include <linux/slab.h>20#include <media/v4l2-flash-led-class.h>21 22#define MODE_OFF		023#define MODE_FLASH(a)		(1 << (a))24#define MODE_TORCH(a)		(1 << (2 + (a)))25#define MODE_FLASH_EXTERNAL(a)	(1 << (4 + (a)))26 27#define MODE_FLASH_MASK		(MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \28				 MODE_FLASH_EXTERNAL(FLED1) | \29				 MODE_FLASH_EXTERNAL(FLED2))30#define MODE_TORCH_MASK		(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))31 32#define FLED1_IOUT		(1 << 0)33#define FLED2_IOUT		(1 << 1)34 35enum max77693_fled {36	FLED1,37	FLED2,38};39 40enum max77693_led_mode {41	FLASH,42	TORCH,43};44 45struct max77693_led_config_data {46	const char *label[2];47	u32 iout_torch_max[2];48	u32 iout_flash_max[2];49	u32 flash_timeout_max[2];50	u32 num_leds;51	u32 boost_mode;52	u32 boost_vout;53	u32 low_vsys;54};55 56struct max77693_sub_led {57	/* corresponding FLED output identifier */58	int fled_id;59	/* corresponding LED Flash class device */60	struct led_classdev_flash fled_cdev;61	/* V4L2 Flash device */62	struct v4l2_flash *v4l2_flash;63 64	/* brightness cache */65	unsigned int torch_brightness;66	/* flash timeout cache */67	unsigned int flash_timeout;68	/* flash faults that may have occurred */69	u32 flash_faults;70};71 72struct max77693_led_device {73	/* parent mfd regmap */74	struct regmap *regmap;75	/* platform device data */76	struct platform_device *pdev;77	/* secures access to the device */78	struct mutex lock;79 80	/* sub led data */81	struct max77693_sub_led sub_leds[2];82 83	/* maximum torch current values for FLED outputs */84	u32 iout_torch_max[2];85	/* maximum flash current values for FLED outputs */86	u32 iout_flash_max[2];87 88	/* current flash timeout cache */89	unsigned int current_flash_timeout;90	/* ITORCH register cache */91	u8 torch_iout_reg;92	/* mode of fled outputs */93	unsigned int mode_flags;94	/* recently strobed fled */95	int strobing_sub_led_id;96	/* bitmask of FLED outputs use state (bit 0. - FLED1, bit 1. - FLED2) */97	u8 fled_mask;98	/* FLED modes that can be set */99	u8 allowed_modes;100 101	/* arrangement of current outputs */102	bool iout_joint;103};104 105static u8 max77693_led_iout_to_reg(u32 ua)106{107	if (ua < FLASH_IOUT_MIN)108		ua = FLASH_IOUT_MIN;109	return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP;110}111 112static u8 max77693_flash_timeout_to_reg(u32 us)113{114	return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP;115}116 117static inline struct max77693_sub_led *flcdev_to_sub_led(118					struct led_classdev_flash *fled_cdev)119{120	return container_of(fled_cdev, struct max77693_sub_led, fled_cdev);121}122 123static inline struct max77693_led_device *sub_led_to_led(124					struct max77693_sub_led *sub_led)125{126	return container_of(sub_led, struct max77693_led_device,127				sub_leds[sub_led->fled_id]);128}129 130static inline u8 max77693_led_vsys_to_reg(u32 mv)131{132	return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2;133}134 135static inline u8 max77693_led_vout_to_reg(u32 mv)136{137	return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN;138}139 140static inline bool max77693_fled_used(struct max77693_led_device *led,141					 int fled_id)142{143	u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT;144 145	return led->fled_mask & fled_bit;146}147 148static int max77693_set_mode_reg(struct max77693_led_device *led, u8 mode)149{150	struct regmap *rmap = led->regmap;151	int ret, v = 0, i;152 153	for (i = FLED1; i <= FLED2; ++i) {154		if (mode & MODE_TORCH(i))155			v |= FLASH_EN_ON << TORCH_EN_SHIFT(i);156 157		if (mode & MODE_FLASH(i)) {158			v |= FLASH_EN_ON << FLASH_EN_SHIFT(i);159		} else if (mode & MODE_FLASH_EXTERNAL(i)) {160			v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i);161			/*162			 * Enable hw triggering also for torch mode, as some163			 * camera sensors use torch led to fathom ambient light164			 * conditions before strobing the flash.165			 */166			v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i);167		}168	}169 170	/* Reset the register only prior setting flash modes */171	if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) {172		ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0);173		if (ret < 0)174			return ret;175	}176 177	return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v);178}179 180static int max77693_add_mode(struct max77693_led_device *led, u8 mode)181{182	u8 new_mode_flags;183	int i, ret;184 185	if (led->iout_joint)186		/* Span the mode on FLED2 for joint iouts case */187		mode |= (mode << 1);188 189	/*190	 * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device.191	 * Corresponding register bit fields interfere with SW triggered modes,192	 * thus clear them to ensure proper device configuration.193	 */194	for (i = FLED1; i <= FLED2; ++i)195		if (mode & MODE_FLASH_EXTERNAL(i))196			led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i));197 198	new_mode_flags = mode | led->mode_flags;199	new_mode_flags &= led->allowed_modes;200 201	if (new_mode_flags ^ led->mode_flags)202		led->mode_flags = new_mode_flags;203	else204		return 0;205 206	ret = max77693_set_mode_reg(led, led->mode_flags);207	if (ret < 0)208		return ret;209 210	/*211	 * Clear flash mode flag after setting the mode to avoid spurious flash212	 * strobing on each subsequent torch mode setting.213	 */214	if (mode & MODE_FLASH_MASK)215		led->mode_flags &= ~mode;216 217	return ret;218}219 220static int max77693_clear_mode(struct max77693_led_device *led,221				u8 mode)222{223	if (led->iout_joint)224		/* Clear mode also on FLED2 for joint iouts case */225		mode |= (mode << 1);226 227	led->mode_flags &= ~mode;228 229	return max77693_set_mode_reg(led, led->mode_flags);230}231 232static void max77693_add_allowed_modes(struct max77693_led_device *led,233				int fled_id, enum max77693_led_mode mode)234{235	if (mode == FLASH)236		led->allowed_modes |= (MODE_FLASH(fled_id) |237				       MODE_FLASH_EXTERNAL(fled_id));238	else239		led->allowed_modes |= MODE_TORCH(fled_id);240}241 242static void max77693_distribute_currents(struct max77693_led_device *led,243				int fled_id, enum max77693_led_mode mode,244				u32 micro_amp, u32 iout_max[2], u32 iout[2])245{246	if (!led->iout_joint) {247		iout[fled_id] = micro_amp;248		max77693_add_allowed_modes(led, fled_id, mode);249		return;250	}251 252	iout[FLED1] = min(micro_amp, iout_max[FLED1]);253	iout[FLED2] = micro_amp - iout[FLED1];254 255	if (mode == FLASH)256		led->allowed_modes &= ~MODE_FLASH_MASK;257	else258		led->allowed_modes &= ~MODE_TORCH_MASK;259 260	max77693_add_allowed_modes(led, FLED1, mode);261 262	if (iout[FLED2])263		max77693_add_allowed_modes(led, FLED2, mode);264}265 266static int max77693_set_torch_current(struct max77693_led_device *led,267				int fled_id, u32 micro_amp)268{269	struct regmap *rmap = led->regmap;270	u8 iout1_reg = 0, iout2_reg = 0;271	u32 iout[2];272 273	max77693_distribute_currents(led, fled_id, TORCH, micro_amp,274					led->iout_torch_max, iout);275 276	if (fled_id == FLED1 || led->iout_joint) {277		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);278		led->torch_iout_reg &= TORCH_IOUT_MASK(TORCH_IOUT2_SHIFT);279	}280	if (fled_id == FLED2 || led->iout_joint) {281		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);282		led->torch_iout_reg &= TORCH_IOUT_MASK(TORCH_IOUT1_SHIFT);283	}284 285	led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) |286				(iout2_reg << TORCH_IOUT2_SHIFT));287 288	return regmap_write(rmap, MAX77693_LED_REG_ITORCH,289						led->torch_iout_reg);290}291 292static int max77693_set_flash_current(struct max77693_led_device *led,293					int fled_id,294					u32 micro_amp)295{296	struct regmap *rmap = led->regmap;297	u8 iout1_reg, iout2_reg;298	u32 iout[2];299	int ret = -EINVAL;300 301	max77693_distribute_currents(led, fled_id, FLASH, micro_amp,302					led->iout_flash_max, iout);303 304	if (fled_id == FLED1 || led->iout_joint) {305		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);306		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1,307							iout1_reg);308		if (ret < 0)309			return ret;310	}311	if (fled_id == FLED2 || led->iout_joint) {312		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);313		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2,314							iout2_reg);315	}316 317	return ret;318}319 320static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec)321{322	struct regmap *rmap = led->regmap;323	u8 v;324	int ret;325 326	v = max77693_flash_timeout_to_reg(microsec) | FLASH_TMR_LEVEL;327 328	ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v);329	if (ret < 0)330		return ret;331 332	led->current_flash_timeout = microsec;333 334	return 0;335}336 337static int max77693_get_strobe_status(struct max77693_led_device *led,338					bool *state)339{340	struct regmap *rmap = led->regmap;341	unsigned int v;342	int ret;343 344	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v);345	if (ret < 0)346		return ret;347 348	*state = v & FLASH_STATUS_FLASH_ON;349 350	return ret;351}352 353static int max77693_get_flash_faults(struct max77693_sub_led *sub_led)354{355	struct max77693_led_device *led = sub_led_to_led(sub_led);356	struct regmap *rmap = led->regmap;357	unsigned int v;358	u8 fault_open_mask, fault_short_mask;359	int ret;360 361	sub_led->flash_faults = 0;362 363	if (led->iout_joint) {364		fault_open_mask = FLASH_INT_FLED1_OPEN | FLASH_INT_FLED2_OPEN;365		fault_short_mask = FLASH_INT_FLED1_SHORT |366							FLASH_INT_FLED2_SHORT;367	} else {368		fault_open_mask = (sub_led->fled_id == FLED1) ?369						FLASH_INT_FLED1_OPEN :370						FLASH_INT_FLED2_OPEN;371		fault_short_mask = (sub_led->fled_id == FLED1) ?372						FLASH_INT_FLED1_SHORT :373						FLASH_INT_FLED2_SHORT;374	}375 376	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, &v);377	if (ret < 0)378		return ret;379 380	if (v & fault_open_mask)381		sub_led->flash_faults |= LED_FAULT_OVER_VOLTAGE;382	if (v & fault_short_mask)383		sub_led->flash_faults |= LED_FAULT_SHORT_CIRCUIT;384	if (v & FLASH_INT_OVER_CURRENT)385		sub_led->flash_faults |= LED_FAULT_OVER_CURRENT;386 387	return 0;388}389 390static int max77693_setup(struct max77693_led_device *led,391			 struct max77693_led_config_data *led_cfg)392{393	struct regmap *rmap = led->regmap;394	int i, first_led, last_led, ret;395	u32 max_flash_curr[2];396	u8 v;397 398	/*399	 * Initialize only flash current. Torch current doesn't400	 * require initialization as ITORCH register is written with401	 * new value each time brightness_set op is called.402	 */403	if (led->iout_joint) {404		first_led = FLED1;405		last_led = FLED1;406		max_flash_curr[FLED1] = led_cfg->iout_flash_max[FLED1] +407					led_cfg->iout_flash_max[FLED2];408	} else {409		first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2;410		last_led = max77693_fled_used(led, FLED2) ? FLED2 : FLED1;411		max_flash_curr[FLED1] = led_cfg->iout_flash_max[FLED1];412		max_flash_curr[FLED2] = led_cfg->iout_flash_max[FLED2];413	}414 415	for (i = first_led; i <= last_led; ++i) {416		ret = max77693_set_flash_current(led, i,417					max_flash_curr[i]);418		if (ret < 0)419			return ret;420	}421 422	v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL;423	ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v);424	if (ret < 0)425		return ret;426 427	if (led_cfg->low_vsys > 0)428		v = max77693_led_vsys_to_reg(led_cfg->low_vsys) |429						MAX_FLASH1_MAX_FL_EN;430	else431		v = 0;432 433	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v);434	if (ret < 0)435		return ret;436	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0);437	if (ret < 0)438		return ret;439 440	if (led_cfg->boost_mode == MAX77693_LED_BOOST_FIXED)441		v = FLASH_BOOST_FIXED;442	else443		v = led_cfg->boost_mode | led_cfg->boost_mode << 1;444 445	if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))446		v |= FLASH_BOOST_LEDNUM_2;447 448	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v);449	if (ret < 0)450		return ret;451 452	v = max77693_led_vout_to_reg(led_cfg->boost_vout);453	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v);454	if (ret < 0)455		return ret;456 457	return max77693_set_mode_reg(led, MODE_OFF);458}459 460/* LED subsystem callbacks */461static int max77693_led_brightness_set(struct led_classdev *led_cdev,462					enum led_brightness value)463{464	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);465	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);466	struct max77693_led_device *led = sub_led_to_led(sub_led);467	int fled_id = sub_led->fled_id, ret;468 469	mutex_lock(&led->lock);470 471	if (value == 0) {472		ret = max77693_clear_mode(led, MODE_TORCH(fled_id));473		if (ret < 0)474			dev_dbg(&led->pdev->dev,475				"Failed to clear torch mode (%d)\n",476				ret);477		goto unlock;478	}479 480	ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP);481	if (ret < 0) {482		dev_dbg(&led->pdev->dev,483			"Failed to set torch current (%d)\n",484			ret);485		goto unlock;486	}487 488	ret = max77693_add_mode(led, MODE_TORCH(fled_id));489	if (ret < 0)490		dev_dbg(&led->pdev->dev,491			"Failed to set torch mode (%d)\n",492			ret);493unlock:494	mutex_unlock(&led->lock);495 496	return ret;497}498 499static int max77693_led_flash_brightness_set(500				struct led_classdev_flash *fled_cdev,501				u32 brightness)502{503	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);504	struct max77693_led_device *led = sub_led_to_led(sub_led);505	int ret;506 507	mutex_lock(&led->lock);508	ret = max77693_set_flash_current(led, sub_led->fled_id, brightness);509	mutex_unlock(&led->lock);510 511	return ret;512}513 514static int max77693_led_flash_strobe_set(515				struct led_classdev_flash *fled_cdev,516				bool state)517{518	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);519	struct max77693_led_device *led = sub_led_to_led(sub_led);520	int fled_id = sub_led->fled_id;521	int ret;522 523	mutex_lock(&led->lock);524 525	if (!state) {526		ret = max77693_clear_mode(led, MODE_FLASH(fled_id));527		goto unlock;528	}529 530	if (sub_led->flash_timeout != led->current_flash_timeout) {531		ret = max77693_set_timeout(led, sub_led->flash_timeout);532		if (ret < 0)533			goto unlock;534	}535 536	led->strobing_sub_led_id = fled_id;537 538	ret = max77693_add_mode(led, MODE_FLASH(fled_id));539	if (ret < 0)540		goto unlock;541 542	ret = max77693_get_flash_faults(sub_led);543 544unlock:545	mutex_unlock(&led->lock);546	return ret;547}548 549static int max77693_led_flash_fault_get(550				struct led_classdev_flash *fled_cdev,551				u32 *fault)552{553	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);554 555	*fault = sub_led->flash_faults;556 557	return 0;558}559 560static int max77693_led_flash_strobe_get(561				struct led_classdev_flash *fled_cdev,562				bool *state)563{564	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);565	struct max77693_led_device *led = sub_led_to_led(sub_led);566	int ret;567 568	if (!state)569		return -EINVAL;570 571	mutex_lock(&led->lock);572 573	ret = max77693_get_strobe_status(led, state);574 575	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));576 577	mutex_unlock(&led->lock);578 579	return ret;580}581 582static int max77693_led_flash_timeout_set(583				struct led_classdev_flash *fled_cdev,584				u32 timeout)585{586	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);587	struct max77693_led_device *led = sub_led_to_led(sub_led);588 589	mutex_lock(&led->lock);590	sub_led->flash_timeout = timeout;591	mutex_unlock(&led->lock);592 593	return 0;594}595 596static int max77693_led_parse_dt(struct max77693_led_device *led,597				struct max77693_led_config_data *cfg,598				struct device_node **sub_nodes)599{600	struct device *dev = &led->pdev->dev;601	struct max77693_sub_led *sub_leds = led->sub_leds;602	struct device_node *node = dev_of_node(dev);603	struct property *prop;604	u32 led_sources[2];605	int i, ret, fled_id;606 607	of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode);608	of_property_read_u32(node, "maxim,boost-mvout", &cfg->boost_vout);609	of_property_read_u32(node, "maxim,mvsys-min", &cfg->low_vsys);610 611	for_each_available_child_of_node_scoped(node, child_node) {612		prop = of_find_property(child_node, "led-sources", NULL);613		if (prop) {614			const __be32 *srcs = NULL;615 616			for (i = 0; i < ARRAY_SIZE(led_sources); ++i) {617				srcs = of_prop_next_u32(prop, srcs,618							&led_sources[i]);619				if (!srcs)620					break;621			}622		} else {623			dev_err(dev,624				"led-sources DT property missing\n");625			return -EINVAL;626		}627 628		if (i == 2) {629			fled_id = FLED1;630			led->fled_mask = FLED1_IOUT | FLED2_IOUT;631		} else if (led_sources[0] == FLED1) {632			fled_id = FLED1;633			led->fled_mask |= FLED1_IOUT;634		} else if (led_sources[0] == FLED2) {635			fled_id = FLED2;636			led->fled_mask |= FLED2_IOUT;637		} else {638			dev_err(dev,639				"Wrong led-sources DT property value.\n");640			return -EINVAL;641		}642 643		if (sub_nodes[fled_id]) {644			dev_err(dev,645				"Conflicting \"led-sources\" DT properties\n");646			return -EINVAL;647		}648 649		sub_nodes[fled_id] = of_node_get(child_node);650		sub_leds[fled_id].fled_id = fled_id;651 652		cfg->label[fled_id] =653			of_get_property(child_node, "label", NULL) ? :654						child_node->name;655 656		ret = of_property_read_u32(child_node, "led-max-microamp",657					&cfg->iout_torch_max[fled_id]);658		if (ret < 0) {659			cfg->iout_torch_max[fled_id] = TORCH_IOUT_MIN;660			dev_warn(dev, "led-max-microamp DT property missing\n");661		}662 663		ret = of_property_read_u32(child_node, "flash-max-microamp",664					&cfg->iout_flash_max[fled_id]);665		if (ret < 0) {666			cfg->iout_flash_max[fled_id] = FLASH_IOUT_MIN;667			dev_warn(dev,668				 "flash-max-microamp DT property missing\n");669		}670 671		ret = of_property_read_u32(child_node, "flash-max-timeout-us",672					&cfg->flash_timeout_max[fled_id]);673		if (ret < 0) {674			cfg->flash_timeout_max[fled_id] = FLASH_TIMEOUT_MIN;675			dev_warn(dev,676				 "flash-max-timeout-us DT property missing\n");677		}678 679		if (++cfg->num_leds == 2 ||680		    (max77693_fled_used(led, FLED1) &&681		     max77693_fled_used(led, FLED2)))682			break;683	}684 685	if (cfg->num_leds == 0) {686		dev_err(dev, "No DT child node found for connected LED(s).\n");687		return -EINVAL;688	}689 690	return 0;691}692 693static void clamp_align(u32 *v, u32 min, u32 max, u32 step)694{695	*v = clamp_val(*v, min, max);696	if (step > 1)697		*v = (*v - min) / step * step + min;698}699 700static void max77693_align_iout_current(struct max77693_led_device *led,701					u32 *iout, u32 min, u32 max, u32 step)702{703	int i;704 705	if (led->iout_joint) {706		if (iout[FLED1] > min) {707			iout[FLED1] /= 2;708			iout[FLED2] = iout[FLED1];709		} else {710			iout[FLED1] = min;711			iout[FLED2] = 0;712			return;713		}714	}715 716	for (i = FLED1; i <= FLED2; ++i)717		if (max77693_fled_used(led, i))718			clamp_align(&iout[i], min, max, step);719		else720			iout[i] = 0;721}722 723static void max77693_led_validate_configuration(struct max77693_led_device *led,724					struct max77693_led_config_data *cfg)725{726	u32 flash_iout_max = cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS :727					       FLASH_IOUT_MAX_1LED;728	int i;729 730	if (cfg->num_leds == 1 &&731	    max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))732		led->iout_joint = true;733 734	cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE,735			    MAX77693_LED_BOOST_FIXED);736 737	/* Boost must be enabled if both current outputs are used */738	if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint)739		cfg->boost_mode = MAX77693_LED_BOOST_FIXED;740 741	max77693_align_iout_current(led, cfg->iout_torch_max,742			TORCH_IOUT_MIN, TORCH_IOUT_MAX, TORCH_IOUT_STEP);743 744	max77693_align_iout_current(led, cfg->iout_flash_max,745			FLASH_IOUT_MIN, flash_iout_max, FLASH_IOUT_STEP);746 747	for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout_max); ++i)748		clamp_align(&cfg->flash_timeout_max[i], FLASH_TIMEOUT_MIN,749				FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP);750 751	clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX,752							FLASH_VOUT_STEP);753 754	if (cfg->low_vsys)755		clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN,756				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);757}758 759static int max77693_led_get_configuration(struct max77693_led_device *led,760				struct max77693_led_config_data *cfg,761				struct device_node **sub_nodes)762{763	int ret;764 765	ret = max77693_led_parse_dt(led, cfg, sub_nodes);766	if (ret < 0)767		return ret;768 769	max77693_led_validate_configuration(led, cfg);770 771	memcpy(led->iout_torch_max, cfg->iout_torch_max,772				sizeof(led->iout_torch_max));773	memcpy(led->iout_flash_max, cfg->iout_flash_max,774				sizeof(led->iout_flash_max));775 776	return 0;777}778 779static const struct led_flash_ops flash_ops = {780	.flash_brightness_set	= max77693_led_flash_brightness_set,781	.strobe_set		= max77693_led_flash_strobe_set,782	.strobe_get		= max77693_led_flash_strobe_get,783	.timeout_set		= max77693_led_flash_timeout_set,784	.fault_get		= max77693_led_flash_fault_get,785};786 787static void max77693_init_flash_settings(struct max77693_sub_led *sub_led,788				 struct max77693_led_config_data *led_cfg)789{790	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;791	struct max77693_led_device *led = sub_led_to_led(sub_led);792	int fled_id = sub_led->fled_id;793	struct led_flash_setting *setting;794 795	/* Init flash intensity setting */796	setting = &fled_cdev->brightness;797	setting->min = FLASH_IOUT_MIN;798	setting->max = led->iout_joint ?799		led_cfg->iout_flash_max[FLED1] +800		led_cfg->iout_flash_max[FLED2] :801		led_cfg->iout_flash_max[fled_id];802	setting->step = FLASH_IOUT_STEP;803	setting->val = setting->max;804 805	/* Init flash timeout setting */806	setting = &fled_cdev->timeout;807	setting->min = FLASH_TIMEOUT_MIN;808	setting->max = led_cfg->flash_timeout_max[fled_id];809	setting->step = FLASH_TIMEOUT_STEP;810	setting->val = setting->max;811}812 813#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)814 815static int max77693_led_external_strobe_set(816				struct v4l2_flash *v4l2_flash,817				bool enable)818{819	struct max77693_sub_led *sub_led =820				flcdev_to_sub_led(v4l2_flash->fled_cdev);821	struct max77693_led_device *led = sub_led_to_led(sub_led);822	int fled_id = sub_led->fled_id;823	int ret;824 825	mutex_lock(&led->lock);826 827	if (enable)828		ret = max77693_add_mode(led, MODE_FLASH_EXTERNAL(fled_id));829	else830		ret = max77693_clear_mode(led, MODE_FLASH_EXTERNAL(fled_id));831 832	mutex_unlock(&led->lock);833 834	return ret;835}836 837static void max77693_init_v4l2_flash_config(struct max77693_sub_led *sub_led,838				struct max77693_led_config_data *led_cfg,839				struct v4l2_flash_config *v4l2_sd_cfg)840{841	struct max77693_led_device *led = sub_led_to_led(sub_led);842	struct device *dev = &led->pdev->dev;843	struct max77693_dev *iodev = dev_get_drvdata(dev->parent);844	struct i2c_client *i2c = iodev->i2c;845	struct led_flash_setting *s;846 847	snprintf(v4l2_sd_cfg->dev_name, sizeof(v4l2_sd_cfg->dev_name),848		 "%s %d-%04x", sub_led->fled_cdev.led_cdev.name,849		 i2c_adapter_id(i2c->adapter), i2c->addr);850 851	s = &v4l2_sd_cfg->intensity;852	s->min = TORCH_IOUT_MIN;853	s->max = sub_led->fled_cdev.led_cdev.max_brightness * TORCH_IOUT_STEP;854	s->step = TORCH_IOUT_STEP;855	s->val = s->max;856 857	/* Init flash faults config */858	v4l2_sd_cfg->flash_faults = LED_FAULT_OVER_VOLTAGE |859				LED_FAULT_SHORT_CIRCUIT |860				LED_FAULT_OVER_CURRENT;861 862	v4l2_sd_cfg->has_external_strobe = true;863}864 865static const struct v4l2_flash_ops v4l2_flash_ops = {866	.external_strobe_set = max77693_led_external_strobe_set,867};868#else869static inline void max77693_init_v4l2_flash_config(870				struct max77693_sub_led *sub_led,871				struct max77693_led_config_data *led_cfg,872				struct v4l2_flash_config *v4l2_sd_cfg)873{874}875static const struct v4l2_flash_ops v4l2_flash_ops;876#endif877 878static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,879				struct max77693_led_config_data *led_cfg)880{881	struct max77693_led_device *led = sub_led_to_led(sub_led);882	int fled_id = sub_led->fled_id;883	struct led_classdev_flash *fled_cdev;884	struct led_classdev *led_cdev;885 886	/* Initialize LED Flash class device */887	fled_cdev = &sub_led->fled_cdev;888	fled_cdev->ops = &flash_ops;889	led_cdev = &fled_cdev->led_cdev;890 891	led_cdev->name = led_cfg->label[fled_id];892 893	led_cdev->brightness_set_blocking = max77693_led_brightness_set;894	led_cdev->max_brightness = (led->iout_joint ?895					led_cfg->iout_torch_max[FLED1] +896					led_cfg->iout_torch_max[FLED2] :897					led_cfg->iout_torch_max[fled_id]) /898				   TORCH_IOUT_STEP;899	led_cdev->flags |= LED_DEV_CAP_FLASH;900 901	max77693_init_flash_settings(sub_led, led_cfg);902 903	/* Init flash timeout cache */904	sub_led->flash_timeout = fled_cdev->timeout.val;905}906 907static int max77693_register_led(struct max77693_sub_led *sub_led,908				 struct max77693_led_config_data *led_cfg,909				 struct device_node *sub_node)910{911	struct max77693_led_device *led = sub_led_to_led(sub_led);912	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;913	struct device *dev = &led->pdev->dev;914	struct v4l2_flash_config v4l2_sd_cfg = {};915	int ret;916 917	/* Register in the LED subsystem */918	ret = led_classdev_flash_register(dev, fled_cdev);919	if (ret < 0)920		return ret;921 922	max77693_init_v4l2_flash_config(sub_led, led_cfg, &v4l2_sd_cfg);923 924	/* Register in the V4L2 subsystem. */925	sub_led->v4l2_flash = v4l2_flash_init(dev, of_fwnode_handle(sub_node),926					      fled_cdev, &v4l2_flash_ops,927					      &v4l2_sd_cfg);928	if (IS_ERR(sub_led->v4l2_flash)) {929		ret = PTR_ERR(sub_led->v4l2_flash);930		goto err_v4l2_flash_init;931	}932 933	return 0;934 935err_v4l2_flash_init:936	led_classdev_flash_unregister(fled_cdev);937	return ret;938}939 940static int max77693_led_probe(struct platform_device *pdev)941{942	struct device *dev = &pdev->dev;943	struct max77693_dev *iodev = dev_get_drvdata(dev->parent);944	struct max77693_led_device *led;945	struct max77693_sub_led *sub_leds;946	struct device_node *sub_nodes[2] = {};947	struct max77693_led_config_data led_cfg = {};948	int init_fled_cdev[2], i, ret;949 950	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);951	if (!led)952		return -ENOMEM;953 954	led->pdev = pdev;955	led->regmap = iodev->regmap;956	led->allowed_modes = MODE_FLASH_MASK;957	sub_leds = led->sub_leds;958 959	platform_set_drvdata(pdev, led);960	ret = max77693_led_get_configuration(led, &led_cfg, sub_nodes);961	if (ret < 0)962		return ret;963 964	ret = max77693_setup(led, &led_cfg);965	if (ret < 0)966		goto err_setup;967 968	mutex_init(&led->lock);969 970	init_fled_cdev[FLED1] =971			led->iout_joint || max77693_fled_used(led, FLED1);972	init_fled_cdev[FLED2] =973			!led->iout_joint && max77693_fled_used(led, FLED2);974 975	for (i = FLED1; i <= FLED2; ++i) {976		if (!init_fled_cdev[i])977			continue;978 979		/* Initialize LED Flash class device */980		max77693_init_fled_cdev(&sub_leds[i], &led_cfg);981 982		/*983		 * Register LED Flash class device and corresponding984		 * V4L2 Flash device.985		 */986		ret = max77693_register_led(&sub_leds[i], &led_cfg,987						sub_nodes[i]);988		if (ret < 0) {989			/*990			 * At this moment FLED1 might have been already991			 * registered and it needs to be released.992			 */993			if (i == FLED2)994				goto err_register_led2;995			else996				goto err_register_led1;997		}998		of_node_put(sub_nodes[i]);999		sub_nodes[i] = NULL;1000	}1001 1002	return 0;1003 1004err_register_led2:1005	/* It is possible than only FLED2 was to be registered */1006	if (!init_fled_cdev[FLED1])1007		goto err_register_led1;1008	v4l2_flash_release(sub_leds[FLED1].v4l2_flash);1009	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);1010err_register_led1:1011	mutex_destroy(&led->lock);1012 1013err_setup:1014	for (i = FLED1; i <= FLED2; i++)1015		of_node_put(sub_nodes[i]);1016	return ret;1017}1018 1019static void max77693_led_remove(struct platform_device *pdev)1020{1021	struct max77693_led_device *led = platform_get_drvdata(pdev);1022	struct max77693_sub_led *sub_leds = led->sub_leds;1023 1024	if (led->iout_joint || max77693_fled_used(led, FLED1)) {1025		v4l2_flash_release(sub_leds[FLED1].v4l2_flash);1026		led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);1027	}1028 1029	if (!led->iout_joint && max77693_fled_used(led, FLED2)) {1030		v4l2_flash_release(sub_leds[FLED2].v4l2_flash);1031		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);1032	}1033 1034	mutex_destroy(&led->lock);1035}1036 1037static const struct of_device_id max77693_led_dt_match[] = {1038	{ .compatible = "maxim,max77693-led" },1039	{},1040};1041MODULE_DEVICE_TABLE(of, max77693_led_dt_match);1042 1043static struct platform_driver max77693_led_driver = {1044	.probe		= max77693_led_probe,1045	.remove_new	= max77693_led_remove,1046	.driver		= {1047		.name	= "max77693-led",1048		.of_match_table = max77693_led_dt_match,1049	},1050};1051 1052module_platform_driver(max77693_led_driver);1053 1054MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");1055MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");1056MODULE_DESCRIPTION("Maxim MAX77693 led flash driver");1057MODULE_LICENSE("GPL v2");1058