Version:  2.0.40 2.2.26 2.4.37 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7

Linux/drivers/leds/leds-ss4200.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us