xref: /openbmc/linux/drivers/leds/leds-lt3593.c (revision a17922de)
1 /*
2  * LEDs driver for LT3593 controllers
3  *
4  * See the datasheet at http://cds.linear.com/docs/Datasheet/3593f.pdf
5  *
6  * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
7  *
8  * Based on leds-gpio.c,
9  *
10  *   Copyright (C) 2007 8D Technologies inc.
11  *   Raphael Assenat <raph@8d.com>
12  *   Copyright (C) 2008 Freescale Semiconductor, Inc.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18 
19 #include <linux/kernel.h>
20 #include <linux/platform_device.h>
21 #include <linux/leds.h>
22 #include <linux/delay.h>
23 #include <linux/gpio.h>
24 #include <linux/slab.h>
25 #include <linux/module.h>
26 
27 struct lt3593_led_data {
28 	struct led_classdev cdev;
29 	unsigned gpio;
30 };
31 
32 static int lt3593_led_set(struct led_classdev *led_cdev,
33 			   enum led_brightness value)
34 {
35 	struct lt3593_led_data *led_dat =
36 		container_of(led_cdev, struct lt3593_led_data, cdev);
37 	int pulses;
38 
39 	/*
40 	 * The LT3593 resets its internal current level register to the maximum
41 	 * level on the first falling edge on the control pin. Each following
42 	 * falling edge decreases the current level by 625uA. Up to 32 pulses
43 	 * can be sent, so the maximum power reduction is 20mA.
44 	 * After a timeout of 128us, the value is taken from the register and
45 	 * applied is to the output driver.
46 	 */
47 
48 	if (value == 0) {
49 		gpio_set_value_cansleep(led_dat->gpio, 0);
50 		return 0;
51 	}
52 
53 	pulses = 32 - (value * 32) / 255;
54 
55 	if (pulses == 0) {
56 		gpio_set_value_cansleep(led_dat->gpio, 0);
57 		mdelay(1);
58 		gpio_set_value_cansleep(led_dat->gpio, 1);
59 		return 0;
60 	}
61 
62 	gpio_set_value_cansleep(led_dat->gpio, 1);
63 
64 	while (pulses--) {
65 		gpio_set_value_cansleep(led_dat->gpio, 0);
66 		udelay(1);
67 		gpio_set_value_cansleep(led_dat->gpio, 1);
68 		udelay(1);
69 	}
70 
71 	return 0;
72 }
73 
74 static int create_lt3593_led(const struct gpio_led *template,
75 	struct lt3593_led_data *led_dat, struct device *parent)
76 {
77 	int ret, state;
78 
79 	/* skip leds on GPIOs that aren't available */
80 	if (!gpio_is_valid(template->gpio)) {
81 		dev_info(parent, "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
82 				KBUILD_MODNAME, template->gpio, template->name);
83 		return 0;
84 	}
85 
86 	led_dat->cdev.name = template->name;
87 	led_dat->cdev.default_trigger = template->default_trigger;
88 	led_dat->gpio = template->gpio;
89 
90 	led_dat->cdev.brightness_set_blocking = lt3593_led_set;
91 
92 	state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
93 	led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
94 
95 	if (!template->retain_state_suspended)
96 		led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
97 
98 	ret = devm_gpio_request_one(parent, template->gpio, state ?
99 				    GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
100 				    template->name);
101 	if (ret < 0)
102 		return ret;
103 
104 	ret = led_classdev_register(parent, &led_dat->cdev);
105 	if (ret < 0)
106 		return ret;
107 
108 	dev_info(parent, "%s: registered LT3593 LED '%s' at GPIO %d\n",
109 		KBUILD_MODNAME, template->name, template->gpio);
110 
111 	return 0;
112 }
113 
114 static void delete_lt3593_led(struct lt3593_led_data *led)
115 {
116 	if (!gpio_is_valid(led->gpio))
117 		return;
118 
119 	led_classdev_unregister(&led->cdev);
120 }
121 
122 static int lt3593_led_probe(struct platform_device *pdev)
123 {
124 	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
125 	struct lt3593_led_data *leds_data;
126 	int i, ret = 0;
127 
128 	if (!pdata)
129 		return -EBUSY;
130 
131 	leds_data = devm_kcalloc(&pdev->dev,
132 			pdata->num_leds, sizeof(struct lt3593_led_data),
133 			GFP_KERNEL);
134 	if (!leds_data)
135 		return -ENOMEM;
136 
137 	for (i = 0; i < pdata->num_leds; i++) {
138 		ret = create_lt3593_led(&pdata->leds[i], &leds_data[i],
139 				      &pdev->dev);
140 		if (ret < 0)
141 			goto err;
142 	}
143 
144 	platform_set_drvdata(pdev, leds_data);
145 
146 	return 0;
147 
148 err:
149 	for (i = i - 1; i >= 0; i--)
150 		delete_lt3593_led(&leds_data[i]);
151 
152 	return ret;
153 }
154 
155 static int lt3593_led_remove(struct platform_device *pdev)
156 {
157 	int i;
158 	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
159 	struct lt3593_led_data *leds_data;
160 
161 	leds_data = platform_get_drvdata(pdev);
162 
163 	for (i = 0; i < pdata->num_leds; i++)
164 		delete_lt3593_led(&leds_data[i]);
165 
166 	return 0;
167 }
168 
169 static struct platform_driver lt3593_led_driver = {
170 	.probe		= lt3593_led_probe,
171 	.remove		= lt3593_led_remove,
172 	.driver		= {
173 		.name	= "leds-lt3593",
174 	},
175 };
176 
177 module_platform_driver(lt3593_led_driver);
178 
179 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
180 MODULE_DESCRIPTION("LED driver for LT3593 controllers");
181 MODULE_LICENSE("GPL");
182 MODULE_ALIAS("platform:leds-lt3593");
183