diff options
Diffstat (limited to 'drivers/leds/leds-tca6507.c')
| -rw-r--r-- | drivers/leds/leds-tca6507.c | 169 |
1 files changed, 56 insertions, 113 deletions
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 45222a7f4f75..fd0e8bab9a4b 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * leds-tca6507 * @@ -68,23 +69,6 @@ * defaulted. Similarly the banks know if each time was explicit or a * default. Defaults are permitted to be changed freely - they are * not recognised when matching. - * - * - * An led-tca6507 device must be provided with platform data or - * configured via devicetree. - * - * The platform-data lists for each output: the name, default trigger, - * and whether the signal is being used as a GPIO rather than an LED. - * 'struct led_plaform_data' is used for this. If 'name' is NULL, the - * output isn't used. If 'flags' is TCA6507_MAKE_GPIO, the output is - * a GPO. The "struct led_platform_data" can be embedded in a "struct - * tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and - * a 'setup' callback which is called once the GPIOs are available. - * - * When configured via devicetree there is one child for each output. - * The "reg" determines the output number and "compatible" determines - * whether it is an LED or a GPIO. "linux,default-trigger" can set a - * default trigger. */ #include <linux/module.h> @@ -92,10 +76,9 @@ #include <linux/leds.h> #include <linux/err.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/property.h> #include <linux/workqueue.h> -#include <linux/leds-tca6507.h> -#include <linux/of.h> /* LED select registers determine the source that drives LED outputs */ #define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */ @@ -107,6 +90,12 @@ #define TCA6507_LS_BLINK0 0x6 /* Blink at Bank0 rate */ #define TCA6507_LS_BLINK1 0x7 /* Blink at Bank1 rate */ +struct tca6507_platform_data { + struct led_platform_data leds; +}; + +#define TCA6507_MAKE_GPIO 1 + enum { BANK0, BANK1, @@ -188,7 +177,6 @@ struct tca6507_chip { } leds[NUM_LEDS]; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; - const char *gpio_name[NUM_LEDS]; int gpio_map[NUM_LEDS]; #endif }; @@ -251,9 +239,7 @@ static int choose_times(int msec, int *c1p, int *c2p) if (diff < 65536) { int actual; if (msec & 1) { - c1 = *c2p; - *c2p = *c1p; - *c1p = c1; + swap(*c2p, *c1p); } actual = time_codes[*c1p] + time_codes[*c2p]; if (*c1p < *c2p) @@ -602,8 +588,8 @@ static int tca6507_blink_set(struct led_classdev *led_cdev, } #ifdef CONFIG_GPIOLIB -static void tca6507_gpio_set_value(struct gpio_chip *gc, - unsigned offset, int val) +static int tca6507_gpio_set_value(struct gpio_chip *gc, unsigned int offset, + int val) { struct tca6507_chip *tca = gpiochip_get_data(gc); unsigned long flags; @@ -618,16 +604,17 @@ static void tca6507_gpio_set_value(struct gpio_chip *gc, spin_unlock_irqrestore(&tca->lock, flags); if (tca->reg_set) schedule_work(&tca->work); + + return 0; } static int tca6507_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val) { - tca6507_gpio_set_value(gc, offset, val); - return 0; + return tca6507_gpio_set_value(gc, offset, val); } -static int tca6507_probe_gpios(struct i2c_client *client, +static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { @@ -638,7 +625,6 @@ static int tca6507_probe_gpios(struct i2c_client *client, for (i = 0; i < NUM_LEDS; i++) if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) { /* Configure as a gpio */ - tca->gpio_name[gpios] = pdata->leds.leds[i].name; tca->gpio_map[gpios] = i; gpios++; } @@ -647,131 +633,104 @@ static int tca6507_probe_gpios(struct i2c_client *client, return 0; tca->gpio.label = "gpio-tca6507"; - tca->gpio.names = tca->gpio_name; tca->gpio.ngpio = gpios; - tca->gpio.base = pdata->gpio_base; + tca->gpio.base = -1; tca->gpio.owner = THIS_MODULE; tca->gpio.direction_output = tca6507_gpio_direction_output; tca->gpio.set = tca6507_gpio_set_value; - tca->gpio.parent = &client->dev; -#ifdef CONFIG_OF_GPIO - tca->gpio.of_node = of_node_get(client->dev.of_node); -#endif - err = gpiochip_add_data(&tca->gpio, tca); + tca->gpio.parent = dev; + err = devm_gpiochip_add_data(dev, &tca->gpio, tca); if (err) { tca->gpio.ngpio = 0; return err; } - if (pdata->setup) - pdata->setup(tca->gpio.base, tca->gpio.ngpio); return 0; } - -static void tca6507_remove_gpio(struct tca6507_chip *tca) -{ - if (tca->gpio.ngpio) - gpiochip_remove(&tca->gpio); -} #else /* CONFIG_GPIOLIB */ -static int tca6507_probe_gpios(struct i2c_client *client, +static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { return 0; } -static void tca6507_remove_gpio(struct tca6507_chip *tca) -{ -} #endif /* CONFIG_GPIOLIB */ -#ifdef CONFIG_OF static struct tca6507_platform_data * -tca6507_led_dt_init(struct i2c_client *client) +tca6507_led_dt_init(struct device *dev) { - struct device_node *np = client->dev.of_node, *child; struct tca6507_platform_data *pdata; struct led_info *tca_leds; int count; - count = of_get_child_count(np); + count = device_get_child_node_count(dev); if (!count || count > NUM_LEDS) return ERR_PTR(-ENODEV); - tca_leds = devm_kzalloc(&client->dev, - sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL); + tca_leds = devm_kcalloc(dev, NUM_LEDS, sizeof(struct led_info), + GFP_KERNEL); if (!tca_leds) return ERR_PTR(-ENOMEM); - for_each_child_of_node(np, child) { + device_for_each_child_node_scoped(dev, child) { struct led_info led; u32 reg; int ret; - led.name = - of_get_property(child, "label", NULL) ? : child->name; - led.default_trigger = - of_get_property(child, "linux,default-trigger", NULL); + if (fwnode_property_read_string(child, "label", &led.name)) + led.name = fwnode_get_name(child); + + if (fwnode_property_read_string(child, "linux,default-trigger", + &led.default_trigger)) + led.default_trigger = NULL; + led.flags = 0; - if (of_property_match_string(child, "compatible", "gpio") >= 0) + if (fwnode_device_is_compatible(child, "gpio")) led.flags |= TCA6507_MAKE_GPIO; - ret = of_property_read_u32(child, "reg", ®); - if (ret != 0 || reg < 0 || reg >= NUM_LEDS) - continue; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg >= NUM_LEDS) + return ERR_PTR(ret ? : -EINVAL); tca_leds[reg] = led; } - pdata = devm_kzalloc(&client->dev, - sizeof(struct tca6507_platform_data), GFP_KERNEL); + + pdata = devm_kzalloc(dev, sizeof(struct tca6507_platform_data), + GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); pdata->leds.leds = tca_leds; pdata->leds.num_leds = NUM_LEDS; -#ifdef CONFIG_GPIOLIB - pdata->gpio_base = -1; -#endif + return pdata; } -static const struct of_device_id of_tca6507_leds_match[] = { +static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = { { .compatible = "ti,tca6507", }, {}, }; MODULE_DEVICE_TABLE(of, of_tca6507_leds_match); -#else -static struct tca6507_platform_data * -tca6507_led_dt_init(struct i2c_client *client) +static int tca6507_probe(struct i2c_client *client) { - return ERR_PTR(-ENODEV); -} - -#endif - -static int tca6507_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tca6507_chip *tca; + struct device *dev = &client->dev; struct i2c_adapter *adapter; + struct tca6507_chip *tca; struct tca6507_platform_data *pdata; int err; int i = 0; - adapter = to_i2c_adapter(client->dev.parent); - pdata = dev_get_platdata(&client->dev); + adapter = client->adapter; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -EIO; - if (!pdata || pdata->leds.num_leds != NUM_LEDS) { - pdata = tca6507_led_dt_init(client); - if (IS_ERR(pdata)) { - dev_err(&client->dev, "Need %d entries in platform-data list\n", - NUM_LEDS); - return PTR_ERR(pdata); - } + pdata = tca6507_led_dt_init(dev); + if (IS_ERR(pdata)) { + dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS); + return PTR_ERR(pdata); } - tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); + tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL); if (!tca) return -ENOMEM; @@ -792,42 +751,26 @@ static int tca6507_probe(struct i2c_client *client, l->led_cdev.brightness_set = tca6507_brightness_set; l->led_cdev.blink_set = tca6507_blink_set; l->bank = -1; - err = led_classdev_register(&client->dev, - &l->led_cdev); + err = devm_led_classdev_register(dev, &l->led_cdev); if (err < 0) - goto exit; + return err; } } - err = tca6507_probe_gpios(client, tca, pdata); + err = tca6507_probe_gpios(dev, tca, pdata); if (err) - goto exit; + return err; /* set all registers to known state - zero */ tca->reg_set = 0x7f; schedule_work(&tca->work); return 0; -exit: - while (i--) { - if (tca->leds[i].led_cdev.name) - led_classdev_unregister(&tca->leds[i].led_cdev); - } - return err; } -static int tca6507_remove(struct i2c_client *client) +static void tca6507_remove(struct i2c_client *client) { - int i; struct tca6507_chip *tca = i2c_get_clientdata(client); - struct tca6507_led *tca_leds = tca->leds; - for (i = 0; i < NUM_LEDS; i++) { - if (tca_leds[i].led_cdev.name) - led_classdev_unregister(&tca_leds[i].led_cdev); - } - tca6507_remove_gpio(tca); cancel_work_sync(&tca->work); - - return 0; } static struct i2c_driver tca6507_driver = { |
