xref: /openbmc/linux/drivers/leds/leds-lm3697.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
15c1d824cSDan Murphy // SPDX-License-Identifier: GPL-2.0
25c1d824cSDan Murphy // TI LM3697 LED chip family driver
3c5437338SAlexander A. Klimov // Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
45c1d824cSDan Murphy 
53a923639SAndy Shevchenko #include <linux/bits.h>
65c1d824cSDan Murphy #include <linux/gpio/consumer.h>
75c1d824cSDan Murphy #include <linux/i2c.h>
83a923639SAndy Shevchenko #include <linux/mod_devicetable.h>
93a923639SAndy Shevchenko #include <linux/module.h>
103a923639SAndy Shevchenko #include <linux/property.h>
113a923639SAndy Shevchenko #include <linux/regmap.h>
125c1d824cSDan Murphy #include <linux/regulator/consumer.h>
133a923639SAndy Shevchenko #include <linux/types.h>
143a923639SAndy Shevchenko 
155c1d824cSDan Murphy #include <linux/leds-ti-lmu-common.h>
165c1d824cSDan Murphy 
175c1d824cSDan Murphy #define LM3697_REV			0x0
185c1d824cSDan Murphy #define LM3697_RESET			0x1
195c1d824cSDan Murphy #define LM3697_OUTPUT_CONFIG		0x10
205c1d824cSDan Murphy #define LM3697_CTRL_A_RAMP		0x11
215c1d824cSDan Murphy #define LM3697_CTRL_B_RAMP		0x12
225c1d824cSDan Murphy #define LM3697_CTRL_A_B_RT_RAMP		0x13
235c1d824cSDan Murphy #define LM3697_CTRL_A_B_RAMP_CFG	0x14
245c1d824cSDan Murphy #define LM3697_CTRL_A_B_BRT_CFG		0x16
255c1d824cSDan Murphy #define LM3697_CTRL_A_FS_CURR_CFG	0x17
265c1d824cSDan Murphy #define LM3697_CTRL_B_FS_CURR_CFG	0x18
275c1d824cSDan Murphy #define LM3697_PWM_CFG			0x1c
285c1d824cSDan Murphy #define LM3697_CTRL_A_BRT_LSB		0x20
295c1d824cSDan Murphy #define LM3697_CTRL_A_BRT_MSB		0x21
305c1d824cSDan Murphy #define LM3697_CTRL_B_BRT_LSB		0x22
315c1d824cSDan Murphy #define LM3697_CTRL_B_BRT_MSB		0x23
325c1d824cSDan Murphy #define LM3697_CTRL_ENABLE		0x24
335c1d824cSDan Murphy 
345c1d824cSDan Murphy #define LM3697_SW_RESET		BIT(0)
355c1d824cSDan Murphy 
365c1d824cSDan Murphy #define LM3697_CTRL_A_EN	BIT(0)
375c1d824cSDan Murphy #define LM3697_CTRL_B_EN	BIT(1)
385c1d824cSDan Murphy #define LM3697_CTRL_A_B_EN	(LM3697_CTRL_A_EN | LM3697_CTRL_B_EN)
395c1d824cSDan Murphy 
405c1d824cSDan Murphy #define LM3697_MAX_LED_STRINGS	3
415c1d824cSDan Murphy 
425c1d824cSDan Murphy #define LM3697_CONTROL_A	0
435c1d824cSDan Murphy #define LM3697_CONTROL_B	1
445c1d824cSDan Murphy #define LM3697_MAX_CONTROL_BANKS 2
455c1d824cSDan Murphy 
465c1d824cSDan Murphy /**
475c1d824cSDan Murphy  * struct lm3697_led -
485c1d824cSDan Murphy  * @hvled_strings: Array of LED strings associated with a control bank
495c1d824cSDan Murphy  * @label: LED label
505c1d824cSDan Murphy  * @led_dev: LED class device
515c1d824cSDan Murphy  * @priv: Pointer to the device struct
525c1d824cSDan Murphy  * @lmu_data: Register and setting values for common code
535c1d824cSDan Murphy  * @control_bank: Control bank the LED is associated to. 0 is control bank A
545c1d824cSDan Murphy  *		   1 is control bank B
556e174d39SLee Jones  * @enabled: LED brightness level (or LED_OFF)
566e174d39SLee Jones  * @num_leds: Number of LEDs available
575c1d824cSDan Murphy  */
585c1d824cSDan Murphy struct lm3697_led {
595c1d824cSDan Murphy 	u32 hvled_strings[LM3697_MAX_LED_STRINGS];
605c1d824cSDan Murphy 	char label[LED_MAX_NAME_SIZE];
615c1d824cSDan Murphy 	struct led_classdev led_dev;
625c1d824cSDan Murphy 	struct lm3697 *priv;
635c1d824cSDan Murphy 	struct ti_lmu_bank lmu_data;
645c1d824cSDan Murphy 	int control_bank;
655c1d824cSDan Murphy 	int enabled;
665c1d824cSDan Murphy 	int num_leds;
675c1d824cSDan Murphy };
685c1d824cSDan Murphy 
695c1d824cSDan Murphy /**
705c1d824cSDan Murphy  * struct lm3697 -
715c1d824cSDan Murphy  * @enable_gpio: Hardware enable gpio
725c1d824cSDan Murphy  * @regulator: LED supply regulator pointer
735c1d824cSDan Murphy  * @client: Pointer to the I2C client
745c1d824cSDan Murphy  * @regmap: Devices register map
755c1d824cSDan Murphy  * @dev: Pointer to the devices device struct
765c1d824cSDan Murphy  * @lock: Lock for reading/writing the device
775c1d824cSDan Murphy  * @leds: Array of LED strings
786e174d39SLee Jones  * @bank_cfg: OUTPUT_CONFIG register values
796e174d39SLee Jones  * @num_banks: Number of control banks
805c1d824cSDan Murphy  */
815c1d824cSDan Murphy struct lm3697 {
825c1d824cSDan Murphy 	struct gpio_desc *enable_gpio;
835c1d824cSDan Murphy 	struct regulator *regulator;
845c1d824cSDan Murphy 	struct i2c_client *client;
855c1d824cSDan Murphy 	struct regmap *regmap;
865c1d824cSDan Murphy 	struct device *dev;
875c1d824cSDan Murphy 	struct mutex lock;
885c1d824cSDan Murphy 
895c1d824cSDan Murphy 	int bank_cfg;
9098d278caSGabriel David 	int num_banks;
915c1d824cSDan Murphy 
925c1d824cSDan Murphy 	struct lm3697_led leds[];
935c1d824cSDan Murphy };
945c1d824cSDan Murphy 
955c1d824cSDan Murphy static const struct reg_default lm3697_reg_defs[] = {
965c1d824cSDan Murphy 	{LM3697_OUTPUT_CONFIG, 0x6},
975c1d824cSDan Murphy 	{LM3697_CTRL_A_RAMP, 0x0},
985c1d824cSDan Murphy 	{LM3697_CTRL_B_RAMP, 0x0},
995c1d824cSDan Murphy 	{LM3697_CTRL_A_B_RT_RAMP, 0x0},
1005c1d824cSDan Murphy 	{LM3697_CTRL_A_B_RAMP_CFG, 0x0},
1015c1d824cSDan Murphy 	{LM3697_CTRL_A_B_BRT_CFG, 0x0},
1025c1d824cSDan Murphy 	{LM3697_CTRL_A_FS_CURR_CFG, 0x13},
1035c1d824cSDan Murphy 	{LM3697_CTRL_B_FS_CURR_CFG, 0x13},
1045c1d824cSDan Murphy 	{LM3697_PWM_CFG, 0xc},
1055c1d824cSDan Murphy 	{LM3697_CTRL_A_BRT_LSB, 0x0},
1065c1d824cSDan Murphy 	{LM3697_CTRL_A_BRT_MSB, 0x0},
1075c1d824cSDan Murphy 	{LM3697_CTRL_B_BRT_LSB, 0x0},
1085c1d824cSDan Murphy 	{LM3697_CTRL_B_BRT_MSB, 0x0},
1095c1d824cSDan Murphy 	{LM3697_CTRL_ENABLE, 0x0},
1105c1d824cSDan Murphy };
1115c1d824cSDan Murphy 
1125c1d824cSDan Murphy static const struct regmap_config lm3697_regmap_config = {
1135c1d824cSDan Murphy 	.reg_bits = 8,
1145c1d824cSDan Murphy 	.val_bits = 8,
1155c1d824cSDan Murphy 
1165c1d824cSDan Murphy 	.max_register = LM3697_CTRL_ENABLE,
1175c1d824cSDan Murphy 	.reg_defaults = lm3697_reg_defs,
1185c1d824cSDan Murphy 	.num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs),
1195c1d824cSDan Murphy 	.cache_type = REGCACHE_FLAT,
1205c1d824cSDan Murphy };
1215c1d824cSDan Murphy 
lm3697_brightness_set(struct led_classdev * led_cdev,enum led_brightness brt_val)1225c1d824cSDan Murphy static int lm3697_brightness_set(struct led_classdev *led_cdev,
1235c1d824cSDan Murphy 				enum led_brightness brt_val)
1245c1d824cSDan Murphy {
1255c1d824cSDan Murphy 	struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,
1265c1d824cSDan Murphy 					      led_dev);
1275c1d824cSDan Murphy 	int ctrl_en_val = (1 << led->control_bank);
1280b9e3572SMarek Behún 	struct device *dev = led->priv->dev;
1295c1d824cSDan Murphy 	int ret;
1305c1d824cSDan Murphy 
1315c1d824cSDan Murphy 	mutex_lock(&led->priv->lock);
1325c1d824cSDan Murphy 
1335c1d824cSDan Murphy 	if (brt_val == LED_OFF) {
1345c1d824cSDan Murphy 		ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,
1355c1d824cSDan Murphy 					 ctrl_en_val, ~ctrl_en_val);
1365c1d824cSDan Murphy 		if (ret) {
1370b9e3572SMarek Behún 			dev_err(dev, "Cannot write ctrl register\n");
1385c1d824cSDan Murphy 			goto brightness_out;
1395c1d824cSDan Murphy 		}
1405c1d824cSDan Murphy 
1415c1d824cSDan Murphy 		led->enabled = LED_OFF;
1425c1d824cSDan Murphy 	} else {
1435c1d824cSDan Murphy 		ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
1445c1d824cSDan Murphy 		if (ret) {
1450b9e3572SMarek Behún 			dev_err(dev, "Cannot write brightness\n");
1465c1d824cSDan Murphy 			goto brightness_out;
1475c1d824cSDan Murphy 		}
1485c1d824cSDan Murphy 
1495c1d824cSDan Murphy 		if (!led->enabled) {
1505c1d824cSDan Murphy 			ret = regmap_update_bits(led->priv->regmap,
1515c1d824cSDan Murphy 						 LM3697_CTRL_ENABLE,
1525c1d824cSDan Murphy 						 ctrl_en_val, ctrl_en_val);
1535c1d824cSDan Murphy 			if (ret) {
1540b9e3572SMarek Behún 				dev_err(dev, "Cannot enable the device\n");
1555c1d824cSDan Murphy 				goto brightness_out;
1565c1d824cSDan Murphy 			}
1575c1d824cSDan Murphy 
1585c1d824cSDan Murphy 			led->enabled = brt_val;
1595c1d824cSDan Murphy 		}
1605c1d824cSDan Murphy 	}
1615c1d824cSDan Murphy 
1625c1d824cSDan Murphy brightness_out:
1635c1d824cSDan Murphy 	mutex_unlock(&led->priv->lock);
1645c1d824cSDan Murphy 	return ret;
1655c1d824cSDan Murphy }
1665c1d824cSDan Murphy 
lm3697_init(struct lm3697 * priv)1675c1d824cSDan Murphy static int lm3697_init(struct lm3697 *priv)
1685c1d824cSDan Murphy {
1690b9e3572SMarek Behún 	struct device *dev = priv->dev;
1705c1d824cSDan Murphy 	struct lm3697_led *led;
1715c1d824cSDan Murphy 	int i, ret;
1725c1d824cSDan Murphy 
1735c1d824cSDan Murphy 	if (priv->enable_gpio) {
1745c1d824cSDan Murphy 		gpiod_direction_output(priv->enable_gpio, 1);
1755c1d824cSDan Murphy 	} else {
1765c1d824cSDan Murphy 		ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);
1775c1d824cSDan Murphy 		if (ret) {
1780b9e3572SMarek Behún 			dev_err(dev, "Cannot reset the device\n");
1795c1d824cSDan Murphy 			goto out;
1805c1d824cSDan Murphy 		}
1815c1d824cSDan Murphy 	}
1825c1d824cSDan Murphy 
1835c1d824cSDan Murphy 	ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);
1845c1d824cSDan Murphy 	if (ret) {
1850b9e3572SMarek Behún 		dev_err(dev, "Cannot write ctrl enable\n");
1865c1d824cSDan Murphy 		goto out;
1875c1d824cSDan Murphy 	}
1885c1d824cSDan Murphy 
1895c1d824cSDan Murphy 	ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);
1905c1d824cSDan Murphy 	if (ret)
1910b9e3572SMarek Behún 		dev_err(dev, "Cannot write OUTPUT config\n");
1925c1d824cSDan Murphy 
19398d278caSGabriel David 	for (i = 0; i < priv->num_banks; i++) {
1945c1d824cSDan Murphy 		led = &priv->leds[i];
1955c1d824cSDan Murphy 		ret = ti_lmu_common_set_ramp(&led->lmu_data);
1965c1d824cSDan Murphy 		if (ret)
1970b9e3572SMarek Behún 			dev_err(dev, "Setting the ramp rate failed\n");
1985c1d824cSDan Murphy 	}
1995c1d824cSDan Murphy out:
2005c1d824cSDan Murphy 	return ret;
2015c1d824cSDan Murphy }
2025c1d824cSDan Murphy 
lm3697_probe_dt(struct lm3697 * priv)2035c1d824cSDan Murphy static int lm3697_probe_dt(struct lm3697 *priv)
2045c1d824cSDan Murphy {
2055c1d824cSDan Murphy 	struct fwnode_handle *child = NULL;
2060b9e3572SMarek Behún 	struct device *dev = priv->dev;
2075c1d824cSDan Murphy 	struct lm3697_led *led;
2080b9e3572SMarek Behún 	int ret = -EINVAL;
2095c1d824cSDan Murphy 	int control_bank;
2105c1d824cSDan Murphy 	size_t i = 0;
2115c1d824cSDan Murphy 	int j;
2125c1d824cSDan Murphy 
2130b9e3572SMarek Behún 	priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
2140b9e3572SMarek Behún 						    GPIOD_OUT_LOW);
215807553f8SAndy Shevchenko 	if (IS_ERR(priv->enable_gpio))
216807553f8SAndy Shevchenko 		return dev_err_probe(dev, PTR_ERR(priv->enable_gpio),
217807553f8SAndy Shevchenko 					  "Failed to get enable GPIO\n");
2185c1d824cSDan Murphy 
2190b9e3572SMarek Behún 	priv->regulator = devm_regulator_get(dev, "vled");
2205c1d824cSDan Murphy 	if (IS_ERR(priv->regulator))
2215c1d824cSDan Murphy 		priv->regulator = NULL;
2225c1d824cSDan Murphy 
2230b9e3572SMarek Behún 	device_for_each_child_node(dev, child) {
2243a953dc3SMarek Behún 		struct led_init_data init_data = {};
2253a953dc3SMarek Behún 
2265c1d824cSDan Murphy 		ret = fwnode_property_read_u32(child, "reg", &control_bank);
2275c1d824cSDan Murphy 		if (ret) {
2280b9e3572SMarek Behún 			dev_err(dev, "reg property missing\n");
2295c1d824cSDan Murphy 			goto child_out;
2305c1d824cSDan Murphy 		}
2315c1d824cSDan Murphy 
2325c1d824cSDan Murphy 		if (control_bank > LM3697_CONTROL_B) {
2330b9e3572SMarek Behún 			dev_err(dev, "reg property is invalid\n");
2345c1d824cSDan Murphy 			ret = -EINVAL;
2355c1d824cSDan Murphy 			goto child_out;
2365c1d824cSDan Murphy 		}
2375c1d824cSDan Murphy 
2385c1d824cSDan Murphy 		led = &priv->leds[i];
2395c1d824cSDan Murphy 
2400b9e3572SMarek Behún 		ret = ti_lmu_common_get_brt_res(dev, child, &led->lmu_data);
2415c1d824cSDan Murphy 		if (ret)
2420b9e3572SMarek Behún 			dev_warn(dev,
2430b9e3572SMarek Behún 				 "brightness resolution property missing\n");
2445c1d824cSDan Murphy 
2455c1d824cSDan Murphy 		led->control_bank = control_bank;
2465c1d824cSDan Murphy 		led->lmu_data.regmap = priv->regmap;
2475c1d824cSDan Murphy 		led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP +
2485c1d824cSDan Murphy 						 control_bank;
2495c1d824cSDan Murphy 		led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB +
2505c1d824cSDan Murphy 						   led->control_bank * 2;
2515c1d824cSDan Murphy 		led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB +
2525c1d824cSDan Murphy 						   led->control_bank * 2;
2535c1d824cSDan Murphy 
254246eab59SAndy Shevchenko 		led->num_leds = fwnode_property_count_u32(child, "led-sources");
2555c1d824cSDan Murphy 		if (led->num_leds > LM3697_MAX_LED_STRINGS) {
2560b9e3572SMarek Behún 			dev_err(dev, "Too many LED strings defined\n");
2575c1d824cSDan Murphy 			continue;
2585c1d824cSDan Murphy 		}
2595c1d824cSDan Murphy 
2605c1d824cSDan Murphy 		ret = fwnode_property_read_u32_array(child, "led-sources",
2615c1d824cSDan Murphy 						    led->hvled_strings,
2625c1d824cSDan Murphy 						    led->num_leds);
2635c1d824cSDan Murphy 		if (ret) {
2640b9e3572SMarek Behún 			dev_err(dev, "led-sources property missing\n");
2655c1d824cSDan Murphy 			goto child_out;
2665c1d824cSDan Murphy 		}
2675c1d824cSDan Murphy 
2685c1d824cSDan Murphy 		for (j = 0; j < led->num_leds; j++)
2695c1d824cSDan Murphy 			priv->bank_cfg |=
2705c1d824cSDan Murphy 				(led->control_bank << led->hvled_strings[j]);
2715c1d824cSDan Murphy 
2720b9e3572SMarek Behún 		ret = ti_lmu_common_get_ramp_params(dev, child, &led->lmu_data);
2735c1d824cSDan Murphy 		if (ret)
2740b9e3572SMarek Behún 			dev_warn(dev, "runtime-ramp properties missing\n");
2755c1d824cSDan Murphy 
2763a953dc3SMarek Behún 		init_data.fwnode = child;
2773a953dc3SMarek Behún 		init_data.devicename = priv->client->name;
2783a953dc3SMarek Behún 		/* for backwards compatibility if `label` is not present */
2793a953dc3SMarek Behún 		init_data.default_label = ":";
2805c1d824cSDan Murphy 
2815c1d824cSDan Murphy 		led->priv = priv;
2825c1d824cSDan Murphy 		led->led_dev.max_brightness = led->lmu_data.max_brightness;
2835c1d824cSDan Murphy 		led->led_dev.brightness_set_blocking = lm3697_brightness_set;
2845c1d824cSDan Murphy 
2850b9e3572SMarek Behún 		ret = devm_led_classdev_register_ext(dev, &led->led_dev,
2863a953dc3SMarek Behún 						     &init_data);
2875c1d824cSDan Murphy 		if (ret) {
2880b9e3572SMarek Behún 			dev_err(dev, "led register err: %d\n", ret);
2895c1d824cSDan Murphy 			goto child_out;
2905c1d824cSDan Murphy 		}
2915c1d824cSDan Murphy 
2925c1d824cSDan Murphy 		i++;
2935c1d824cSDan Murphy 	}
2945c1d824cSDan Murphy 
295d299ae94SAndy Shevchenko 	return ret;
296d299ae94SAndy Shevchenko 
2975c1d824cSDan Murphy child_out:
298d299ae94SAndy Shevchenko 	fwnode_handle_put(child);
2995c1d824cSDan Murphy 	return ret;
3005c1d824cSDan Murphy }
3015c1d824cSDan Murphy 
lm3697_probe(struct i2c_client * client)30290955588SUwe Kleine-König static int lm3697_probe(struct i2c_client *client)
3035c1d824cSDan Murphy {
3040b9e3572SMarek Behún 	struct device *dev = &client->dev;
3055c1d824cSDan Murphy 	struct lm3697 *led;
3065c1d824cSDan Murphy 	int count;
3075c1d824cSDan Murphy 	int ret;
3085c1d824cSDan Murphy 
3090b9e3572SMarek Behún 	count = device_get_child_node_count(dev);
31098d278caSGabriel David 	if (!count || count > LM3697_MAX_CONTROL_BANKS) {
31198d278caSGabriel David 		dev_err(dev, "Strange device tree!");
3125c1d824cSDan Murphy 		return -ENODEV;
3135c1d824cSDan Murphy 	}
3145c1d824cSDan Murphy 
3150b9e3572SMarek Behún 	led = devm_kzalloc(dev, struct_size(led, leds, count), GFP_KERNEL);
3165c1d824cSDan Murphy 	if (!led)
3175c1d824cSDan Murphy 		return -ENOMEM;
3185c1d824cSDan Murphy 
3195c1d824cSDan Murphy 	mutex_init(&led->lock);
3205c1d824cSDan Murphy 	i2c_set_clientdata(client, led);
3215c1d824cSDan Murphy 
3225c1d824cSDan Murphy 	led->client = client;
3230b9e3572SMarek Behún 	led->dev = dev;
32498d278caSGabriel David 	led->num_banks = count;
3255c1d824cSDan Murphy 	led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);
3265c1d824cSDan Murphy 	if (IS_ERR(led->regmap)) {
3275c1d824cSDan Murphy 		ret = PTR_ERR(led->regmap);
3280b9e3572SMarek Behún 		dev_err(dev, "Failed to allocate register map: %d\n", ret);
3295c1d824cSDan Murphy 		return ret;
3305c1d824cSDan Murphy 	}
3315c1d824cSDan Murphy 
3325c1d824cSDan Murphy 	ret = lm3697_probe_dt(led);
3335c1d824cSDan Murphy 	if (ret)
3345c1d824cSDan Murphy 		return ret;
3355c1d824cSDan Murphy 
3365c1d824cSDan Murphy 	return lm3697_init(led);
3375c1d824cSDan Murphy }
3385c1d824cSDan Murphy 
lm3697_remove(struct i2c_client * client)339ed5c2f5fSUwe Kleine-König static void lm3697_remove(struct i2c_client *client)
3405c1d824cSDan Murphy {
3415c1d824cSDan Murphy 	struct lm3697 *led = i2c_get_clientdata(client);
3420b9e3572SMarek Behún 	struct device *dev = &led->client->dev;
3435c1d824cSDan Murphy 	int ret;
3445c1d824cSDan Murphy 
3455c1d824cSDan Murphy 	ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,
3465c1d824cSDan Murphy 				 LM3697_CTRL_A_B_EN, 0);
347af89fa11SUwe Kleine-König 	if (ret)
3480b9e3572SMarek Behún 		dev_err(dev, "Failed to disable the device\n");
3495c1d824cSDan Murphy 
3505c1d824cSDan Murphy 	if (led->enable_gpio)
3515c1d824cSDan Murphy 		gpiod_direction_output(led->enable_gpio, 0);
3525c1d824cSDan Murphy 
3535c1d824cSDan Murphy 	if (led->regulator) {
3545c1d824cSDan Murphy 		ret = regulator_disable(led->regulator);
3555c1d824cSDan Murphy 		if (ret)
3560b9e3572SMarek Behún 			dev_err(dev, "Failed to disable regulator\n");
3575c1d824cSDan Murphy 	}
3585c1d824cSDan Murphy 
3595c1d824cSDan Murphy 	mutex_destroy(&led->lock);
3605c1d824cSDan Murphy }
3615c1d824cSDan Murphy 
3625c1d824cSDan Murphy static const struct i2c_device_id lm3697_id[] = {
3635c1d824cSDan Murphy 	{ "lm3697", 0 },
3645c1d824cSDan Murphy 	{ }
3655c1d824cSDan Murphy };
3665c1d824cSDan Murphy MODULE_DEVICE_TABLE(i2c, lm3697_id);
3675c1d824cSDan Murphy 
3685c1d824cSDan Murphy static const struct of_device_id of_lm3697_leds_match[] = {
3695c1d824cSDan Murphy 	{ .compatible = "ti,lm3697", },
3705c1d824cSDan Murphy 	{},
3715c1d824cSDan Murphy };
3725c1d824cSDan Murphy MODULE_DEVICE_TABLE(of, of_lm3697_leds_match);
3735c1d824cSDan Murphy 
3745c1d824cSDan Murphy static struct i2c_driver lm3697_driver = {
3755c1d824cSDan Murphy 	.driver = {
3765c1d824cSDan Murphy 		.name	= "lm3697",
3775c1d824cSDan Murphy 		.of_match_table = of_lm3697_leds_match,
3785c1d824cSDan Murphy 	},
379*d9ff8a8eSUwe Kleine-König 	.probe		= lm3697_probe,
3805c1d824cSDan Murphy 	.remove		= lm3697_remove,
3815c1d824cSDan Murphy 	.id_table	= lm3697_id,
3825c1d824cSDan Murphy };
3835c1d824cSDan Murphy module_i2c_driver(lm3697_driver);
3845c1d824cSDan Murphy 
3855c1d824cSDan Murphy MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver");
3865c1d824cSDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
3875c1d824cSDan Murphy MODULE_LICENSE("GPL v2");
388