|
37 | 37 | * bits the chip supports. |
38 | 38 | */ |
39 | 39 |
|
| 40 | +#include <linux/bitops.h> |
40 | 41 | #include <linux/ctype.h> |
41 | 42 | #include <linux/delay.h> |
42 | 43 | #include <linux/err.h> |
@@ -118,6 +119,7 @@ struct pca955x { |
118 | 119 | struct pca955x_led *leds; |
119 | 120 | struct pca955x_chipdef *chipdef; |
120 | 121 | struct i2c_client *client; |
| 122 | + unsigned long active_pins; |
121 | 123 | #ifdef CONFIG_LEDS_PCA955X_GPIO |
122 | 124 | struct gpio_chip gpio; |
123 | 125 | #endif |
@@ -360,12 +362,15 @@ static int pca955x_read_input(struct i2c_client *client, int n, u8 *val) |
360 | 362 | static int pca955x_gpio_request_pin(struct gpio_chip *gc, unsigned int offset) |
361 | 363 | { |
362 | 364 | struct pca955x *pca955x = gpiochip_get_data(gc); |
363 | | - struct pca955x_led *led = &pca955x->leds[offset]; |
364 | 365 |
|
365 | | - if (led->type == PCA955X_TYPE_GPIO) |
366 | | - return 0; |
| 366 | + return test_and_set_bit(offset, &pca955x->active_pins) ? -EBUSY : 0; |
| 367 | +} |
| 368 | + |
| 369 | +static void pca955x_gpio_free_pin(struct gpio_chip *gc, unsigned int offset) |
| 370 | +{ |
| 371 | + struct pca955x *pca955x = gpiochip_get_data(gc); |
367 | 372 |
|
368 | | - return -EBUSY; |
| 373 | + clear_bit(offset, &pca955x->active_pins); |
369 | 374 | } |
370 | 375 |
|
371 | 376 | static int pca955x_set_value(struct gpio_chip *gc, unsigned int offset, |
@@ -424,7 +429,7 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip) |
424 | 429 | int count; |
425 | 430 |
|
426 | 431 | count = device_get_child_node_count(&client->dev); |
427 | | - if (!count || count > chip->bits) |
| 432 | + if (count > chip->bits) |
428 | 433 | return ERR_PTR(-ENODEV); |
429 | 434 |
|
430 | 435 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); |
@@ -489,7 +494,6 @@ static int pca955x_probe(struct i2c_client *client) |
489 | 494 | struct i2c_adapter *adapter; |
490 | 495 | int i, err; |
491 | 496 | struct pca955x_platform_data *pdata; |
492 | | - int ngpios = 0; |
493 | 497 | bool set_default_label = false; |
494 | 498 | bool keep_pwm = false; |
495 | 499 | char default_label[8]; |
@@ -567,9 +571,7 @@ static int pca955x_probe(struct i2c_client *client) |
567 | 571 |
|
568 | 572 | switch (pca955x_led->type) { |
569 | 573 | case PCA955X_TYPE_NONE: |
570 | | - break; |
571 | 574 | case PCA955X_TYPE_GPIO: |
572 | | - ngpios++; |
573 | 575 | break; |
574 | 576 | case PCA955X_TYPE_LED: |
575 | 577 | led = &pca955x_led->led_cdev; |
@@ -613,6 +615,8 @@ static int pca955x_probe(struct i2c_client *client) |
613 | 615 | if (err) |
614 | 616 | return err; |
615 | 617 |
|
| 618 | + set_bit(i, &pca955x->active_pins); |
| 619 | + |
616 | 620 | /* |
617 | 621 | * For default-state == "keep", let the core update the |
618 | 622 | * brightness from the hardware, then check the |
@@ -650,31 +654,30 @@ static int pca955x_probe(struct i2c_client *client) |
650 | 654 | return err; |
651 | 655 |
|
652 | 656 | #ifdef CONFIG_LEDS_PCA955X_GPIO |
653 | | - if (ngpios) { |
654 | | - pca955x->gpio.label = "gpio-pca955x"; |
655 | | - pca955x->gpio.direction_input = pca955x_gpio_direction_input; |
656 | | - pca955x->gpio.direction_output = pca955x_gpio_direction_output; |
657 | | - pca955x->gpio.set = pca955x_gpio_set_value; |
658 | | - pca955x->gpio.get = pca955x_gpio_get_value; |
659 | | - pca955x->gpio.request = pca955x_gpio_request_pin; |
660 | | - pca955x->gpio.can_sleep = 1; |
661 | | - pca955x->gpio.base = -1; |
662 | | - pca955x->gpio.ngpio = ngpios; |
663 | | - pca955x->gpio.parent = &client->dev; |
664 | | - pca955x->gpio.owner = THIS_MODULE; |
665 | | - |
666 | | - err = devm_gpiochip_add_data(&client->dev, &pca955x->gpio, |
667 | | - pca955x); |
668 | | - if (err) { |
669 | | - /* Use data->gpio.dev as a flag for freeing gpiochip */ |
670 | | - pca955x->gpio.parent = NULL; |
671 | | - dev_warn(&client->dev, "could not add gpiochip\n"); |
672 | | - return err; |
673 | | - } |
674 | | - dev_info(&client->dev, "gpios %i...%i\n", |
675 | | - pca955x->gpio.base, pca955x->gpio.base + |
676 | | - pca955x->gpio.ngpio - 1); |
| 657 | + pca955x->gpio.label = "gpio-pca955x"; |
| 658 | + pca955x->gpio.direction_input = pca955x_gpio_direction_input; |
| 659 | + pca955x->gpio.direction_output = pca955x_gpio_direction_output; |
| 660 | + pca955x->gpio.set = pca955x_gpio_set_value; |
| 661 | + pca955x->gpio.get = pca955x_gpio_get_value; |
| 662 | + pca955x->gpio.request = pca955x_gpio_request_pin; |
| 663 | + pca955x->gpio.free = pca955x_gpio_free_pin; |
| 664 | + pca955x->gpio.can_sleep = 1; |
| 665 | + pca955x->gpio.base = -1; |
| 666 | + pca955x->gpio.ngpio = chip->bits; |
| 667 | + pca955x->gpio.parent = &client->dev; |
| 668 | + pca955x->gpio.owner = THIS_MODULE; |
| 669 | + |
| 670 | + err = devm_gpiochip_add_data(&client->dev, &pca955x->gpio, |
| 671 | + pca955x); |
| 672 | + if (err) { |
| 673 | + /* Use data->gpio.dev as a flag for freeing gpiochip */ |
| 674 | + pca955x->gpio.parent = NULL; |
| 675 | + dev_warn(&client->dev, "could not add gpiochip\n"); |
| 676 | + return err; |
677 | 677 | } |
| 678 | + dev_info(&client->dev, "gpios %i...%i\n", |
| 679 | + pca955x->gpio.base, pca955x->gpio.base + |
| 680 | + pca955x->gpio.ngpio - 1); |
678 | 681 | #endif |
679 | 682 |
|
680 | 683 | return 0; |
|
0 commit comments