root/drivers/leds/leds-ss4200.c

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

DEFINITIONS

This source file includes following definitions.
  1. ss4200_led_dmi_callback
  2. led_classdev_to_nasgpio_led
  3. get_led_named
  4. __nasgpio_led_set_attr
  5. nasgpio_led_set_attr
  6. nasgpio_led_get_attr
  7. nasgpio_led_set_brightness
  8. nasgpio_led_set_blink
  9. ich7_gpio_init
  10. ich7_lpc_cleanup
  11. ich7_lpc_probe
  12. ich7_lpc_remove
  13. get_classdev_for_led_nr
  14. set_power_light_amber_noblink
  15. nas_led_blink_show
  16. nas_led_blink_store
  17. register_nasgpio_led
  18. unregister_nasgpio_led
  19. nas_gpio_init
  20. nas_gpio_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * SS4200-E Hardware API
   4  * Copyright (c) 2009, Intel Corporation.
   5  * Copyright IBM Corporation, 2009
   6  *
   7  * Author: Dave Hansen <dave@sr71.net>
   8  */
   9 
  10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/dmi.h>
  13 #include <linux/init.h>
  14 #include <linux/ioport.h>
  15 #include <linux/kernel.h>
  16 #include <linux/leds.h>
  17 #include <linux/module.h>
  18 #include <linux/pci.h>
  19 #include <linux/types.h>
  20 #include <linux/uaccess.h>
  21 
  22 MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
  23 MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
  24 MODULE_LICENSE("GPL");
  25 
  26 /*
  27  * ICH7 LPC/GPIO PCI Config register offsets
  28  */
  29 #define PMBASE          0x040
  30 #define GPIO_BASE       0x048
  31 #define GPIO_CTRL       0x04c
  32 #define GPIO_EN         0x010
  33 
  34 /*
  35  * The ICH7 GPIO register block is 64 bytes in size.
  36  */
  37 #define ICH7_GPIO_SIZE  64
  38 
  39 /*
  40  * Define register offsets within the ICH7 register block.
  41  */
  42 #define GPIO_USE_SEL    0x000
  43 #define GP_IO_SEL       0x004
  44 #define GP_LVL          0x00c
  45 #define GPO_BLINK       0x018
  46 #define GPI_INV         0x030
  47 #define GPIO_USE_SEL2   0x034
  48 #define GP_IO_SEL2      0x038
  49 #define GP_LVL2         0x03c
  50 
  51 /*
  52  * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
  53  */
  54 static const struct pci_device_id ich7_lpc_pci_id[] = {
  55         { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
  56         { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
  57         { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
  58         { } /* NULL entry */
  59 };
  60 
  61 MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
  62 
  63 static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
  64 {
  65         pr_info("detected '%s'\n", id->ident);
  66         return 1;
  67 }
  68 
  69 static bool nodetect;
  70 module_param_named(nodetect, nodetect, bool, 0);
  71 MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
  72 
  73 /*
  74  * struct nas_led_whitelist - List of known good models
  75  *
  76  * Contains the known good models this driver is compatible with.
  77  * When adding a new model try to be as strict as possible. This
  78  * makes it possible to keep the false positives (the model is
  79  * detected as working, but in reality it is not) as low as
  80  * possible.
  81  */
  82 static const struct dmi_system_id nas_led_whitelist[] __initconst = {
  83         {
  84                 .callback = ss4200_led_dmi_callback,
  85                 .ident = "Intel SS4200-E",
  86                 .matches = {
  87                         DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
  88                         DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
  89                         DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
  90                 }
  91         },
  92         {
  93                 /*
  94                  * FUJITSU SIEMENS SCALEO Home Server/SS4200-E
  95                  * BIOS V090L 12/19/2007
  96                  */
  97                 .callback = ss4200_led_dmi_callback,
  98                 .ident = "Fujitsu Siemens SCALEO Home Server",
  99                 .matches = {
 100                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 101                         DMI_MATCH(DMI_PRODUCT_NAME, "SCALEO Home Server"),
 102                         DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
 103                 }
 104         },
 105         {}
 106 };
 107 
 108 /*
 109  * Base I/O address assigned to the Power Management register block
 110  */
 111 static u32 g_pm_io_base;
 112 
 113 /*
 114  * Base I/O address assigned to the ICH7 GPIO register block
 115  */
 116 static u32 nas_gpio_io_base;
 117 
 118 /*
 119  * When we successfully register a region, we are returned a resource.
 120  * We use these to identify which regions we need to release on our way
 121  * back out.
 122  */
 123 static struct resource *gp_gpio_resource;
 124 
 125 struct nasgpio_led {
 126         char *name;
 127         u32 gpio_bit;
 128         struct led_classdev led_cdev;
 129 };
 130 
 131 /*
 132  * gpio_bit(s) are the ICH7 GPIO bit assignments
 133  */
 134 static struct nasgpio_led nasgpio_leds[] = {
 135         { .name = "hdd1:blue:sata",     .gpio_bit = 0 },
 136         { .name = "hdd1:amber:sata",    .gpio_bit = 1 },
 137         { .name = "hdd2:blue:sata",     .gpio_bit = 2 },
 138         { .name = "hdd2:amber:sata",    .gpio_bit = 3 },
 139         { .name = "hdd3:blue:sata",     .gpio_bit = 4 },
 140         { .name = "hdd3:amber:sata",    .gpio_bit = 5 },
 141         { .name = "hdd4:blue:sata",     .gpio_bit = 6 },
 142         { .name = "hdd4:amber:sata",    .gpio_bit = 7 },
 143         { .name = "power:blue:power",   .gpio_bit = 27},
 144         { .name = "power:amber:power",  .gpio_bit = 28},
 145 };
 146 
 147 #define NAS_RECOVERY    0x00000400      /* GPIO10 */
 148 
 149 static struct nasgpio_led *
 150 led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
 151 {
 152         return container_of(led_cdev, struct nasgpio_led, led_cdev);
 153 }
 154 
 155 static struct nasgpio_led *get_led_named(char *name)
 156 {
 157         int i;
 158         for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
 159                 if (strcmp(nasgpio_leds[i].name, name))
 160                         continue;
 161                 return &nasgpio_leds[i];
 162         }
 163         return NULL;
 164 }
 165 
 166 /*
 167  * This protects access to the gpio ports.
 168  */
 169 static DEFINE_SPINLOCK(nasgpio_gpio_lock);
 170 
 171 /*
 172  * There are two gpio ports, one for blinking and the other
 173  * for power.  @port tells us if we're doing blinking or
 174  * power control.
 175  *
 176  * Caller must hold nasgpio_gpio_lock
 177  */
 178 static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
 179                                    u32 port, u32 value)
 180 {
 181         struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
 182         u32 gpio_out;
 183 
 184         gpio_out = inl(nas_gpio_io_base + port);
 185         if (value)
 186                 gpio_out |= (1<<led->gpio_bit);
 187         else
 188                 gpio_out &= ~(1<<led->gpio_bit);
 189 
 190         outl(gpio_out, nas_gpio_io_base + port);
 191 }
 192 
 193 static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
 194                                  u32 port, u32 value)
 195 {
 196         spin_lock(&nasgpio_gpio_lock);
 197         __nasgpio_led_set_attr(led_cdev, port, value);
 198         spin_unlock(&nasgpio_gpio_lock);
 199 }
 200 
 201 static u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
 202 {
 203         struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
 204         u32 gpio_in;
 205 
 206         spin_lock(&nasgpio_gpio_lock);
 207         gpio_in = inl(nas_gpio_io_base + port);
 208         spin_unlock(&nasgpio_gpio_lock);
 209         if (gpio_in & (1<<led->gpio_bit))
 210                 return 1;
 211         return 0;
 212 }
 213 
 214 /*
 215  * There is actual brightness control in the hardware,
 216  * but it is via smbus commands and not implemented
 217  * in this driver.
 218  */
 219 static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
 220                                        enum led_brightness brightness)
 221 {
 222         u32 setting = 0;
 223         if (brightness >= LED_HALF)
 224                 setting = 1;
 225         /*
 226          * Hold the lock across both operations.  This ensures
 227          * consistency so that both the "turn off blinking"
 228          * and "turn light off" operations complete as a set.
 229          */
 230         spin_lock(&nasgpio_gpio_lock);
 231         /*
 232          * LED class documentation asks that past blink state
 233          * be disabled when brightness is turned to zero.
 234          */
 235         if (brightness == 0)
 236                 __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
 237         __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
 238         spin_unlock(&nasgpio_gpio_lock);
 239 }
 240 
 241 static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
 242                                  unsigned long *delay_on,
 243                                  unsigned long *delay_off)
 244 {
 245         u32 setting = 1;
 246         if (!(*delay_on == 0 && *delay_off == 0) &&
 247             !(*delay_on == 500 && *delay_off == 500))
 248                 return -EINVAL;
 249         /*
 250          * These are very approximate.
 251          */
 252         *delay_on = 500;
 253         *delay_off = 500;
 254 
 255         nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
 256 
 257         return 0;
 258 }
 259 
 260 
 261 /*
 262  * Initialize the ICH7 GPIO registers for NAS usage.  The BIOS should have
 263  * already taken care of this, but we will do so in a non destructive manner
 264  * so that we have what we need whether the BIOS did it or not.
 265  */
 266 static int ich7_gpio_init(struct device *dev)
 267 {
 268         int i;
 269         u32 config_data = 0;
 270         u32 all_nas_led = 0;
 271 
 272         for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
 273                 all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
 274 
 275         spin_lock(&nasgpio_gpio_lock);
 276         /*
 277          * We need to enable all of the GPIO lines used by the NAS box,
 278          * so we will read the current Use Selection and add our usage
 279          * to it.  This should be benign with regard to the original
 280          * BIOS configuration.
 281          */
 282         config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
 283         dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
 284         config_data |= all_nas_led + NAS_RECOVERY;
 285         outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
 286         config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
 287         dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
 288 
 289         /*
 290          * The LED GPIO outputs need to be configured for output, so we
 291          * will ensure that all LED lines are cleared for output and the
 292          * RECOVERY line ready for input.  This too should be benign with
 293          * regard to BIOS configuration.
 294          */
 295         config_data = inl(nas_gpio_io_base + GP_IO_SEL);
 296         dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
 297                                         config_data);
 298         config_data &= ~all_nas_led;
 299         config_data |= NAS_RECOVERY;
 300         outl(config_data, nas_gpio_io_base + GP_IO_SEL);
 301         config_data = inl(nas_gpio_io_base + GP_IO_SEL);
 302         dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
 303 
 304         /*
 305          * In our final system, the BIOS will initialize the state of all
 306          * of the LEDs.  For now, we turn them all off (or Low).
 307          */
 308         config_data = inl(nas_gpio_io_base + GP_LVL);
 309         dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
 310         /*
 311          * In our final system, the BIOS will initialize the blink state of all
 312          * of the LEDs.  For now, we turn blink off for all of them.
 313          */
 314         config_data = inl(nas_gpio_io_base + GPO_BLINK);
 315         dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
 316 
 317         /*
 318          * At this moment, I am unsure if anything needs to happen with GPI_INV
 319          */
 320         config_data = inl(nas_gpio_io_base + GPI_INV);
 321         dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
 322 
 323         spin_unlock(&nasgpio_gpio_lock);
 324         return 0;
 325 }
 326 
 327 static void ich7_lpc_cleanup(struct device *dev)
 328 {
 329         /*
 330          * If we were given exclusive use of the GPIO
 331          * I/O Address range, we must return it.
 332          */
 333         if (gp_gpio_resource) {
 334                 dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
 335                 release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
 336                 gp_gpio_resource = NULL;
 337         }
 338 }
 339 
 340 /*
 341  * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
 342  * so we can retrive the required operational information and prepare the GPIO.
 343  */
 344 static struct pci_dev *nas_gpio_pci_dev;
 345 static int ich7_lpc_probe(struct pci_dev *dev,
 346                                     const struct pci_device_id *id)
 347 {
 348         int status;
 349         u32 gc = 0;
 350 
 351         status = pci_enable_device(dev);
 352         if (status) {
 353                 dev_err(&dev->dev, "pci_enable_device failed\n");
 354                 return -EIO;
 355         }
 356 
 357         nas_gpio_pci_dev = dev;
 358         status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
 359         if (status)
 360                 goto out;
 361         g_pm_io_base &= 0x00000ff80;
 362 
 363         status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
 364         if (!(GPIO_EN & gc)) {
 365                 status = -EEXIST;
 366                 dev_info(&dev->dev,
 367                            "ERROR: The LPC GPIO Block has not been enabled.\n");
 368                 goto out;
 369         }
 370 
 371         status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
 372         if (0 > status) {
 373                 dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
 374                 goto out;
 375         }
 376         dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
 377         nas_gpio_io_base &= 0x00000ffc0;
 378 
 379         /*
 380          * Insure that we have exclusive access to the GPIO I/O address range.
 381          */
 382         gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
 383                                           KBUILD_MODNAME);
 384         if (NULL == gp_gpio_resource) {
 385                 dev_info(&dev->dev,
 386                          "ERROR Unable to register GPIO I/O addresses.\n");
 387                 status = -1;
 388                 goto out;
 389         }
 390 
 391         /*
 392          * Initialize the GPIO for NAS/Home Server Use
 393          */
 394         ich7_gpio_init(&dev->dev);
 395 
 396 out:
 397         if (status) {
 398                 ich7_lpc_cleanup(&dev->dev);
 399                 pci_disable_device(dev);
 400         }
 401         return status;
 402 }
 403 
 404 static void ich7_lpc_remove(struct pci_dev *dev)
 405 {
 406         ich7_lpc_cleanup(&dev->dev);
 407         pci_disable_device(dev);
 408 }
 409 
 410 /*
 411  * pci_driver structure passed to the PCI modules
 412  */
 413 static struct pci_driver nas_gpio_pci_driver = {
 414         .name = KBUILD_MODNAME,
 415         .id_table = ich7_lpc_pci_id,
 416         .probe = ich7_lpc_probe,
 417         .remove = ich7_lpc_remove,
 418 };
 419 
 420 static struct led_classdev *get_classdev_for_led_nr(int nr)
 421 {
 422         struct nasgpio_led *nas_led = &nasgpio_leds[nr];
 423         struct led_classdev *led = &nas_led->led_cdev;
 424         return led;
 425 }
 426 
 427 
 428 static void set_power_light_amber_noblink(void)
 429 {
 430         struct nasgpio_led *amber = get_led_named("power:amber:power");
 431         struct nasgpio_led *blue = get_led_named("power:blue:power");
 432 
 433         if (!amber || !blue)
 434                 return;
 435         /*
 436          * LED_OFF implies disabling future blinking
 437          */
 438         pr_debug("setting blue off and amber on\n");
 439 
 440         nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
 441         nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
 442 }
 443 
 444 static ssize_t nas_led_blink_show(struct device *dev,
 445                                   struct device_attribute *attr, char *buf)
 446 {
 447         struct led_classdev *led = dev_get_drvdata(dev);
 448         int blinking = 0;
 449         if (nasgpio_led_get_attr(led, GPO_BLINK))
 450                 blinking = 1;
 451         return sprintf(buf, "%u\n", blinking);
 452 }
 453 
 454 static ssize_t nas_led_blink_store(struct device *dev,
 455                                    struct device_attribute *attr,
 456                                    const char *buf, size_t size)
 457 {
 458         int ret;
 459         struct led_classdev *led = dev_get_drvdata(dev);
 460         unsigned long blink_state;
 461 
 462         ret = kstrtoul(buf, 10, &blink_state);
 463         if (ret)
 464                 return ret;
 465 
 466         nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
 467 
 468         return size;
 469 }
 470 
 471 static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store);
 472 
 473 static struct attribute *nasgpio_led_attrs[] = {
 474         &dev_attr_blink.attr,
 475         NULL
 476 };
 477 ATTRIBUTE_GROUPS(nasgpio_led);
 478 
 479 static int register_nasgpio_led(int led_nr)
 480 {
 481         int ret;
 482         struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
 483         struct led_classdev *led = get_classdev_for_led_nr(led_nr);
 484 
 485         led->name = nas_led->name;
 486         led->brightness = LED_OFF;
 487         if (nasgpio_led_get_attr(led, GP_LVL))
 488                 led->brightness = LED_FULL;
 489         led->brightness_set = nasgpio_led_set_brightness;
 490         led->blink_set = nasgpio_led_set_blink;
 491         led->groups = nasgpio_led_groups;
 492         ret = led_classdev_register(&nas_gpio_pci_dev->dev, led);
 493         if (ret)
 494                 return ret;
 495 
 496         return 0;
 497 }
 498 
 499 static void unregister_nasgpio_led(int led_nr)
 500 {
 501         struct led_classdev *led = get_classdev_for_led_nr(led_nr);
 502         led_classdev_unregister(led);
 503 }
 504 /*
 505  * module load/initialization
 506  */
 507 static int __init nas_gpio_init(void)
 508 {
 509         int i;
 510         int ret = 0;
 511         int nr_devices = 0;
 512 
 513         nr_devices = dmi_check_system(nas_led_whitelist);
 514         if (nodetect) {
 515                 pr_info("skipping hardware autodetection\n");
 516                 pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
 517                 nr_devices++;
 518         }
 519 
 520         if (nr_devices <= 0) {
 521                 pr_info("no LED devices found\n");
 522                 return -ENODEV;
 523         }
 524 
 525         pr_info("registering PCI driver\n");
 526         ret = pci_register_driver(&nas_gpio_pci_driver);
 527         if (ret)
 528                 return ret;
 529         for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
 530                 ret = register_nasgpio_led(i);
 531                 if (ret)
 532                         goto out_err;
 533         }
 534         /*
 535          * When the system powers on, the BIOS leaves the power
 536          * light blue and blinking.  This will turn it solid
 537          * amber once the driver is loaded.
 538          */
 539         set_power_light_amber_noblink();
 540         return 0;
 541 out_err:
 542         for (i--; i >= 0; i--)
 543                 unregister_nasgpio_led(i);
 544         pci_unregister_driver(&nas_gpio_pci_driver);
 545         return ret;
 546 }
 547 
 548 /*
 549  * module unload
 550  */
 551 static void __exit nas_gpio_exit(void)
 552 {
 553         int i;
 554         pr_info("Unregistering driver\n");
 555         for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
 556                 unregister_nasgpio_led(i);
 557         pci_unregister_driver(&nas_gpio_pci_driver);
 558 }
 559 
 560 module_init(nas_gpio_init);
 561 module_exit(nas_gpio_exit);

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