Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/warp: switch to using gpiod API

This switches PIKA Warp away from legacy gpio API and to newer gpiod
API, so that we can eventually deprecate the former.

Because LEDs are normally driven by leds-gpio driver, but the
platform code also wants to access the LEDs during thermal shutdown,
and gpiod API does not allow locating GPIO without requesting it,
the platform code is now responsible for locating GPIOs through device
tree and requesting them. It then constructs platform data for
leds-gpio platform device and registers it. This allows platform
code to retain access to LED GPIO descriptors and use them when needed.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/YzKSLcrYmV5kjyeX@google.com

authored by

Dmitry Torokhov and committed by
Michael Ellerman
1892e87a 1c4a4a4c

+94 -15
+1 -3
arch/powerpc/boot/dts/warp.dts
··· 258 258 }; 259 259 260 260 power-leds { 261 - compatible = "gpio-leds"; 261 + compatible = "warp-power-leds"; 262 262 green { 263 263 gpios = <&GPIO1 0 0>; 264 - default-state = "keep"; 265 264 }; 266 265 red { 267 266 gpios = <&GPIO1 1 0>; 268 - default-state = "keep"; 269 267 }; 270 268 }; 271 269
+93 -12
arch/powerpc/platforms/44x/warp.c
··· 5 5 * Copyright (c) 2008-2009 PIKA Technologies 6 6 * Sean MacLennan <smaclennan@pikatech.com> 7 7 */ 8 + #include <linux/err.h> 8 9 #include <linux/init.h> 9 10 #include <linux/of_platform.h> 10 11 #include <linux/kthread.h> 12 + #include <linux/leds.h> 11 13 #include <linux/i2c.h> 12 14 #include <linux/interrupt.h> 13 15 #include <linux/delay.h> 14 16 #include <linux/of_address.h> 15 17 #include <linux/of_irq.h> 16 - #include <linux/of_gpio.h> 18 + #include <linux/gpio/consumer.h> 17 19 #include <linux/slab.h> 18 20 #include <linux/export.h> 19 21 ··· 94 92 95 93 static LIST_HEAD(dtm_shutdown_list); 96 94 static void __iomem *dtm_fpga; 97 - static unsigned green_led, red_led; 98 - 99 95 100 96 struct dtm_shutdown { 101 97 struct list_head list; 102 98 void (*func)(void *arg); 103 99 void *arg; 104 100 }; 105 - 106 101 107 102 int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) 108 103 { ··· 131 132 return -EINVAL; 132 133 } 133 134 135 + #define WARP_GREEN_LED 0 136 + #define WARP_RED_LED 1 137 + 138 + static struct gpio_led warp_gpio_led_pins[] = { 139 + [WARP_GREEN_LED] = { 140 + .name = "green", 141 + .default_state = LEDS_DEFSTATE_KEEP, 142 + .gpiod = NULL, /* to be filled by pika_setup_leds() */ 143 + }, 144 + [WARP_RED_LED] = { 145 + .name = "red", 146 + .default_state = LEDS_DEFSTATE_KEEP, 147 + .gpiod = NULL, /* to be filled by pika_setup_leds() */ 148 + }, 149 + }; 150 + 151 + static struct gpio_led_platform_data warp_gpio_led_data = { 152 + .leds = warp_gpio_led_pins, 153 + .num_leds = ARRAY_SIZE(warp_gpio_led_pins), 154 + }; 155 + 156 + static struct platform_device warp_gpio_leds = { 157 + .name = "leds-gpio", 158 + .id = -1, 159 + .dev = { 160 + .platform_data = &warp_gpio_led_data, 161 + }, 162 + }; 163 + 134 164 static irqreturn_t temp_isr(int irq, void *context) 135 165 { 136 166 struct dtm_shutdown *shutdown; ··· 167 139 168 140 local_irq_disable(); 169 141 170 - gpio_set_value(green_led, 0); 142 + gpiod_set_value(warp_gpio_led_pins[WARP_GREEN_LED].gpiod, 0); 171 143 172 144 /* Run through the shutdown list. */ 173 145 list_for_each_entry(shutdown, &dtm_shutdown_list, list) ··· 181 153 out_be32(dtm_fpga + 0x14, reset); 182 154 } 183 155 184 - gpio_set_value(red_led, value); 156 + gpiod_set_value(warp_gpio_led_pins[WARP_RED_LED].gpiod, value); 185 157 value ^= 1; 186 158 mdelay(500); 187 159 } ··· 190 162 return IRQ_HANDLED; 191 163 } 192 164 165 + /* 166 + * Because green and red power LEDs are normally driven by leds-gpio driver, 167 + * but in case of critical temperature shutdown we want to drive them 168 + * ourselves, we acquire both and then create leds-gpio platform device 169 + * ourselves, instead of doing it through device tree. This way we can still 170 + * keep access to the gpios and use them when needed. 171 + */ 193 172 static int pika_setup_leds(void) 194 173 { 195 174 struct device_node *np, *child; 175 + struct gpio_desc *gpio; 176 + struct gpio_led *led; 177 + int led_count = 0; 178 + int error; 179 + int i; 196 180 197 - np = of_find_compatible_node(NULL, NULL, "gpio-leds"); 181 + np = of_find_compatible_node(NULL, NULL, "warp-power-leds"); 198 182 if (!np) { 199 183 printk(KERN_ERR __FILE__ ": Unable to find leds\n"); 200 184 return -ENOENT; 201 185 } 202 186 203 - for_each_child_of_node(np, child) 204 - if (of_node_name_eq(child, "green")) 205 - green_led = of_get_gpio(child, 0); 206 - else if (of_node_name_eq(child, "red")) 207 - red_led = of_get_gpio(child, 0); 187 + for_each_child_of_node(np, child) { 188 + for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) { 189 + led = &warp_gpio_led_pins[i]; 190 + 191 + if (!of_node_name_eq(child, led->name)) 192 + continue; 193 + 194 + if (led->gpiod) { 195 + printk(KERN_ERR __FILE__ ": %s led has already been defined\n", 196 + led->name); 197 + continue; 198 + } 199 + 200 + gpio = fwnode_gpiod_get_index(of_fwnode_handle(child), 201 + NULL, 0, GPIOD_ASIS, 202 + led->name); 203 + error = PTR_ERR_OR_ZERO(gpio); 204 + if (error) { 205 + printk(KERN_ERR __FILE__ ": Failed to get %s led gpio: %d\n", 206 + led->name, error); 207 + of_node_put(child); 208 + goto err_cleanup_pins; 209 + } 210 + 211 + led->gpiod = gpio; 212 + led_count++; 213 + } 214 + } 208 215 209 216 of_node_put(np); 210 217 218 + /* Skip device registration if no leds have been defined */ 219 + if (led_count) { 220 + error = platform_device_register(&warp_gpio_leds); 221 + if (error) { 222 + printk(KERN_ERR __FILE__ ": Unable to add leds-gpio: %d\n", 223 + error); 224 + goto err_cleanup_pins; 225 + } 226 + } 227 + 211 228 return 0; 229 + 230 + err_cleanup_pins: 231 + for (i = 0; i < ARRAY_SIZE(warp_gpio_led_pins); i++) { 232 + led = &warp_gpio_led_pins[i]; 233 + gpiod_put(led->gpiod); 234 + led->gpiod = NULL; 235 + } 236 + return error; 212 237 } 213 238 214 239 static void pika_setup_critical_temp(struct device_node *np,