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

Configure Feed

Select the types of activity you want to include in your feed.

misc: ti_fpc202: Support special-purpose GPIO lines with LED features

The FPC202 dual port controller has 20 regular GPIO lines and 8 special
GPIO lines with LED features. Each one of these "LED GPIOs" can output PWM
and blink signals.

Add support for the eight special-purpose GPIO lines to the existing FPC202
driver's GPIO support. Add support for registering led-class devices on
these GPIO lines.

Signed-off-by: Romain Gantois <romain.gantois@bootlin.com>
Link: https://patch.msgid.link/20260331-fpc202-leds-v3-3-74b173537d42@bootlin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Romain Gantois and committed by
Greg Kroah-Hartman
2a8c2080 7bc51528

+327 -13
+1
drivers/misc/Kconfig
··· 117 117 tristate "TI FPC202 Dual Port Controller" 118 118 depends on I2C 119 119 depends on GPIOLIB 120 + depends on LEDS_CLASS 120 121 select I2C_ATR 121 122 help 122 123 If you say yes here you get support for the Texas Instruments FPC202
+326 -13
drivers/misc/ti_fpc202.c
··· 7 7 */ 8 8 9 9 #include <linux/cleanup.h> 10 + #include <linux/device/devres.h> 10 11 #include <linux/err.h> 11 12 #include <linux/i2c.h> 12 13 #include <linux/i2c-atr.h> 13 14 #include <linux/gpio/consumer.h> 14 15 #include <linux/gpio/driver.h> 16 + #include <linux/gpio/machine.h> 17 + #include <linux/leds.h> 15 18 #include <linux/module.h> 19 + #include <linux/math.h> 20 + #include <linux/types.h> 16 21 17 22 #define FPC202_NUM_PORTS 2 18 23 #define FPC202_ALIASES_PER_PORT 2 ··· 39 34 * ... 40 35 * 19: P1_S1_OUT_B 41 36 * 37 + * Ports with optional LED control: 38 + * 39 + * 20: P0_S0_OUT_C (P0_S0_LED1) 40 + * ... 41 + * 23: P1_S1_OUT_C (P1_S1_LED1) 42 + * 24: P0_S0_OUT_D (P0_S0_LED2 43 + * ... 44 + * 27: P1_S1_OUT_D (P1_S1_LED2) 45 + * 42 46 */ 43 47 44 - #define FPC202_GPIO_COUNT 20 48 + #define FPC202_GPIO_COUNT 28 45 49 #define FPC202_GPIO_P0_S0_IN_B 4 46 50 #define FPC202_GPIO_P0_S0_OUT_A 12 51 + #define FPC202_GPIO_P0_S0_OUT_C 20 52 + #define FPC202_GPIO_P0_S0_OUT_D 24 47 53 48 54 #define FPC202_REG_IN_A_INT 0x6 49 55 #define FPC202_REG_IN_C_IN_B 0x7 50 56 #define FPC202_REG_OUT_A_OUT_B 0x8 57 + #define FPC202_REG_OUT_C_OUT_D 0x9 51 58 52 59 #define FPC202_REG_OUT_A_OUT_B_VAL 0xa 60 + 61 + #define FPC202_LED_COUNT 8 62 + 63 + /* There are four LED GPIO mode registers which manage two GPIOs each. */ 64 + #define FPC202_REG_LED_MODE(offset) (0x1a + 0x20 * ((offset) % 4)) 65 + 66 + /* LED1 GPIOs (*_OUT_C) are configured in bits 1:0, LED2 GPIOs (*_OUT_D) in bits 3:2. */ 67 + #define FPC202_LED_MODE_SHIFT(offset) ((offset) < FPC202_GPIO_P0_S0_OUT_D ? 0 : 2) 68 + #define FPC202_LED_MODE_MASK(offset) (GENMASK(1, 0) << FPC202_LED_MODE_SHIFT(offset)) 69 + 70 + /* There is one PWM control register for each GPIO LED */ 71 + #define FPC202_REG_LED_PWM(offset) \ 72 + (((offset) < FPC202_GPIO_P0_S0_OUT_D ? 0x14 : 0x15) + 0x20 * ((offset) % 4)) 73 + 74 + /* There are two blink delay registers (on/off time) for each GPIO LED */ 75 + #define FPC202_REG_LED_BLINK_ON(offset) \ 76 + (((offset) < FPC202_GPIO_P0_S0_OUT_D ? 0x16 : 0x18) + 0x20 * ((offset) % 4)) 77 + #define FPC202_REG_LED_BLINK_OFF(offset) (FPC202_REG_LED_BLINK_ON(offset) + 1) 78 + 79 + /* The actual hardware precision is 2.5ms but since the LED API doesn't handle sub-millisecond 80 + * timesteps this is rounded up to 5ms 81 + */ 82 + #define FPC202_LED_BLINK_PRECISION 5UL 83 + 84 + #define FPC202_LED_MAX_BRIGHTNESS 255 53 85 54 86 #define FPC202_REG_MOD_DEV(port, dev) (0xb4 + ((port) * 4) + (dev)) 55 87 #define FPC202_REG_AUX_DEV(port, dev) (0xb6 + ((port) * 4) + (dev)) ··· 101 59 /* Even aliases are assigned to device 0 and odd aliases to device 1 */ 102 60 #define fpc202_dev_num_from_alias(alias) ((alias) % 2) 103 61 62 + enum fpc202_led_mode { 63 + FPC202_LED_MODE_OFF = 0, 64 + FPC202_LED_MODE_ON = 1, 65 + FPC202_LED_MODE_PWM = 2, 66 + FPC202_LED_MODE_BLINK = 3, 67 + }; 68 + 69 + struct fpc202_led { 70 + int offset; 71 + struct led_classdev led_cdev; 72 + struct fpc202_priv *priv; 73 + struct gpio_desc *gpio; 74 + enum fpc202_led_mode mode; 75 + }; 76 + 104 77 struct fpc202_priv { 105 78 struct i2c_client *client; 106 79 struct i2c_atr *atr; 107 80 struct gpio_desc *en_gpio; 108 81 struct gpio_chip gpio; 82 + struct fpc202_led leds[FPC202_LED_COUNT]; 109 83 110 84 /* Lock REG_MOD/AUX_DEV and addr_caches during attach/detach */ 111 85 struct mutex reg_dev_lock; 86 + 87 + /* Lock LED mode select register during accesses */ 88 + struct mutex led_mode_lock; 112 89 113 90 /* Cached device addresses for both ports and their devices */ 114 91 u8 addr_caches[2][2]; ··· 158 97 return offset < FPC202_GPIO_P0_S0_OUT_A ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; 159 98 } 160 99 100 + static int fpc202_gpio_has_led_caps(int offset) 101 + { 102 + return offset >= FPC202_GPIO_P0_S0_OUT_C; 103 + } 104 + 161 105 static int fpc202_read(struct fpc202_priv *priv, u8 reg) 162 106 { 163 107 int val; ··· 184 118 gpiod_set_value(priv->en_gpio, enable); 185 119 } 186 120 121 + static int fpc202_led_mode_write(struct fpc202_priv *priv, 122 + int offset, 123 + enum fpc202_led_mode mode) 124 + { 125 + u8 val, reg = FPC202_REG_LED_MODE(offset); 126 + int ret; 127 + 128 + guard(mutex)(&priv->led_mode_lock); 129 + 130 + ret = fpc202_read(priv, reg); 131 + if (ret < 0) { 132 + dev_err(&priv->client->dev, "failed to read LED mode %d! err %d\n", 133 + offset, ret); 134 + return ret; 135 + } 136 + 137 + val = (u8)ret & ~FPC202_LED_MODE_MASK(offset); 138 + val |= mode << FPC202_LED_MODE_SHIFT(offset); 139 + 140 + return fpc202_write(priv, reg, val); 141 + } 142 + 143 + static int fpc202_led_mode_set(struct fpc202_led *led, enum fpc202_led_mode mode) 144 + { 145 + struct fpc202_priv *priv = led->priv; 146 + 147 + led->mode = mode; 148 + 149 + return fpc202_led_mode_write(priv, led->offset, mode); 150 + } 151 + 187 152 static int fpc202_gpio_set(struct gpio_chip *chip, unsigned int offset, 188 153 int value) 189 154 { 190 155 struct fpc202_priv *priv = gpiochip_get_data(chip); 191 156 int ret; 192 157 u8 val; 158 + 159 + if (fpc202_gpio_has_led_caps(offset)) { 160 + ret = fpc202_led_mode_write(priv, offset, 161 + value ? FPC202_LED_MODE_ON : FPC202_LED_MODE_OFF); 162 + if (ret < 0) 163 + dev_err(&priv->client->dev, "Failed to set GPIO %d LED mode! err %d\n", 164 + offset, ret); 165 + 166 + return ret; 167 + } 193 168 194 169 ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B_VAL); 195 170 if (ret < 0) { ··· 260 153 } else if (offset < FPC202_GPIO_P0_S0_OUT_A) { 261 154 reg = FPC202_REG_IN_C_IN_B; 262 155 bit = BIT(offset - FPC202_GPIO_P0_S0_IN_B); 263 - } else { 156 + } else if (!fpc202_gpio_has_led_caps(offset)) { 264 157 reg = FPC202_REG_OUT_A_OUT_B_VAL; 265 158 bit = BIT(offset - FPC202_GPIO_P0_S0_OUT_A); 159 + } else { 160 + return -EOPNOTSUPP; 266 161 } 267 162 268 163 ret = fpc202_read(priv, reg); ··· 286 177 int value) 287 178 { 288 179 struct fpc202_priv *priv = gpiochip_get_data(chip); 180 + u8 reg, val, bit; 289 181 int ret; 290 - u8 val; 291 182 292 183 if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_IN) 293 184 return -EINVAL; 294 185 295 186 fpc202_gpio_set(chip, offset, value); 296 187 297 - ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B); 188 + if (fpc202_gpio_has_led_caps(offset)) { 189 + reg = FPC202_REG_OUT_C_OUT_D; 190 + bit = BIT(offset - FPC202_GPIO_P0_S0_OUT_C); 191 + } else { 192 + reg = FPC202_REG_OUT_A_OUT_B; 193 + bit = BIT(offset - FPC202_GPIO_P0_S0_OUT_A); 194 + } 195 + 196 + ret = fpc202_read(priv, reg); 298 197 if (ret < 0) 299 198 return ret; 300 199 301 - val = (u8)ret | BIT(offset - FPC202_GPIO_P0_S0_OUT_A); 200 + val = (u8)ret | bit; 302 201 303 - return fpc202_write(priv, FPC202_REG_OUT_A_OUT_B, val); 202 + return fpc202_write(priv, reg, val); 304 203 } 305 204 306 205 /* ··· 381 264 .detach_addr = fpc202_detach_addr, 382 265 }; 383 266 267 + static struct fpc202_led *fpc202_cdev_to_led(struct led_classdev *cdev) 268 + { 269 + return container_of(cdev, struct fpc202_led, led_cdev); 270 + } 271 + 272 + static struct fpc202_led *fpc202_led_get(struct fpc202_priv *priv, int offset) 273 + { 274 + return &priv->leds[offset - FPC202_GPIO_P0_S0_OUT_C]; 275 + } 276 + 277 + static int fpc202_led_blink_set(struct led_classdev *cdev, 278 + unsigned long *delay_on, 279 + unsigned long *delay_off) 280 + { 281 + struct fpc202_led *led = fpc202_cdev_to_led(cdev); 282 + struct fpc202_priv *priv = led->priv; 283 + unsigned long val; 284 + int ret; 285 + 286 + if (*delay_on == 0 && *delay_off == 0) { 287 + *delay_on = 250; 288 + *delay_off = 250; 289 + } else { 290 + if (*delay_on % FPC202_LED_BLINK_PRECISION) 291 + *delay_on = roundup(*delay_on, FPC202_LED_BLINK_PRECISION); 292 + 293 + if (*delay_off % FPC202_LED_BLINK_PRECISION) 294 + *delay_off = roundup(*delay_off, FPC202_LED_BLINK_PRECISION); 295 + } 296 + 297 + /* Multiply the duration by two, since the actual precision is 2.5ms not 5ms*/ 298 + val = 2 * (*delay_on / FPC202_LED_BLINK_PRECISION); 299 + if (val > 255) { 300 + val = 255; 301 + *delay_on = (val / 2) * FPC202_LED_BLINK_PRECISION; 302 + } 303 + 304 + ret = fpc202_write(priv, FPC202_REG_LED_BLINK_ON(led->offset), val); 305 + if (ret) { 306 + dev_err(&priv->client->dev, 307 + "Failed to set blink on duration for LED %d, err %d\n", 308 + led->offset, ret); 309 + return ret; 310 + } 311 + 312 + val = 2 * (*delay_off / FPC202_LED_BLINK_PRECISION); 313 + if (val > 255) { 314 + val = 255; 315 + *delay_off = (val / 2) * FPC202_LED_BLINK_PRECISION; 316 + } 317 + 318 + ret = fpc202_write(priv, FPC202_REG_LED_BLINK_OFF(led->offset), val); 319 + if (ret) { 320 + dev_err(&priv->client->dev, 321 + "Failed to set blink off duration for LED %d, err %d\n", 322 + led->offset, ret); 323 + return ret; 324 + } 325 + 326 + return fpc202_led_mode_set(led, FPC202_LED_MODE_BLINK); 327 + } 328 + 329 + static enum led_brightness fpc202_led_brightness_get(struct led_classdev *cdev) 330 + { 331 + struct fpc202_led *led = fpc202_cdev_to_led(cdev); 332 + 333 + if (led->mode == FPC202_LED_MODE_OFF) 334 + return LED_OFF; 335 + 336 + return LED_ON; 337 + } 338 + 339 + static int fpc202_led_brightness_set(struct led_classdev *cdev, 340 + enum led_brightness brightness) 341 + { 342 + struct fpc202_led *led = fpc202_cdev_to_led(cdev); 343 + struct fpc202_priv *priv = led->priv; 344 + int ret; 345 + 346 + if (!brightness) 347 + return fpc202_led_mode_set(led, FPC202_LED_MODE_OFF); 348 + 349 + if (led->mode != FPC202_LED_MODE_BLINK) { 350 + if (brightness == FPC202_LED_MAX_BRIGHTNESS) 351 + return fpc202_led_mode_set(led, FPC202_LED_MODE_ON); 352 + 353 + ret = fpc202_led_mode_set(led, FPC202_LED_MODE_PWM); 354 + if (ret) { 355 + dev_err(&priv->client->dev, "Failed to set LED %d mode, err %d\n", 356 + led->offset, ret); 357 + return ret; 358 + } 359 + } 360 + 361 + return fpc202_write(priv, FPC202_REG_LED_PWM(led->offset), brightness); 362 + } 363 + 364 + static int fpc202_register_led(struct fpc202_priv *priv, int offset, 365 + struct device_node *led_handle) 366 + { 367 + struct fpc202_led *led = fpc202_led_get(priv, offset); 368 + struct device *dev = &priv->client->dev; 369 + struct led_init_data init_data = { }; 370 + int ret = 0; 371 + 372 + led->priv = priv; 373 + led->offset = offset; 374 + led->led_cdev.max_brightness = FPC202_LED_MAX_BRIGHTNESS; 375 + led->led_cdev.brightness_set_blocking = fpc202_led_brightness_set; 376 + led->led_cdev.brightness_get = fpc202_led_brightness_get; 377 + led->led_cdev.blink_set = fpc202_led_blink_set; 378 + 379 + init_data.fwnode = of_fwnode_handle(led_handle); 380 + init_data.default_label = NULL; 381 + init_data.devicename = NULL; 382 + init_data.devname_mandatory = false; 383 + 384 + ret = fpc202_led_mode_set(led, FPC202_LED_MODE_OFF); 385 + if (ret) { 386 + dev_err(dev, "Failed to set LED %d mode, err %d\n", offset, ret); 387 + return ret; 388 + } 389 + 390 + ret = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); 391 + if (ret) { 392 + dev_err(dev, "Failed to register LED %d cdev, err %d\n", offset, ret); 393 + return ret; 394 + } 395 + 396 + /* Claim corresponding GPIO line so that it cannot be interfered with */ 397 + led->gpio = gpiochip_request_own_desc(&priv->gpio, offset, led->led_cdev.name, 398 + GPIO_ACTIVE_HIGH, GPIOD_ASIS); 399 + if (IS_ERR(led->gpio)) { 400 + ret = PTR_ERR(led->gpio); 401 + dev_err(dev, "Failed to register LED %d cdev, err %d\n", offset, ret); 402 + } 403 + 404 + return ret; 405 + } 406 + 407 + static int fpc202_register_leds(struct fpc202_priv *priv) 408 + { 409 + struct device *dev = &priv->client->dev; 410 + int offset, ret = 0; 411 + 412 + if (!devres_open_group(dev, fpc202_register_leds, GFP_KERNEL)) 413 + return -ENOMEM; 414 + 415 + for_each_child_of_node_scoped(dev->of_node, led_handle) { 416 + ret = of_property_read_u32(led_handle, "reg", &offset); 417 + if (ret) { 418 + dev_err(dev, "Failed to read 'reg' property of child node, err %d\n", ret); 419 + return ret; 420 + } 421 + 422 + if (offset < FPC202_GPIO_P0_S0_OUT_C || offset > FPC202_GPIO_COUNT) 423 + continue; 424 + 425 + ret = fpc202_register_led(priv, offset, led_handle); 426 + if (ret) { 427 + dev_err(dev, "Failed to register LED %d, err %d\n", offset, 428 + ret); 429 + goto free_own_gpios; 430 + } 431 + } 432 + 433 + devres_close_group(dev, fpc202_register_leds); 434 + 435 + return 0; 436 + 437 + free_own_gpios: 438 + for (offset = 0; offset < FPC202_LED_COUNT; offset++) 439 + if (priv->leds[offset].gpio) 440 + gpiochip_free_own_desc(priv->leds[offset].gpio); 441 + return ret; 442 + } 443 + 384 444 static int fpc202_probe_port(struct fpc202_priv *priv, struct device_node *i2c_handle, int port_id) 385 445 { 386 446 u16 aliases[FPC202_ALIASES_PER_PORT] = { }; ··· 596 302 { 597 303 struct device *dev = &client->dev; 598 304 struct fpc202_priv *priv; 599 - int ret, port_id; 305 + int ret, port_id, led_id; 600 306 601 307 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 602 308 if (!priv) 603 309 return -ENOMEM; 604 310 605 311 mutex_init(&priv->reg_dev_lock); 312 + mutex_init(&priv->led_mode_lock); 606 313 607 314 priv->client = client; 608 315 i2c_set_clientdata(client, priv); ··· 641 346 642 347 i2c_atr_set_driver_data(priv->atr, priv); 643 348 349 + ret = fpc202_register_leds(priv); 350 + if (ret) { 351 + dev_err(dev, "Failed to register LEDs, err %d\n", ret); 352 + goto delete_atr; 353 + } 354 + 644 355 bitmap_zero(priv->probed_ports, FPC202_NUM_PORTS); 645 356 646 357 for_each_child_of_node_scoped(dev->of_node, i2c_handle) { ··· 659 358 goto unregister_chans; 660 359 } 661 360 662 - if (port_id >= FPC202_NUM_PORTS) { 663 - dev_err(dev, "port ID %d is out of range!\n", port_id); 664 - ret = -EINVAL; 665 - goto unregister_chans; 666 - } 361 + if (port_id >= FPC202_NUM_PORTS) 362 + continue; 667 363 668 364 ret = fpc202_probe_port(priv, i2c_handle, port_id); 669 365 if (ret) { ··· 675 377 for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS) 676 378 fpc202_remove_port(priv, port_id); 677 379 380 + for (led_id = 0; led_id < FPC202_LED_COUNT; led_id++) 381 + if (priv->leds[led_id].gpio) 382 + gpiochip_free_own_desc(priv->leds[led_id].gpio); 383 + 384 + devres_release_group(&client->dev, fpc202_register_leds); 385 + delete_atr: 678 386 i2c_atr_delete(priv->atr); 679 387 disable_gpio: 680 388 fpc202_set_enable(priv, 0); 681 389 gpiochip_remove(&priv->gpio); 682 390 destroy_mutex: 391 + mutex_destroy(&priv->led_mode_lock); 683 392 mutex_destroy(&priv->reg_dev_lock); 684 393 out: 685 394 return ret; ··· 695 390 static void fpc202_remove(struct i2c_client *client) 696 391 { 697 392 struct fpc202_priv *priv = i2c_get_clientdata(client); 698 - int port_id; 393 + int port_id, led_id; 699 394 700 395 for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS) 701 396 fpc202_remove_port(priv, port_id); 702 397 398 + for (led_id = 0; led_id < FPC202_LED_COUNT; led_id++) 399 + if (priv->leds[led_id].gpio) 400 + gpiochip_free_own_desc(priv->leds[led_id].gpio); 401 + 402 + /* Release led devices early so that blink handlers don't trigger. */ 403 + devres_release_group(&client->dev, fpc202_register_leds); 404 + 405 + mutex_destroy(&priv->led_mode_lock); 703 406 mutex_destroy(&priv->reg_dev_lock); 704 407 705 408 i2c_atr_delete(priv->atr);