0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011
0012 #include <linux/dmi.h>
0013 #include <linux/init.h>
0014 #include <linux/ioport.h>
0015 #include <linux/kernel.h>
0016 #include <linux/leds.h>
0017 #include <linux/module.h>
0018 #include <linux/pci.h>
0019 #include <linux/types.h>
0020 #include <linux/uaccess.h>
0021
0022 MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
0023 MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
0024 MODULE_LICENSE("GPL");
0025
0026
0027
0028
0029 #define PMBASE 0x040
0030 #define GPIO_BASE 0x048
0031 #define GPIO_CTRL 0x04c
0032 #define GPIO_EN 0x010
0033
0034
0035
0036
0037 #define ICH7_GPIO_SIZE 64
0038
0039
0040
0041
0042 #define GPIO_USE_SEL 0x000
0043 #define GP_IO_SEL 0x004
0044 #define GP_LVL 0x00c
0045 #define GPO_BLINK 0x018
0046 #define GPI_INV 0x030
0047 #define GPIO_USE_SEL2 0x034
0048 #define GP_IO_SEL2 0x038
0049 #define GP_LVL2 0x03c
0050
0051
0052
0053
0054 static const struct pci_device_id ich7_lpc_pci_id[] = {
0055 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
0056 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
0057 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
0058 { }
0059 };
0060
0061 MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
0062
0063 static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
0064 {
0065 pr_info("detected '%s'\n", id->ident);
0066 return 1;
0067 }
0068
0069 static bool nodetect;
0070 module_param_named(nodetect, nodetect, bool, 0);
0071 MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 static const struct dmi_system_id nas_led_whitelist[] __initconst = {
0083 {
0084 .callback = ss4200_led_dmi_callback,
0085 .ident = "Intel SS4200-E",
0086 .matches = {
0087 DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
0088 DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
0089 DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
0090 }
0091 },
0092 {
0093
0094
0095
0096
0097 .callback = ss4200_led_dmi_callback,
0098 .ident = "Fujitsu Siemens SCALEO Home Server",
0099 .matches = {
0100 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
0101 DMI_MATCH(DMI_PRODUCT_NAME, "SCALEO Home Server"),
0102 DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
0103 }
0104 },
0105 {}
0106 };
0107
0108
0109
0110
0111 static u32 g_pm_io_base;
0112
0113
0114
0115
0116 static u32 nas_gpio_io_base;
0117
0118
0119
0120
0121
0122
0123 static struct resource *gp_gpio_resource;
0124
0125 struct nasgpio_led {
0126 char *name;
0127 u32 gpio_bit;
0128 struct led_classdev led_cdev;
0129 };
0130
0131
0132
0133
0134 static struct nasgpio_led nasgpio_leds[] = {
0135 { .name = "hdd1:blue:sata", .gpio_bit = 0 },
0136 { .name = "hdd1:amber:sata", .gpio_bit = 1 },
0137 { .name = "hdd2:blue:sata", .gpio_bit = 2 },
0138 { .name = "hdd2:amber:sata", .gpio_bit = 3 },
0139 { .name = "hdd3:blue:sata", .gpio_bit = 4 },
0140 { .name = "hdd3:amber:sata", .gpio_bit = 5 },
0141 { .name = "hdd4:blue:sata", .gpio_bit = 6 },
0142 { .name = "hdd4:amber:sata", .gpio_bit = 7 },
0143 { .name = "power:blue:power", .gpio_bit = 27},
0144 { .name = "power:amber:power", .gpio_bit = 28},
0145 };
0146
0147 #define NAS_RECOVERY 0x00000400
0148
0149 static struct nasgpio_led *
0150 led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
0151 {
0152 return container_of(led_cdev, struct nasgpio_led, led_cdev);
0153 }
0154
0155 static struct nasgpio_led *get_led_named(char *name)
0156 {
0157 int i;
0158 for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
0159 if (strcmp(nasgpio_leds[i].name, name))
0160 continue;
0161 return &nasgpio_leds[i];
0162 }
0163 return NULL;
0164 }
0165
0166
0167
0168
0169 static DEFINE_SPINLOCK(nasgpio_gpio_lock);
0170
0171
0172
0173
0174
0175
0176
0177
0178 static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
0179 u32 port, u32 value)
0180 {
0181 struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
0182 u32 gpio_out;
0183
0184 gpio_out = inl(nas_gpio_io_base + port);
0185 if (value)
0186 gpio_out |= (1<<led->gpio_bit);
0187 else
0188 gpio_out &= ~(1<<led->gpio_bit);
0189
0190 outl(gpio_out, nas_gpio_io_base + port);
0191 }
0192
0193 static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
0194 u32 port, u32 value)
0195 {
0196 spin_lock(&nasgpio_gpio_lock);
0197 __nasgpio_led_set_attr(led_cdev, port, value);
0198 spin_unlock(&nasgpio_gpio_lock);
0199 }
0200
0201 static u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
0202 {
0203 struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
0204 u32 gpio_in;
0205
0206 spin_lock(&nasgpio_gpio_lock);
0207 gpio_in = inl(nas_gpio_io_base + port);
0208 spin_unlock(&nasgpio_gpio_lock);
0209 if (gpio_in & (1<<led->gpio_bit))
0210 return 1;
0211 return 0;
0212 }
0213
0214
0215
0216
0217
0218
0219 static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
0220 enum led_brightness brightness)
0221 {
0222 u32 setting = 0;
0223 if (brightness >= LED_HALF)
0224 setting = 1;
0225
0226
0227
0228
0229
0230 spin_lock(&nasgpio_gpio_lock);
0231
0232
0233
0234
0235 if (brightness == 0)
0236 __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
0237 __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
0238 spin_unlock(&nasgpio_gpio_lock);
0239 }
0240
0241 static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
0242 unsigned long *delay_on,
0243 unsigned long *delay_off)
0244 {
0245 u32 setting = 1;
0246 if (!(*delay_on == 0 && *delay_off == 0) &&
0247 !(*delay_on == 500 && *delay_off == 500))
0248 return -EINVAL;
0249
0250
0251
0252 *delay_on = 500;
0253 *delay_off = 500;
0254
0255 nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
0256
0257 return 0;
0258 }
0259
0260
0261
0262
0263
0264
0265
0266 static int ich7_gpio_init(struct device *dev)
0267 {
0268 int i;
0269 u32 config_data = 0;
0270 u32 all_nas_led = 0;
0271
0272 for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
0273 all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
0274
0275 spin_lock(&nasgpio_gpio_lock);
0276
0277
0278
0279
0280
0281
0282 config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
0283 dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
0284 config_data |= all_nas_led + NAS_RECOVERY;
0285 outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
0286 config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
0287 dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
0288
0289
0290
0291
0292
0293
0294
0295 config_data = inl(nas_gpio_io_base + GP_IO_SEL);
0296 dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
0297 config_data);
0298 config_data &= ~all_nas_led;
0299 config_data |= NAS_RECOVERY;
0300 outl(config_data, nas_gpio_io_base + GP_IO_SEL);
0301 config_data = inl(nas_gpio_io_base + GP_IO_SEL);
0302 dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
0303
0304
0305
0306
0307
0308 config_data = inl(nas_gpio_io_base + GP_LVL);
0309 dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
0310
0311
0312
0313
0314 config_data = inl(nas_gpio_io_base + GPO_BLINK);
0315 dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
0316
0317
0318
0319
0320 config_data = inl(nas_gpio_io_base + GPI_INV);
0321 dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
0322
0323 spin_unlock(&nasgpio_gpio_lock);
0324 return 0;
0325 }
0326
0327 static void ich7_lpc_cleanup(struct device *dev)
0328 {
0329
0330
0331
0332
0333 if (gp_gpio_resource) {
0334 dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
0335 release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
0336 gp_gpio_resource = NULL;
0337 }
0338 }
0339
0340
0341
0342
0343
0344 static struct pci_dev *nas_gpio_pci_dev;
0345 static int ich7_lpc_probe(struct pci_dev *dev,
0346 const struct pci_device_id *id)
0347 {
0348 int status;
0349 u32 gc = 0;
0350
0351 status = pci_enable_device(dev);
0352 if (status) {
0353 dev_err(&dev->dev, "pci_enable_device failed\n");
0354 return -EIO;
0355 }
0356
0357 nas_gpio_pci_dev = dev;
0358 status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
0359 if (status)
0360 goto out;
0361 g_pm_io_base &= 0x00000ff80;
0362
0363 status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
0364 if (!(GPIO_EN & gc)) {
0365 status = -EEXIST;
0366 dev_info(&dev->dev,
0367 "ERROR: The LPC GPIO Block has not been enabled.\n");
0368 goto out;
0369 }
0370
0371 status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
0372 if (0 > status) {
0373 dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
0374 goto out;
0375 }
0376 dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
0377 nas_gpio_io_base &= 0x00000ffc0;
0378
0379
0380
0381
0382 gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
0383 KBUILD_MODNAME);
0384 if (NULL == gp_gpio_resource) {
0385 dev_info(&dev->dev,
0386 "ERROR Unable to register GPIO I/O addresses.\n");
0387 status = -1;
0388 goto out;
0389 }
0390
0391
0392
0393
0394 ich7_gpio_init(&dev->dev);
0395
0396 out:
0397 if (status) {
0398 ich7_lpc_cleanup(&dev->dev);
0399 pci_disable_device(dev);
0400 }
0401 return status;
0402 }
0403
0404 static void ich7_lpc_remove(struct pci_dev *dev)
0405 {
0406 ich7_lpc_cleanup(&dev->dev);
0407 pci_disable_device(dev);
0408 }
0409
0410
0411
0412
0413 static struct pci_driver nas_gpio_pci_driver = {
0414 .name = KBUILD_MODNAME,
0415 .id_table = ich7_lpc_pci_id,
0416 .probe = ich7_lpc_probe,
0417 .remove = ich7_lpc_remove,
0418 };
0419
0420 static struct led_classdev *get_classdev_for_led_nr(int nr)
0421 {
0422 struct nasgpio_led *nas_led = &nasgpio_leds[nr];
0423 struct led_classdev *led = &nas_led->led_cdev;
0424 return led;
0425 }
0426
0427
0428 static void set_power_light_amber_noblink(void)
0429 {
0430 struct nasgpio_led *amber = get_led_named("power:amber:power");
0431 struct nasgpio_led *blue = get_led_named("power:blue:power");
0432
0433 if (!amber || !blue)
0434 return;
0435
0436
0437
0438 pr_debug("setting blue off and amber on\n");
0439
0440 nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
0441 nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
0442 }
0443
0444 static ssize_t blink_show(struct device *dev,
0445 struct device_attribute *attr, char *buf)
0446 {
0447 struct led_classdev *led = dev_get_drvdata(dev);
0448 int blinking = 0;
0449 if (nasgpio_led_get_attr(led, GPO_BLINK))
0450 blinking = 1;
0451 return sprintf(buf, "%u\n", blinking);
0452 }
0453
0454 static ssize_t blink_store(struct device *dev,
0455 struct device_attribute *attr,
0456 const char *buf, size_t size)
0457 {
0458 int ret;
0459 struct led_classdev *led = dev_get_drvdata(dev);
0460 unsigned long blink_state;
0461
0462 ret = kstrtoul(buf, 10, &blink_state);
0463 if (ret)
0464 return ret;
0465
0466 nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
0467
0468 return size;
0469 }
0470
0471 static DEVICE_ATTR_RW(blink);
0472
0473 static struct attribute *nasgpio_led_attrs[] = {
0474 &dev_attr_blink.attr,
0475 NULL
0476 };
0477 ATTRIBUTE_GROUPS(nasgpio_led);
0478
0479 static int register_nasgpio_led(int led_nr)
0480 {
0481 struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
0482 struct led_classdev *led = get_classdev_for_led_nr(led_nr);
0483
0484 led->name = nas_led->name;
0485 led->brightness = LED_OFF;
0486 if (nasgpio_led_get_attr(led, GP_LVL))
0487 led->brightness = LED_FULL;
0488 led->brightness_set = nasgpio_led_set_brightness;
0489 led->blink_set = nasgpio_led_set_blink;
0490 led->groups = nasgpio_led_groups;
0491
0492 return led_classdev_register(&nas_gpio_pci_dev->dev, led);
0493 }
0494
0495 static void unregister_nasgpio_led(int led_nr)
0496 {
0497 struct led_classdev *led = get_classdev_for_led_nr(led_nr);
0498 led_classdev_unregister(led);
0499 }
0500
0501
0502
0503 static int __init nas_gpio_init(void)
0504 {
0505 int i;
0506 int ret = 0;
0507 int nr_devices = 0;
0508
0509 nr_devices = dmi_check_system(nas_led_whitelist);
0510 if (nodetect) {
0511 pr_info("skipping hardware autodetection\n");
0512 pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
0513 nr_devices++;
0514 }
0515
0516 if (nr_devices <= 0) {
0517 pr_info("no LED devices found\n");
0518 return -ENODEV;
0519 }
0520
0521 pr_info("registering PCI driver\n");
0522 ret = pci_register_driver(&nas_gpio_pci_driver);
0523 if (ret)
0524 return ret;
0525 for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
0526 ret = register_nasgpio_led(i);
0527 if (ret)
0528 goto out_err;
0529 }
0530
0531
0532
0533
0534
0535 set_power_light_amber_noblink();
0536 return 0;
0537 out_err:
0538 for (i--; i >= 0; i--)
0539 unregister_nasgpio_led(i);
0540 pci_unregister_driver(&nas_gpio_pci_driver);
0541 return ret;
0542 }
0543
0544
0545
0546
0547 static void __exit nas_gpio_exit(void)
0548 {
0549 int i;
0550 pr_info("Unregistering driver\n");
0551 for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
0552 unregister_nasgpio_led(i);
0553 pci_unregister_driver(&nas_gpio_pci_driver);
0554 }
0555
0556 module_init(nas_gpio_init);
0557 module_exit(nas_gpio_exit);