Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
0004  *
0005  * Copyright (C) 2010 LaCie
0006  *
0007  * Author: Simon Guinot <sguinot@lacie.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/irq.h>
0012 #include <linux/slab.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/leds.h>
0017 #include <linux/of.h>
0018 #include <linux/of_platform.h>
0019 
0020 struct netxbig_gpio_ext {
0021     struct gpio_desc **addr;
0022     int     num_addr;
0023     struct gpio_desc **data;
0024     int     num_data;
0025     struct gpio_desc *enable;
0026 };
0027 
0028 enum netxbig_led_mode {
0029     NETXBIG_LED_OFF,
0030     NETXBIG_LED_ON,
0031     NETXBIG_LED_SATA,
0032     NETXBIG_LED_TIMER1,
0033     NETXBIG_LED_TIMER2,
0034     NETXBIG_LED_MODE_NUM,
0035 };
0036 
0037 #define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
0038 
0039 struct netxbig_led_timer {
0040     unsigned long       delay_on;
0041     unsigned long       delay_off;
0042     enum netxbig_led_mode   mode;
0043 };
0044 
0045 struct netxbig_led {
0046     const char  *name;
0047     const char  *default_trigger;
0048     int     mode_addr;
0049     int     *mode_val;
0050     int     bright_addr;
0051     int     bright_max;
0052 };
0053 
0054 struct netxbig_led_platform_data {
0055     struct netxbig_gpio_ext *gpio_ext;
0056     struct netxbig_led_timer *timer;
0057     int         num_timer;
0058     struct netxbig_led  *leds;
0059     int         num_leds;
0060 };
0061 
0062 /*
0063  * GPIO extension bus.
0064  */
0065 
0066 static DEFINE_SPINLOCK(gpio_ext_lock);
0067 
0068 static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
0069 {
0070     int pin;
0071 
0072     for (pin = 0; pin < gpio_ext->num_addr; pin++)
0073         gpiod_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
0074 }
0075 
0076 static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
0077 {
0078     int pin;
0079 
0080     for (pin = 0; pin < gpio_ext->num_data; pin++)
0081         gpiod_set_value(gpio_ext->data[pin], (data >> pin) & 1);
0082 }
0083 
0084 static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
0085 {
0086     /* Enable select is done on the raising edge. */
0087     gpiod_set_value(gpio_ext->enable, 0);
0088     gpiod_set_value(gpio_ext->enable, 1);
0089 }
0090 
0091 static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
0092                    int addr, int value)
0093 {
0094     unsigned long flags;
0095 
0096     spin_lock_irqsave(&gpio_ext_lock, flags);
0097     gpio_ext_set_addr(gpio_ext, addr);
0098     gpio_ext_set_data(gpio_ext, value);
0099     gpio_ext_enable_select(gpio_ext);
0100     spin_unlock_irqrestore(&gpio_ext_lock, flags);
0101 }
0102 
0103 /*
0104  * Class LED driver.
0105  */
0106 
0107 struct netxbig_led_data {
0108     struct netxbig_gpio_ext *gpio_ext;
0109     struct led_classdev cdev;
0110     int         mode_addr;
0111     int         *mode_val;
0112     int         bright_addr;
0113     struct          netxbig_led_timer *timer;
0114     int         num_timer;
0115     enum netxbig_led_mode   mode;
0116     int         sata;
0117     spinlock_t      lock;
0118 };
0119 
0120 static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
0121                       unsigned long delay_on,
0122                       unsigned long delay_off,
0123                       struct netxbig_led_timer *timer,
0124                       int num_timer)
0125 {
0126     int i;
0127 
0128     for (i = 0; i < num_timer; i++) {
0129         if (timer[i].delay_on == delay_on &&
0130             timer[i].delay_off == delay_off) {
0131             *mode = timer[i].mode;
0132             return 0;
0133         }
0134     }
0135     return -EINVAL;
0136 }
0137 
0138 static int netxbig_led_blink_set(struct led_classdev *led_cdev,
0139                  unsigned long *delay_on,
0140                  unsigned long *delay_off)
0141 {
0142     struct netxbig_led_data *led_dat =
0143         container_of(led_cdev, struct netxbig_led_data, cdev);
0144     enum netxbig_led_mode mode;
0145     int mode_val;
0146     int ret;
0147 
0148     /* Look for a LED mode with the requested timer frequency. */
0149     ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
0150                      led_dat->timer, led_dat->num_timer);
0151     if (ret < 0)
0152         return ret;
0153 
0154     mode_val = led_dat->mode_val[mode];
0155     if (mode_val == NETXBIG_LED_INVALID_MODE)
0156         return -EINVAL;
0157 
0158     spin_lock_irq(&led_dat->lock);
0159 
0160     gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
0161     led_dat->mode = mode;
0162 
0163     spin_unlock_irq(&led_dat->lock);
0164 
0165     return 0;
0166 }
0167 
0168 static void netxbig_led_set(struct led_classdev *led_cdev,
0169                 enum led_brightness value)
0170 {
0171     struct netxbig_led_data *led_dat =
0172         container_of(led_cdev, struct netxbig_led_data, cdev);
0173     enum netxbig_led_mode mode;
0174     int mode_val;
0175     int set_brightness = 1;
0176     unsigned long flags;
0177 
0178     spin_lock_irqsave(&led_dat->lock, flags);
0179 
0180     if (value == LED_OFF) {
0181         mode = NETXBIG_LED_OFF;
0182         set_brightness = 0;
0183     } else {
0184         if (led_dat->sata)
0185             mode = NETXBIG_LED_SATA;
0186         else if (led_dat->mode == NETXBIG_LED_OFF)
0187             mode = NETXBIG_LED_ON;
0188         else /* Keep 'timer' mode. */
0189             mode = led_dat->mode;
0190     }
0191     mode_val = led_dat->mode_val[mode];
0192 
0193     gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
0194     led_dat->mode = mode;
0195     /*
0196      * Note that the brightness register is shared between all the
0197      * SATA LEDs. So, change the brightness setting for a single
0198      * SATA LED will affect all the others.
0199      */
0200     if (set_brightness)
0201         gpio_ext_set_value(led_dat->gpio_ext,
0202                    led_dat->bright_addr, value);
0203 
0204     spin_unlock_irqrestore(&led_dat->lock, flags);
0205 }
0206 
0207 static ssize_t sata_store(struct device *dev,
0208               struct device_attribute *attr,
0209               const char *buff, size_t count)
0210 {
0211     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0212     struct netxbig_led_data *led_dat =
0213         container_of(led_cdev, struct netxbig_led_data, cdev);
0214     unsigned long enable;
0215     enum netxbig_led_mode mode;
0216     int mode_val;
0217     int ret;
0218 
0219     ret = kstrtoul(buff, 10, &enable);
0220     if (ret < 0)
0221         return ret;
0222 
0223     enable = !!enable;
0224 
0225     spin_lock_irq(&led_dat->lock);
0226 
0227     if (led_dat->sata == enable) {
0228         ret = count;
0229         goto exit_unlock;
0230     }
0231 
0232     if (led_dat->mode != NETXBIG_LED_ON &&
0233         led_dat->mode != NETXBIG_LED_SATA)
0234         mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
0235     else if (enable)
0236         mode = NETXBIG_LED_SATA;
0237     else
0238         mode = NETXBIG_LED_ON;
0239 
0240     mode_val = led_dat->mode_val[mode];
0241     if (mode_val == NETXBIG_LED_INVALID_MODE) {
0242         ret = -EINVAL;
0243         goto exit_unlock;
0244     }
0245 
0246     gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
0247     led_dat->mode = mode;
0248     led_dat->sata = enable;
0249 
0250     ret = count;
0251 
0252 exit_unlock:
0253     spin_unlock_irq(&led_dat->lock);
0254 
0255     return ret;
0256 }
0257 
0258 static ssize_t sata_show(struct device *dev,
0259              struct device_attribute *attr, char *buf)
0260 {
0261     struct led_classdev *led_cdev = dev_get_drvdata(dev);
0262     struct netxbig_led_data *led_dat =
0263         container_of(led_cdev, struct netxbig_led_data, cdev);
0264 
0265     return sprintf(buf, "%d\n", led_dat->sata);
0266 }
0267 
0268 static DEVICE_ATTR_RW(sata);
0269 
0270 static struct attribute *netxbig_led_attrs[] = {
0271     &dev_attr_sata.attr,
0272     NULL
0273 };
0274 ATTRIBUTE_GROUPS(netxbig_led);
0275 
0276 static int create_netxbig_led(struct platform_device *pdev,
0277                   struct netxbig_led_platform_data *pdata,
0278                   struct netxbig_led_data *led_dat,
0279                   const struct netxbig_led *template)
0280 {
0281     spin_lock_init(&led_dat->lock);
0282     led_dat->gpio_ext = pdata->gpio_ext;
0283     led_dat->cdev.name = template->name;
0284     led_dat->cdev.default_trigger = template->default_trigger;
0285     led_dat->cdev.blink_set = netxbig_led_blink_set;
0286     led_dat->cdev.brightness_set = netxbig_led_set;
0287     /*
0288      * Because the GPIO extension bus don't allow to read registers
0289      * value, there is no way to probe the LED initial state.
0290      * So, the initial sysfs LED value for the "brightness" and "sata"
0291      * attributes are inconsistent.
0292      *
0293      * Note that the initial LED state can't be reconfigured.
0294      * The reason is that the LED behaviour must stay uniform during
0295      * the whole boot process (bootloader+linux).
0296      */
0297     led_dat->sata = 0;
0298     led_dat->cdev.brightness = LED_OFF;
0299     led_dat->cdev.max_brightness = template->bright_max;
0300     led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
0301     led_dat->mode_addr = template->mode_addr;
0302     led_dat->mode_val = template->mode_val;
0303     led_dat->bright_addr = template->bright_addr;
0304     led_dat->timer = pdata->timer;
0305     led_dat->num_timer = pdata->num_timer;
0306     /*
0307      * If available, expose the SATA activity blink capability through
0308      * a "sata" sysfs attribute.
0309      */
0310     if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
0311         led_dat->cdev.groups = netxbig_led_groups;
0312 
0313     return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
0314 }
0315 
0316 /**
0317  * netxbig_gpio_ext_remove() - Clean up GPIO extension data
0318  * @data: managed resource data to clean up
0319  *
0320  * Since we pick GPIO descriptors from another device than the device our
0321  * driver is probing to, we need to register a specific callback to free
0322  * these up using managed resources.
0323  */
0324 static void netxbig_gpio_ext_remove(void *data)
0325 {
0326     struct netxbig_gpio_ext *gpio_ext = data;
0327     int i;
0328 
0329     for (i = 0; i < gpio_ext->num_addr; i++)
0330         gpiod_put(gpio_ext->addr[i]);
0331     for (i = 0; i < gpio_ext->num_data; i++)
0332         gpiod_put(gpio_ext->data[i]);
0333     gpiod_put(gpio_ext->enable);
0334 }
0335 
0336 /**
0337  * netxbig_gpio_ext_get() - Obtain GPIO extension device data
0338  * @dev: main LED device
0339  * @gpio_ext_dev: the GPIO extension device
0340  * @gpio_ext: the data structure holding the GPIO extension data
0341  *
0342  * This function walks the subdevice that only contain GPIO line
0343  * handles in the device tree and obtains the GPIO descriptors from that
0344  * device.
0345  */
0346 static int netxbig_gpio_ext_get(struct device *dev,
0347                 struct device *gpio_ext_dev,
0348                 struct netxbig_gpio_ext *gpio_ext)
0349 {
0350     struct gpio_desc **addr, **data;
0351     int num_addr, num_data;
0352     struct gpio_desc *gpiod;
0353     int ret;
0354     int i;
0355 
0356     ret = gpiod_count(gpio_ext_dev, "addr");
0357     if (ret < 0) {
0358         dev_err(dev,
0359             "Failed to count GPIOs in DT property addr-gpios\n");
0360         return ret;
0361     }
0362     num_addr = ret;
0363     addr = devm_kcalloc(dev, num_addr, sizeof(*addr), GFP_KERNEL);
0364     if (!addr)
0365         return -ENOMEM;
0366 
0367     /*
0368      * We cannot use devm_ managed resources with these GPIO descriptors
0369      * since they are associated with the "GPIO extension device" which
0370      * does not probe any driver. The device tree parser will however
0371      * populate a platform device for it so we can anyway obtain the
0372      * GPIO descriptors from the device.
0373      */
0374     for (i = 0; i < num_addr; i++) {
0375         gpiod = gpiod_get_index(gpio_ext_dev, "addr", i,
0376                     GPIOD_OUT_LOW);
0377         if (IS_ERR(gpiod))
0378             return PTR_ERR(gpiod);
0379         gpiod_set_consumer_name(gpiod, "GPIO extension addr");
0380         addr[i] = gpiod;
0381     }
0382     gpio_ext->addr = addr;
0383     gpio_ext->num_addr = num_addr;
0384 
0385     ret = gpiod_count(gpio_ext_dev, "data");
0386     if (ret < 0) {
0387         dev_err(dev,
0388             "Failed to count GPIOs in DT property data-gpios\n");
0389         return ret;
0390     }
0391     num_data = ret;
0392     data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL);
0393     if (!data)
0394         return -ENOMEM;
0395 
0396     for (i = 0; i < num_data; i++) {
0397         gpiod = gpiod_get_index(gpio_ext_dev, "data", i,
0398                     GPIOD_OUT_LOW);
0399         if (IS_ERR(gpiod))
0400             return PTR_ERR(gpiod);
0401         gpiod_set_consumer_name(gpiod, "GPIO extension data");
0402         data[i] = gpiod;
0403     }
0404     gpio_ext->data = data;
0405     gpio_ext->num_data = num_data;
0406 
0407     gpiod = gpiod_get(gpio_ext_dev, "enable", GPIOD_OUT_LOW);
0408     if (IS_ERR(gpiod)) {
0409         dev_err(dev,
0410             "Failed to get GPIO from DT property enable-gpio\n");
0411         return PTR_ERR(gpiod);
0412     }
0413     gpiod_set_consumer_name(gpiod, "GPIO extension enable");
0414     gpio_ext->enable = gpiod;
0415 
0416     return devm_add_action_or_reset(dev, netxbig_gpio_ext_remove, gpio_ext);
0417 }
0418 
0419 static int netxbig_leds_get_of_pdata(struct device *dev,
0420                      struct netxbig_led_platform_data *pdata)
0421 {
0422     struct device_node *np = dev_of_node(dev);
0423     struct device_node *gpio_ext_np;
0424     struct platform_device *gpio_ext_pdev;
0425     struct device *gpio_ext_dev;
0426     struct device_node *child;
0427     struct netxbig_gpio_ext *gpio_ext;
0428     struct netxbig_led_timer *timers;
0429     struct netxbig_led *leds, *led;
0430     int num_timers;
0431     int num_leds = 0;
0432     int ret;
0433     int i;
0434 
0435     /* GPIO extension */
0436     gpio_ext_np = of_parse_phandle(np, "gpio-ext", 0);
0437     if (!gpio_ext_np) {
0438         dev_err(dev, "Failed to get DT handle gpio-ext\n");
0439         return -EINVAL;
0440     }
0441     gpio_ext_pdev = of_find_device_by_node(gpio_ext_np);
0442     if (!gpio_ext_pdev) {
0443         dev_err(dev, "Failed to find platform device for gpio-ext\n");
0444         return -ENODEV;
0445     }
0446     gpio_ext_dev = &gpio_ext_pdev->dev;
0447 
0448     gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
0449     if (!gpio_ext) {
0450         of_node_put(gpio_ext_np);
0451         ret = -ENOMEM;
0452         goto put_device;
0453     }
0454     ret = netxbig_gpio_ext_get(dev, gpio_ext_dev, gpio_ext);
0455     of_node_put(gpio_ext_np);
0456     if (ret)
0457         goto put_device;
0458     pdata->gpio_ext = gpio_ext;
0459 
0460     /* Timers (optional) */
0461     ret = of_property_count_u32_elems(np, "timers");
0462     if (ret > 0) {
0463         if (ret % 3) {
0464             ret = -EINVAL;
0465             goto put_device;
0466         }
0467 
0468         num_timers = ret / 3;
0469         timers = devm_kcalloc(dev, num_timers, sizeof(*timers),
0470                       GFP_KERNEL);
0471         if (!timers) {
0472             ret = -ENOMEM;
0473             goto put_device;
0474         }
0475         for (i = 0; i < num_timers; i++) {
0476             u32 tmp;
0477 
0478             of_property_read_u32_index(np, "timers", 3 * i,
0479                            &timers[i].mode);
0480             if (timers[i].mode >= NETXBIG_LED_MODE_NUM) {
0481                 ret = -EINVAL;
0482                 goto put_device;
0483             }
0484             of_property_read_u32_index(np, "timers",
0485                            3 * i + 1, &tmp);
0486             timers[i].delay_on = tmp;
0487             of_property_read_u32_index(np, "timers",
0488                            3 * i + 2, &tmp);
0489             timers[i].delay_off = tmp;
0490         }
0491         pdata->timer = timers;
0492         pdata->num_timer = num_timers;
0493     }
0494 
0495     /* LEDs */
0496     num_leds = of_get_available_child_count(np);
0497     if (!num_leds) {
0498         dev_err(dev, "No LED subnodes found in DT\n");
0499         ret = -ENODEV;
0500         goto put_device;
0501     }
0502 
0503     leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL);
0504     if (!leds) {
0505         ret = -ENOMEM;
0506         goto put_device;
0507     }
0508 
0509     led = leds;
0510     for_each_available_child_of_node(np, child) {
0511         const char *string;
0512         int *mode_val;
0513         int num_modes;
0514 
0515         ret = of_property_read_u32(child, "mode-addr",
0516                        &led->mode_addr);
0517         if (ret)
0518             goto err_node_put;
0519 
0520         ret = of_property_read_u32(child, "bright-addr",
0521                        &led->bright_addr);
0522         if (ret)
0523             goto err_node_put;
0524 
0525         ret = of_property_read_u32(child, "max-brightness",
0526                        &led->bright_max);
0527         if (ret)
0528             goto err_node_put;
0529 
0530         mode_val =
0531             devm_kcalloc(dev,
0532                      NETXBIG_LED_MODE_NUM, sizeof(*mode_val),
0533                      GFP_KERNEL);
0534         if (!mode_val) {
0535             ret = -ENOMEM;
0536             goto err_node_put;
0537         }
0538 
0539         for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
0540             mode_val[i] = NETXBIG_LED_INVALID_MODE;
0541 
0542         ret = of_property_count_u32_elems(child, "mode-val");
0543         if (ret < 0 || ret % 2) {
0544             ret = -EINVAL;
0545             goto err_node_put;
0546         }
0547         num_modes = ret / 2;
0548         if (num_modes > NETXBIG_LED_MODE_NUM) {
0549             ret = -EINVAL;
0550             goto err_node_put;
0551         }
0552 
0553         for (i = 0; i < num_modes; i++) {
0554             int mode;
0555             int val;
0556 
0557             of_property_read_u32_index(child,
0558                            "mode-val", 2 * i, &mode);
0559             of_property_read_u32_index(child,
0560                            "mode-val", 2 * i + 1, &val);
0561             if (mode >= NETXBIG_LED_MODE_NUM) {
0562                 ret = -EINVAL;
0563                 goto err_node_put;
0564             }
0565             mode_val[mode] = val;
0566         }
0567         led->mode_val = mode_val;
0568 
0569         if (!of_property_read_string(child, "label", &string))
0570             led->name = string;
0571         else
0572             led->name = child->name;
0573 
0574         if (!of_property_read_string(child,
0575                          "linux,default-trigger", &string))
0576             led->default_trigger = string;
0577 
0578         led++;
0579     }
0580 
0581     pdata->leds = leds;
0582     pdata->num_leds = num_leds;
0583 
0584     return 0;
0585 
0586 err_node_put:
0587     of_node_put(child);
0588 put_device:
0589     put_device(gpio_ext_dev);
0590     return ret;
0591 }
0592 
0593 static const struct of_device_id of_netxbig_leds_match[] = {
0594     { .compatible = "lacie,netxbig-leds", },
0595     {},
0596 };
0597 MODULE_DEVICE_TABLE(of, of_netxbig_leds_match);
0598 
0599 static int netxbig_led_probe(struct platform_device *pdev)
0600 {
0601     struct netxbig_led_platform_data *pdata;
0602     struct netxbig_led_data *leds_data;
0603     int i;
0604     int ret;
0605 
0606     pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
0607     if (!pdata)
0608         return -ENOMEM;
0609     ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
0610     if (ret)
0611         return ret;
0612 
0613     leds_data = devm_kcalloc(&pdev->dev,
0614                  pdata->num_leds, sizeof(*leds_data),
0615                  GFP_KERNEL);
0616     if (!leds_data)
0617         return -ENOMEM;
0618 
0619     for (i = 0; i < pdata->num_leds; i++) {
0620         ret = create_netxbig_led(pdev, pdata,
0621                      &leds_data[i], &pdata->leds[i]);
0622         if (ret < 0)
0623             return ret;
0624     }
0625 
0626     return 0;
0627 }
0628 
0629 static struct platform_driver netxbig_led_driver = {
0630     .probe      = netxbig_led_probe,
0631     .driver     = {
0632         .name       = "leds-netxbig",
0633         .of_match_table = of_netxbig_leds_match,
0634     },
0635 };
0636 
0637 module_platform_driver(netxbig_led_driver);
0638 
0639 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
0640 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
0641 MODULE_LICENSE("GPL");
0642 MODULE_ALIAS("platform:leds-netxbig");