aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/leds/leds-gpio.c80
-rw-r--r--include/linux/leds.h1
2 files changed, 46 insertions, 35 deletions
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b4518c8751c8..1ff95ce9487a 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -12,6 +12,7 @@
12 */ 12 */
13#include <linux/err.h> 13#include <linux/err.h>
14#include <linux/gpio.h> 14#include <linux/gpio.h>
15#include <linux/gpio/consumer.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#include <linux/leds.h> 17#include <linux/leds.h>
17#include <linux/module.h> 18#include <linux/module.h>
@@ -24,11 +25,10 @@
24 25
25struct gpio_led_data { 26struct gpio_led_data {
26 struct led_classdev cdev; 27 struct led_classdev cdev;
27 unsigned gpio; 28 struct gpio_desc *gpiod;
28 struct work_struct work; 29 struct work_struct work;
29 u8 new_level; 30 u8 new_level;
30 u8 can_sleep; 31 u8 can_sleep;
31 u8 active_low;
32 u8 blinking; 32 u8 blinking;
33 int (*platform_gpio_blink_set)(unsigned gpio, int state, 33 int (*platform_gpio_blink_set)(unsigned gpio, int state,
34 unsigned long *delay_on, unsigned long *delay_off); 34 unsigned long *delay_on, unsigned long *delay_off);
@@ -40,12 +40,16 @@ static void gpio_led_work(struct work_struct *work)
40 container_of(work, struct gpio_led_data, work); 40 container_of(work, struct gpio_led_data, work);
41 41
42 if (led_dat->blinking) { 42 if (led_dat->blinking) {
43 led_dat->platform_gpio_blink_set(led_dat->gpio, 43 int gpio = desc_to_gpio(led_dat->gpiod);
44 led_dat->new_level, 44 int level = led_dat->new_level;
45 NULL, NULL); 45
46 if (gpiod_is_active_low(led_dat->gpiod))
47 level = !level;
48
49 led_dat->platform_gpio_blink_set(gpio, level, NULL, NULL);
46 led_dat->blinking = 0; 50 led_dat->blinking = 0;
47 } else 51 } else
48 gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); 52 gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
49} 53}
50 54
51static void gpio_led_set(struct led_classdev *led_cdev, 55static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +64,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
60 else 64 else
61 level = 1; 65 level = 1;
62 66
63 if (led_dat->active_low)
64 level = !level;
65
66 /* Setting GPIOs with I2C/etc requires a task context, and we don't 67 /* Setting GPIOs with I2C/etc requires a task context, and we don't
67 * seem to have a reliable way to know if we're already in one; so 68 * seem to have a reliable way to know if we're already in one; so
68 * let's just assume the worst. 69 * let's just assume the worst.
@@ -72,11 +73,16 @@ static void gpio_led_set(struct led_classdev *led_cdev,
72 schedule_work(&led_dat->work); 73 schedule_work(&led_dat->work);
73 } else { 74 } else {
74 if (led_dat->blinking) { 75 if (led_dat->blinking) {
75 led_dat->platform_gpio_blink_set(led_dat->gpio, level, 76 int gpio = desc_to_gpio(led_dat->gpiod);
76 NULL, NULL); 77
78 if (gpiod_is_active_low(led_dat->gpiod))
79 level = !level;
80
81 led_dat->platform_gpio_blink_set(gpio, level, NULL,
82 NULL);
77 led_dat->blinking = 0; 83 led_dat->blinking = 0;
78 } else 84 } else
79 gpio_set_value(led_dat->gpio, level); 85 gpiod_set_value(led_dat->gpiod, level);
80 } 86 }
81} 87}
82 88
@@ -85,9 +91,10 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
85{ 91{
86 struct gpio_led_data *led_dat = 92 struct gpio_led_data *led_dat =
87 container_of(led_cdev, struct gpio_led_data, cdev); 93 container_of(led_cdev, struct gpio_led_data, cdev);
94 int gpio = desc_to_gpio(led_dat->gpiod);
88 95
89 led_dat->blinking = 1; 96 led_dat->blinking = 1;
90 return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK, 97 return led_dat->platform_gpio_blink_set(gpio, GPIO_LED_BLINK,
91 delay_on, delay_off); 98 delay_on, delay_off);
92} 99}
93 100
@@ -97,24 +104,33 @@ static int create_gpio_led(const struct gpio_led *template,
97{ 104{
98 int ret, state; 105 int ret, state;
99 106
100 led_dat->gpio = -1; 107 if (!template->gpiod) {
108 unsigned long flags = 0;
101 109
102 /* skip leds that aren't available */ 110 /* skip leds that aren't available */
103 if (!gpio_is_valid(template->gpio)) { 111 if (!gpio_is_valid(template->gpio)) {
104 dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n", 112 dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
105 template->gpio, template->name); 113 template->gpio, template->name);
106 return 0; 114 return 0;
107 } 115 }
108 116
109 ret = devm_gpio_request(parent, template->gpio, template->name); 117 if (template->active_low)
110 if (ret < 0) 118 flags |= GPIOF_ACTIVE_LOW;
111 return ret; 119
120 ret = devm_gpio_request_one(parent, template->gpio, flags,
121 template->name);
122 if (ret < 0)
123 return ret;
124
125 led_dat->gpiod = gpio_to_desc(template->gpio);
126 if (IS_ERR(led_dat->gpiod))
127 return PTR_ERR(led_dat->gpiod);
128 }
112 129
113 led_dat->cdev.name = template->name; 130 led_dat->cdev.name = template->name;
114 led_dat->cdev.default_trigger = template->default_trigger; 131 led_dat->cdev.default_trigger = template->default_trigger;
115 led_dat->gpio = template->gpio; 132 led_dat->gpiod = template->gpiod;
116 led_dat->can_sleep = gpio_cansleep(template->gpio); 133 led_dat->can_sleep = gpiod_cansleep(template->gpiod);
117 led_dat->active_low = template->active_low;
118 led_dat->blinking = 0; 134 led_dat->blinking = 0;
119 if (blink_set) { 135 if (blink_set) {
120 led_dat->platform_gpio_blink_set = blink_set; 136 led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +138,24 @@ static int create_gpio_led(const struct gpio_led *template,
122 } 138 }
123 led_dat->cdev.brightness_set = gpio_led_set; 139 led_dat->cdev.brightness_set = gpio_led_set;
124 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) 140 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
125 state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low; 141 state = !!gpiod_get_value_cansleep(led_dat->gpiod);
126 else 142 else
127 state = (template->default_state == LEDS_GPIO_DEFSTATE_ON); 143 state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
128 led_dat->cdev.brightness = state ? LED_FULL : LED_OFF; 144 led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
129 if (!template->retain_state_suspended) 145 if (!template->retain_state_suspended)
130 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; 146 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
131 147
132 ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); 148 ret = gpiod_direction_output(led_dat->gpiod, state);
133 if (ret < 0) 149 if (ret < 0)
134 return ret; 150 return ret;
135 151
136 INIT_WORK(&led_dat->work, gpio_led_work); 152 INIT_WORK(&led_dat->work, gpio_led_work);
137 153
138 ret = led_classdev_register(parent, &led_dat->cdev); 154 return led_classdev_register(parent, &led_dat->cdev);
139 if (ret < 0)
140 return ret;
141
142 return 0;
143} 155}
144 156
145static void delete_gpio_led(struct gpio_led_data *led) 157static void delete_gpio_led(struct gpio_led_data *led)
146{ 158{
147 if (!gpio_is_valid(led->gpio))
148 return;
149 led_classdev_unregister(&led->cdev); 159 led_classdev_unregister(&led->cdev);
150 cancel_work_sync(&led->work); 160 cancel_work_sync(&led->work);
151} 161}
diff --git a/include/linux/leds.h b/include/linux/leds.h
index a57611d0c94e..f3af5c4d9084 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -261,6 +261,7 @@ struct gpio_led {
261 unsigned retain_state_suspended : 1; 261 unsigned retain_state_suspended : 1;
262 unsigned default_state : 2; 262 unsigned default_state : 2;
263 /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ 263 /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
264 struct gpio_desc *gpiod;
264}; 265};
265#define LEDS_GPIO_DEFSTATE_OFF 0 266#define LEDS_GPIO_DEFSTATE_OFF 0
266#define LEDS_GPIO_DEFSTATE_ON 1 267#define LEDS_GPIO_DEFSTATE_ON 1