root/drivers/leds/leds-netxbig.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gpio_ext_set_addr
  2. gpio_ext_set_data
  3. gpio_ext_enable_select
  4. gpio_ext_set_value
  5. gpio_ext_init
  6. netxbig_led_get_timer_mode
  7. netxbig_led_blink_set
  8. netxbig_led_set
  9. netxbig_led_sata_store
  10. netxbig_led_sata_show
  11. create_netxbig_led
  12. gpio_ext_get_of_pdata
  13. netxbig_leds_get_of_pdata
  14. netxbig_led_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
   4  *
   5  * Copyright (C) 2010 LaCie
   6  *
   7  * Author: Simon Guinot <sguinot@lacie.com>
   8  */
   9 
  10 #include <linux/module.h>
  11 #include <linux/irq.h>
  12 #include <linux/slab.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/gpio.h>
  16 #include <linux/of_gpio.h>
  17 #include <linux/leds.h>
  18 
  19 struct netxbig_gpio_ext {
  20         unsigned int    *addr;
  21         int             num_addr;
  22         unsigned int    *data;
  23         int             num_data;
  24         unsigned int    enable;
  25 };
  26 
  27 enum netxbig_led_mode {
  28         NETXBIG_LED_OFF,
  29         NETXBIG_LED_ON,
  30         NETXBIG_LED_SATA,
  31         NETXBIG_LED_TIMER1,
  32         NETXBIG_LED_TIMER2,
  33         NETXBIG_LED_MODE_NUM,
  34 };
  35 
  36 #define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
  37 
  38 struct netxbig_led_timer {
  39         unsigned long           delay_on;
  40         unsigned long           delay_off;
  41         enum netxbig_led_mode   mode;
  42 };
  43 
  44 struct netxbig_led {
  45         const char      *name;
  46         const char      *default_trigger;
  47         int             mode_addr;
  48         int             *mode_val;
  49         int             bright_addr;
  50         int             bright_max;
  51 };
  52 
  53 struct netxbig_led_platform_data {
  54         struct netxbig_gpio_ext *gpio_ext;
  55         struct netxbig_led_timer *timer;
  56         int                     num_timer;
  57         struct netxbig_led      *leds;
  58         int                     num_leds;
  59 };
  60 
  61 /*
  62  * GPIO extension bus.
  63  */
  64 
  65 static DEFINE_SPINLOCK(gpio_ext_lock);
  66 
  67 static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
  68 {
  69         int pin;
  70 
  71         for (pin = 0; pin < gpio_ext->num_addr; pin++)
  72                 gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
  73 }
  74 
  75 static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
  76 {
  77         int pin;
  78 
  79         for (pin = 0; pin < gpio_ext->num_data; pin++)
  80                 gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1);
  81 }
  82 
  83 static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
  84 {
  85         /* Enable select is done on the raising edge. */
  86         gpio_set_value(gpio_ext->enable, 0);
  87         gpio_set_value(gpio_ext->enable, 1);
  88 }
  89 
  90 static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
  91                                int addr, int value)
  92 {
  93         unsigned long flags;
  94 
  95         spin_lock_irqsave(&gpio_ext_lock, flags);
  96         gpio_ext_set_addr(gpio_ext, addr);
  97         gpio_ext_set_data(gpio_ext, value);
  98         gpio_ext_enable_select(gpio_ext);
  99         spin_unlock_irqrestore(&gpio_ext_lock, flags);
 100 }
 101 
 102 static int gpio_ext_init(struct platform_device *pdev,
 103                          struct netxbig_gpio_ext *gpio_ext)
 104 {
 105         int err;
 106         int i;
 107 
 108         if (unlikely(!gpio_ext))
 109                 return -EINVAL;
 110 
 111         /* Configure address GPIOs. */
 112         for (i = 0; i < gpio_ext->num_addr; i++) {
 113                 err = devm_gpio_request_one(&pdev->dev, gpio_ext->addr[i],
 114                                             GPIOF_OUT_INIT_LOW,
 115                                             "GPIO extension addr");
 116                 if (err)
 117                         return err;
 118         }
 119         /* Configure data GPIOs. */
 120         for (i = 0; i < gpio_ext->num_data; i++) {
 121                 err = devm_gpio_request_one(&pdev->dev, gpio_ext->data[i],
 122                                             GPIOF_OUT_INIT_LOW,
 123                                             "GPIO extension data");
 124                 if (err)
 125                         return err;
 126         }
 127         /* Configure "enable select" GPIO. */
 128         err = devm_gpio_request_one(&pdev->dev, gpio_ext->enable,
 129                                     GPIOF_OUT_INIT_LOW,
 130                                     "GPIO extension enable");
 131         if (err)
 132                 return err;
 133 
 134         return 0;
 135 }
 136 
 137 /*
 138  * Class LED driver.
 139  */
 140 
 141 struct netxbig_led_data {
 142         struct netxbig_gpio_ext *gpio_ext;
 143         struct led_classdev     cdev;
 144         int                     mode_addr;
 145         int                     *mode_val;
 146         int                     bright_addr;
 147         struct                  netxbig_led_timer *timer;
 148         int                     num_timer;
 149         enum netxbig_led_mode   mode;
 150         int                     sata;
 151         spinlock_t              lock;
 152 };
 153 
 154 static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
 155                                       unsigned long delay_on,
 156                                       unsigned long delay_off,
 157                                       struct netxbig_led_timer *timer,
 158                                       int num_timer)
 159 {
 160         int i;
 161 
 162         for (i = 0; i < num_timer; i++) {
 163                 if (timer[i].delay_on == delay_on &&
 164                     timer[i].delay_off == delay_off) {
 165                         *mode = timer[i].mode;
 166                         return 0;
 167                 }
 168         }
 169         return -EINVAL;
 170 }
 171 
 172 static int netxbig_led_blink_set(struct led_classdev *led_cdev,
 173                                  unsigned long *delay_on,
 174                                  unsigned long *delay_off)
 175 {
 176         struct netxbig_led_data *led_dat =
 177                 container_of(led_cdev, struct netxbig_led_data, cdev);
 178         enum netxbig_led_mode mode;
 179         int mode_val;
 180         int ret;
 181 
 182         /* Look for a LED mode with the requested timer frequency. */
 183         ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
 184                                          led_dat->timer, led_dat->num_timer);
 185         if (ret < 0)
 186                 return ret;
 187 
 188         mode_val = led_dat->mode_val[mode];
 189         if (mode_val == NETXBIG_LED_INVALID_MODE)
 190                 return -EINVAL;
 191 
 192         spin_lock_irq(&led_dat->lock);
 193 
 194         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
 195         led_dat->mode = mode;
 196 
 197         spin_unlock_irq(&led_dat->lock);
 198 
 199         return 0;
 200 }
 201 
 202 static void netxbig_led_set(struct led_classdev *led_cdev,
 203                             enum led_brightness value)
 204 {
 205         struct netxbig_led_data *led_dat =
 206                 container_of(led_cdev, struct netxbig_led_data, cdev);
 207         enum netxbig_led_mode mode;
 208         int mode_val;
 209         int set_brightness = 1;
 210         unsigned long flags;
 211 
 212         spin_lock_irqsave(&led_dat->lock, flags);
 213 
 214         if (value == LED_OFF) {
 215                 mode = NETXBIG_LED_OFF;
 216                 set_brightness = 0;
 217         } else {
 218                 if (led_dat->sata)
 219                         mode = NETXBIG_LED_SATA;
 220                 else if (led_dat->mode == NETXBIG_LED_OFF)
 221                         mode = NETXBIG_LED_ON;
 222                 else /* Keep 'timer' mode. */
 223                         mode = led_dat->mode;
 224         }
 225         mode_val = led_dat->mode_val[mode];
 226 
 227         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
 228         led_dat->mode = mode;
 229         /*
 230          * Note that the brightness register is shared between all the
 231          * SATA LEDs. So, change the brightness setting for a single
 232          * SATA LED will affect all the others.
 233          */
 234         if (set_brightness)
 235                 gpio_ext_set_value(led_dat->gpio_ext,
 236                                    led_dat->bright_addr, value);
 237 
 238         spin_unlock_irqrestore(&led_dat->lock, flags);
 239 }
 240 
 241 static ssize_t netxbig_led_sata_store(struct device *dev,
 242                                       struct device_attribute *attr,
 243                                       const char *buff, size_t count)
 244 {
 245         struct led_classdev *led_cdev = dev_get_drvdata(dev);
 246         struct netxbig_led_data *led_dat =
 247                 container_of(led_cdev, struct netxbig_led_data, cdev);
 248         unsigned long enable;
 249         enum netxbig_led_mode mode;
 250         int mode_val;
 251         int ret;
 252 
 253         ret = kstrtoul(buff, 10, &enable);
 254         if (ret < 0)
 255                 return ret;
 256 
 257         enable = !!enable;
 258 
 259         spin_lock_irq(&led_dat->lock);
 260 
 261         if (led_dat->sata == enable) {
 262                 ret = count;
 263                 goto exit_unlock;
 264         }
 265 
 266         if (led_dat->mode != NETXBIG_LED_ON &&
 267             led_dat->mode != NETXBIG_LED_SATA)
 268                 mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
 269         else if (enable)
 270                 mode = NETXBIG_LED_SATA;
 271         else
 272                 mode = NETXBIG_LED_ON;
 273 
 274         mode_val = led_dat->mode_val[mode];
 275         if (mode_val == NETXBIG_LED_INVALID_MODE) {
 276                 ret = -EINVAL;
 277                 goto exit_unlock;
 278         }
 279 
 280         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
 281         led_dat->mode = mode;
 282         led_dat->sata = enable;
 283 
 284         ret = count;
 285 
 286 exit_unlock:
 287         spin_unlock_irq(&led_dat->lock);
 288 
 289         return ret;
 290 }
 291 
 292 static ssize_t netxbig_led_sata_show(struct device *dev,
 293                                      struct device_attribute *attr, char *buf)
 294 {
 295         struct led_classdev *led_cdev = dev_get_drvdata(dev);
 296         struct netxbig_led_data *led_dat =
 297                 container_of(led_cdev, struct netxbig_led_data, cdev);
 298 
 299         return sprintf(buf, "%d\n", led_dat->sata);
 300 }
 301 
 302 static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
 303 
 304 static struct attribute *netxbig_led_attrs[] = {
 305         &dev_attr_sata.attr,
 306         NULL
 307 };
 308 ATTRIBUTE_GROUPS(netxbig_led);
 309 
 310 static int create_netxbig_led(struct platform_device *pdev,
 311                               struct netxbig_led_platform_data *pdata,
 312                               struct netxbig_led_data *led_dat,
 313                               const struct netxbig_led *template)
 314 {
 315         spin_lock_init(&led_dat->lock);
 316         led_dat->gpio_ext = pdata->gpio_ext;
 317         led_dat->cdev.name = template->name;
 318         led_dat->cdev.default_trigger = template->default_trigger;
 319         led_dat->cdev.blink_set = netxbig_led_blink_set;
 320         led_dat->cdev.brightness_set = netxbig_led_set;
 321         /*
 322          * Because the GPIO extension bus don't allow to read registers
 323          * value, there is no way to probe the LED initial state.
 324          * So, the initial sysfs LED value for the "brightness" and "sata"
 325          * attributes are inconsistent.
 326          *
 327          * Note that the initial LED state can't be reconfigured.
 328          * The reason is that the LED behaviour must stay uniform during
 329          * the whole boot process (bootloader+linux).
 330          */
 331         led_dat->sata = 0;
 332         led_dat->cdev.brightness = LED_OFF;
 333         led_dat->cdev.max_brightness = template->bright_max;
 334         led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 335         led_dat->mode_addr = template->mode_addr;
 336         led_dat->mode_val = template->mode_val;
 337         led_dat->bright_addr = template->bright_addr;
 338         led_dat->timer = pdata->timer;
 339         led_dat->num_timer = pdata->num_timer;
 340         /*
 341          * If available, expose the SATA activity blink capability through
 342          * a "sata" sysfs attribute.
 343          */
 344         if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
 345                 led_dat->cdev.groups = netxbig_led_groups;
 346 
 347         return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
 348 }
 349 
 350 static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np,
 351                                  struct netxbig_gpio_ext *gpio_ext)
 352 {
 353         int *addr, *data;
 354         int num_addr, num_data;
 355         int ret;
 356         int i;
 357 
 358         ret = of_gpio_named_count(np, "addr-gpios");
 359         if (ret < 0) {
 360                 dev_err(dev,
 361                         "Failed to count GPIOs in DT property addr-gpios\n");
 362                 return ret;
 363         }
 364         num_addr = ret;
 365         addr = devm_kcalloc(dev, num_addr, sizeof(*addr), GFP_KERNEL);
 366         if (!addr)
 367                 return -ENOMEM;
 368 
 369         for (i = 0; i < num_addr; i++) {
 370                 ret = of_get_named_gpio(np, "addr-gpios", i);
 371                 if (ret < 0)
 372                         return ret;
 373                 addr[i] = ret;
 374         }
 375         gpio_ext->addr = addr;
 376         gpio_ext->num_addr = num_addr;
 377 
 378         ret = of_gpio_named_count(np, "data-gpios");
 379         if (ret < 0) {
 380                 dev_err(dev,
 381                         "Failed to count GPIOs in DT property data-gpios\n");
 382                 return ret;
 383         }
 384         num_data = ret;
 385         data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL);
 386         if (!data)
 387                 return -ENOMEM;
 388 
 389         for (i = 0; i < num_data; i++) {
 390                 ret = of_get_named_gpio(np, "data-gpios", i);
 391                 if (ret < 0)
 392                         return ret;
 393                 data[i] = ret;
 394         }
 395         gpio_ext->data = data;
 396         gpio_ext->num_data = num_data;
 397 
 398         ret = of_get_named_gpio(np, "enable-gpio", 0);
 399         if (ret < 0) {
 400                 dev_err(dev,
 401                         "Failed to get GPIO from DT property enable-gpio\n");
 402                 return ret;
 403         }
 404         gpio_ext->enable = ret;
 405 
 406         return 0;
 407 }
 408 
 409 static int netxbig_leds_get_of_pdata(struct device *dev,
 410                                      struct netxbig_led_platform_data *pdata)
 411 {
 412         struct device_node *np = dev->of_node;
 413         struct device_node *gpio_ext_np;
 414         struct device_node *child;
 415         struct netxbig_gpio_ext *gpio_ext;
 416         struct netxbig_led_timer *timers;
 417         struct netxbig_led *leds, *led;
 418         int num_timers;
 419         int num_leds = 0;
 420         int ret;
 421         int i;
 422 
 423         /* GPIO extension */
 424         gpio_ext_np = of_parse_phandle(np, "gpio-ext", 0);
 425         if (!gpio_ext_np) {
 426                 dev_err(dev, "Failed to get DT handle gpio-ext\n");
 427                 return -EINVAL;
 428         }
 429 
 430         gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
 431         if (!gpio_ext) {
 432                 of_node_put(gpio_ext_np);
 433                 return -ENOMEM;
 434         }
 435         ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext);
 436         of_node_put(gpio_ext_np);
 437         if (ret)
 438                 return ret;
 439         pdata->gpio_ext = gpio_ext;
 440 
 441         /* Timers (optional) */
 442         ret = of_property_count_u32_elems(np, "timers");
 443         if (ret > 0) {
 444                 if (ret % 3)
 445                         return -EINVAL;
 446                 num_timers = ret / 3;
 447                 timers = devm_kcalloc(dev, num_timers, sizeof(*timers),
 448                                       GFP_KERNEL);
 449                 if (!timers)
 450                         return -ENOMEM;
 451                 for (i = 0; i < num_timers; i++) {
 452                         u32 tmp;
 453 
 454                         of_property_read_u32_index(np, "timers", 3 * i,
 455                                                    &timers[i].mode);
 456                         if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
 457                                 return -EINVAL;
 458                         of_property_read_u32_index(np, "timers",
 459                                                    3 * i + 1, &tmp);
 460                         timers[i].delay_on = tmp;
 461                         of_property_read_u32_index(np, "timers",
 462                                                    3 * i + 2, &tmp);
 463                         timers[i].delay_off = tmp;
 464                 }
 465                 pdata->timer = timers;
 466                 pdata->num_timer = num_timers;
 467         }
 468 
 469         /* LEDs */
 470         num_leds = of_get_child_count(np);
 471         if (!num_leds) {
 472                 dev_err(dev, "No LED subnodes found in DT\n");
 473                 return -ENODEV;
 474         }
 475 
 476         leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL);
 477         if (!leds)
 478                 return -ENOMEM;
 479 
 480         led = leds;
 481         for_each_child_of_node(np, child) {
 482                 const char *string;
 483                 int *mode_val;
 484                 int num_modes;
 485 
 486                 ret = of_property_read_u32(child, "mode-addr",
 487                                            &led->mode_addr);
 488                 if (ret)
 489                         goto err_node_put;
 490 
 491                 ret = of_property_read_u32(child, "bright-addr",
 492                                            &led->bright_addr);
 493                 if (ret)
 494                         goto err_node_put;
 495 
 496                 ret = of_property_read_u32(child, "max-brightness",
 497                                            &led->bright_max);
 498                 if (ret)
 499                         goto err_node_put;
 500 
 501                 mode_val =
 502                         devm_kcalloc(dev,
 503                                      NETXBIG_LED_MODE_NUM, sizeof(*mode_val),
 504                                      GFP_KERNEL);
 505                 if (!mode_val) {
 506                         ret = -ENOMEM;
 507                         goto err_node_put;
 508                 }
 509 
 510                 for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
 511                         mode_val[i] = NETXBIG_LED_INVALID_MODE;
 512 
 513                 ret = of_property_count_u32_elems(child, "mode-val");
 514                 if (ret < 0 || ret % 2) {
 515                         ret = -EINVAL;
 516                         goto err_node_put;
 517                 }
 518                 num_modes = ret / 2;
 519                 if (num_modes > NETXBIG_LED_MODE_NUM) {
 520                         ret = -EINVAL;
 521                         goto err_node_put;
 522                 }
 523 
 524                 for (i = 0; i < num_modes; i++) {
 525                         int mode;
 526                         int val;
 527 
 528                         of_property_read_u32_index(child,
 529                                                    "mode-val", 2 * i, &mode);
 530                         of_property_read_u32_index(child,
 531                                                    "mode-val", 2 * i + 1, &val);
 532                         if (mode >= NETXBIG_LED_MODE_NUM) {
 533                                 ret = -EINVAL;
 534                                 goto err_node_put;
 535                         }
 536                         mode_val[mode] = val;
 537                 }
 538                 led->mode_val = mode_val;
 539 
 540                 if (!of_property_read_string(child, "label", &string))
 541                         led->name = string;
 542                 else
 543                         led->name = child->name;
 544 
 545                 if (!of_property_read_string(child,
 546                                              "linux,default-trigger", &string))
 547                         led->default_trigger = string;
 548 
 549                 led++;
 550         }
 551 
 552         pdata->leds = leds;
 553         pdata->num_leds = num_leds;
 554 
 555         return 0;
 556 
 557 err_node_put:
 558         of_node_put(child);
 559         return ret;
 560 }
 561 
 562 static const struct of_device_id of_netxbig_leds_match[] = {
 563         { .compatible = "lacie,netxbig-leds", },
 564         {},
 565 };
 566 MODULE_DEVICE_TABLE(of, of_netxbig_leds_match);
 567 
 568 static int netxbig_led_probe(struct platform_device *pdev)
 569 {
 570         struct netxbig_led_platform_data *pdata;
 571         struct netxbig_led_data *leds_data;
 572         int i;
 573         int ret;
 574 
 575         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 576         if (!pdata)
 577                 return -ENOMEM;
 578         ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
 579         if (ret)
 580                 return ret;
 581 
 582         leds_data = devm_kcalloc(&pdev->dev,
 583                                  pdata->num_leds, sizeof(*leds_data),
 584                                  GFP_KERNEL);
 585         if (!leds_data)
 586                 return -ENOMEM;
 587 
 588         ret = gpio_ext_init(pdev, pdata->gpio_ext);
 589         if (ret < 0)
 590                 return ret;
 591 
 592         for (i = 0; i < pdata->num_leds; i++) {
 593                 ret = create_netxbig_led(pdev, pdata,
 594                                          &leds_data[i], &pdata->leds[i]);
 595                 if (ret < 0)
 596                         return ret;
 597         }
 598 
 599         return 0;
 600 }
 601 
 602 static struct platform_driver netxbig_led_driver = {
 603         .probe          = netxbig_led_probe,
 604         .driver         = {
 605                 .name           = "leds-netxbig",
 606                 .of_match_table = of_netxbig_leds_match,
 607         },
 608 };
 609 
 610 module_platform_driver(netxbig_led_driver);
 611 
 612 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
 613 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
 614 MODULE_LICENSE("GPL");
 615 MODULE_ALIAS("platform:leds-netxbig");

/* [<][>][^][v][top][bottom][index][help] */