diff options
-rw-r--r-- | arch/x86/Kconfig | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/mrst.h | 4 | ||||
-rw-r--r-- | arch/x86/platform/mrst/mrst.c | 515 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 5 | ||||
-rw-r--r-- | include/linux/sfi.h | 8 |
5 files changed, 527 insertions, 7 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e8327686d3c5..b306b84fc8c8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -385,6 +385,8 @@ config X86_MRST | |||
385 | depends on X86_EXTENDED_PLATFORM | 385 | depends on X86_EXTENDED_PLATFORM |
386 | depends on X86_IO_APIC | 386 | depends on X86_IO_APIC |
387 | select APB_TIMER | 387 | select APB_TIMER |
388 | select I2C | ||
389 | select SPI | ||
388 | ---help--- | 390 | ---help--- |
389 | Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin | 391 | Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin |
390 | Internet Device(MID) platform. Moorestown consists of two chips: | 392 | Internet Device(MID) platform. Moorestown consists of two chips: |
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 4a711a684b17..283debd29fc0 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h | |||
@@ -50,4 +50,8 @@ extern void mrst_early_console_init(void); | |||
50 | 50 | ||
51 | extern struct console early_hsu_console; | 51 | extern struct console early_hsu_console; |
52 | extern void hsu_early_console_init(void); | 52 | extern void hsu_early_console_init(void); |
53 | |||
54 | extern void intel_scu_devices_create(void); | ||
55 | extern void intel_scu_devices_destroy(void); | ||
56 | |||
53 | #endif /* _ASM_X86_MRST_H */ | 57 | #endif /* _ASM_X86_MRST_H */ |
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 79ae68154e87..cfa1af24edd5 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c | |||
@@ -9,9 +9,19 @@ | |||
9 | * as published by the Free Software Foundation; version 2 | 9 | * as published by the Free Software Foundation; version 2 |
10 | * of the License. | 10 | * of the License. |
11 | */ | 11 | */ |
12 | |||
13 | #define pr_fmt(fmt) "mrst: " fmt | ||
14 | |||
12 | #include <linux/init.h> | 15 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
14 | #include <linux/sfi.h> | 17 | #include <linux/sfi.h> |
18 | #include <linux/intel_pmic_gpio.h> | ||
19 | #include <linux/spi/spi.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/i2c/pca953x.h> | ||
22 | #include <linux/gpio_keys.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/platform_device.h> | ||
15 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
16 | #include <linux/module.h> | 26 | #include <linux/module.h> |
17 | 27 | ||
@@ -23,8 +33,10 @@ | |||
23 | #include <asm/mrst.h> | 33 | #include <asm/mrst.h> |
24 | #include <asm/io.h> | 34 | #include <asm/io.h> |
25 | #include <asm/i8259.h> | 35 | #include <asm/i8259.h> |
36 | #include <asm/intel_scu_ipc.h> | ||
26 | #include <asm/apb_timer.h> | 37 | #include <asm/apb_timer.h> |
27 | 38 | ||
39 | |||
28 | /* | 40 | /* |
29 | * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, | 41 | * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, |
30 | * cmdline option x86_mrst_timer can be used to override the configuration | 42 | * cmdline option x86_mrst_timer can be used to override the configuration |
@@ -102,10 +114,10 @@ static int __init sfi_parse_mtmr(struct sfi_table_header *table) | |||
102 | memcpy(sfi_mtimer_array, pentry, totallen); | 114 | memcpy(sfi_mtimer_array, pentry, totallen); |
103 | } | 115 | } |
104 | 116 | ||
105 | printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num); | 117 | pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); |
106 | pentry = sfi_mtimer_array; | 118 | pentry = sfi_mtimer_array; |
107 | for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | 119 | for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { |
108 | printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz," | 120 | pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," |
109 | " irq = %d\n", totallen, (u32)pentry->phys_addr, | 121 | " irq = %d\n", totallen, (u32)pentry->phys_addr, |
110 | pentry->freq_hz, pentry->irq); | 122 | pentry->freq_hz, pentry->irq); |
111 | if (!pentry->irq) | 123 | if (!pentry->irq) |
@@ -176,10 +188,10 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) | |||
176 | memcpy(sfi_mrtc_array, pentry, totallen); | 188 | memcpy(sfi_mrtc_array, pentry, totallen); |
177 | } | 189 | } |
178 | 190 | ||
179 | printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num); | 191 | pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); |
180 | pentry = sfi_mrtc_array; | 192 | pentry = sfi_mrtc_array; |
181 | for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { | 193 | for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { |
182 | printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n", | 194 | pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", |
183 | totallen, (u32)pentry->phys_addr, pentry->irq); | 195 | totallen, (u32)pentry->phys_addr, pentry->irq); |
184 | mp_irq.type = MP_IOAPIC; | 196 | mp_irq.type = MP_IOAPIC; |
185 | mp_irq.irqtype = mp_INT; | 197 | mp_irq.irqtype = mp_INT; |
@@ -309,3 +321,498 @@ static inline int __init setup_x86_mrst_timer(char *arg) | |||
309 | return 0; | 321 | return 0; |
310 | } | 322 | } |
311 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); | 323 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); |
324 | |||
325 | /* | ||
326 | * Parsing GPIO table first, since the DEVS table will need this table | ||
327 | * to map the pin name to the actual pin. | ||
328 | */ | ||
329 | static struct sfi_gpio_table_entry *gpio_table; | ||
330 | static int gpio_num_entry; | ||
331 | |||
332 | static int __init sfi_parse_gpio(struct sfi_table_header *table) | ||
333 | { | ||
334 | struct sfi_table_simple *sb; | ||
335 | struct sfi_gpio_table_entry *pentry; | ||
336 | int num, i; | ||
337 | |||
338 | if (gpio_table) | ||
339 | return 0; | ||
340 | sb = (struct sfi_table_simple *)table; | ||
341 | num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); | ||
342 | pentry = (struct sfi_gpio_table_entry *)sb->pentry; | ||
343 | |||
344 | gpio_table = (struct sfi_gpio_table_entry *) | ||
345 | kmalloc(num * sizeof(*pentry), GFP_KERNEL); | ||
346 | if (!gpio_table) | ||
347 | return -1; | ||
348 | memcpy(gpio_table, pentry, num * sizeof(*pentry)); | ||
349 | gpio_num_entry = num; | ||
350 | |||
351 | pr_debug("GPIO pin info:\n"); | ||
352 | for (i = 0; i < num; i++, pentry++) | ||
353 | pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," | ||
354 | " pin = %d\n", i, | ||
355 | pentry->controller_name, | ||
356 | pentry->pin_name, | ||
357 | pentry->pin_no); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int get_gpio_by_name(const char *name) | ||
362 | { | ||
363 | struct sfi_gpio_table_entry *pentry = gpio_table; | ||
364 | int i; | ||
365 | |||
366 | if (!pentry) | ||
367 | return -1; | ||
368 | for (i = 0; i < gpio_num_entry; i++, pentry++) { | ||
369 | if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) | ||
370 | return pentry->pin_no; | ||
371 | } | ||
372 | return -1; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Here defines the array of devices platform data that IAFW would export | ||
377 | * through SFI "DEVS" table, we use name and type to match the device and | ||
378 | * its platform data. | ||
379 | */ | ||
380 | struct devs_id { | ||
381 | char name[SFI_NAME_LEN + 1]; | ||
382 | u8 type; | ||
383 | u8 delay; | ||
384 | void *(*get_platform_data)(void *info); | ||
385 | }; | ||
386 | |||
387 | /* the offset for the mapping of global gpio pin to irq */ | ||
388 | #define MRST_IRQ_OFFSET 0x100 | ||
389 | |||
390 | static void __init *pmic_gpio_platform_data(void *info) | ||
391 | { | ||
392 | static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; | ||
393 | int gpio_base = get_gpio_by_name("pmic_gpio_base"); | ||
394 | |||
395 | if (gpio_base == -1) | ||
396 | gpio_base = 64; | ||
397 | pmic_gpio_pdata.gpio_base = gpio_base; | ||
398 | pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET; | ||
399 | pmic_gpio_pdata.gpiointr = 0xffffeff8; | ||
400 | |||
401 | return &pmic_gpio_pdata; | ||
402 | } | ||
403 | |||
404 | static void __init *max3111_platform_data(void *info) | ||
405 | { | ||
406 | struct spi_board_info *spi_info = info; | ||
407 | int intr = get_gpio_by_name("max3111_int"); | ||
408 | |||
409 | if (intr == -1) | ||
410 | return NULL; | ||
411 | spi_info->irq = intr + MRST_IRQ_OFFSET; | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | /* we have multiple max7315 on the board ... */ | ||
416 | #define MAX7315_NUM 2 | ||
417 | static void __init *max7315_platform_data(void *info) | ||
418 | { | ||
419 | static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; | ||
420 | static int nr; | ||
421 | struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; | ||
422 | struct i2c_board_info *i2c_info = info; | ||
423 | int gpio_base, intr; | ||
424 | char base_pin_name[SFI_NAME_LEN + 1]; | ||
425 | char intr_pin_name[SFI_NAME_LEN + 1]; | ||
426 | |||
427 | if (nr == MAX7315_NUM) { | ||
428 | pr_err("too many max7315s, we only support %d\n", | ||
429 | MAX7315_NUM); | ||
430 | return NULL; | ||
431 | } | ||
432 | /* we have several max7315 on the board, we only need load several | ||
433 | * instances of the same pca953x driver to cover them | ||
434 | */ | ||
435 | strcpy(i2c_info->type, "max7315"); | ||
436 | if (nr++) { | ||
437 | sprintf(base_pin_name, "max7315_%d_base", nr); | ||
438 | sprintf(intr_pin_name, "max7315_%d_int", nr); | ||
439 | } else { | ||
440 | strcpy(base_pin_name, "max7315_base"); | ||
441 | strcpy(intr_pin_name, "max7315_int"); | ||
442 | } | ||
443 | |||
444 | gpio_base = get_gpio_by_name(base_pin_name); | ||
445 | intr = get_gpio_by_name(intr_pin_name); | ||
446 | |||
447 | if (gpio_base == -1) | ||
448 | return NULL; | ||
449 | max7315->gpio_base = gpio_base; | ||
450 | if (intr != -1) { | ||
451 | i2c_info->irq = intr + MRST_IRQ_OFFSET; | ||
452 | max7315->irq_base = gpio_base + MRST_IRQ_OFFSET; | ||
453 | } else { | ||
454 | i2c_info->irq = -1; | ||
455 | max7315->irq_base = -1; | ||
456 | } | ||
457 | return max7315; | ||
458 | } | ||
459 | |||
460 | static void __init *emc1403_platform_data(void *info) | ||
461 | { | ||
462 | static short intr2nd_pdata; | ||
463 | struct i2c_board_info *i2c_info = info; | ||
464 | int intr = get_gpio_by_name("thermal_int"); | ||
465 | int intr2nd = get_gpio_by_name("thermal_alert"); | ||
466 | |||
467 | if (intr == -1 || intr2nd == -1) | ||
468 | return NULL; | ||
469 | |||
470 | i2c_info->irq = intr + MRST_IRQ_OFFSET; | ||
471 | intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | ||
472 | |||
473 | return &intr2nd_pdata; | ||
474 | } | ||
475 | |||
476 | static void __init *lis331dl_platform_data(void *info) | ||
477 | { | ||
478 | static short intr2nd_pdata; | ||
479 | struct i2c_board_info *i2c_info = info; | ||
480 | int intr = get_gpio_by_name("accel_int"); | ||
481 | int intr2nd = get_gpio_by_name("accel_2"); | ||
482 | |||
483 | if (intr == -1 || intr2nd == -1) | ||
484 | return NULL; | ||
485 | |||
486 | i2c_info->irq = intr + MRST_IRQ_OFFSET; | ||
487 | intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | ||
488 | |||
489 | return &intr2nd_pdata; | ||
490 | } | ||
491 | |||
492 | static const struct devs_id __initconst device_ids[] = { | ||
493 | {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, | ||
494 | {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, | ||
495 | {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | ||
496 | {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | ||
497 | {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, | ||
498 | {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, | ||
499 | {}, | ||
500 | }; | ||
501 | |||
502 | #define MAX_IPCDEVS 24 | ||
503 | static struct platform_device *ipc_devs[MAX_IPCDEVS]; | ||
504 | static int ipc_next_dev; | ||
505 | |||
506 | #define MAX_SCU_SPI 24 | ||
507 | static struct spi_board_info *spi_devs[MAX_SCU_SPI]; | ||
508 | static int spi_next_dev; | ||
509 | |||
510 | #define MAX_SCU_I2C 24 | ||
511 | static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; | ||
512 | static int i2c_bus[MAX_SCU_I2C]; | ||
513 | static int i2c_next_dev; | ||
514 | |||
515 | static void __init intel_scu_device_register(struct platform_device *pdev) | ||
516 | { | ||
517 | if(ipc_next_dev == MAX_IPCDEVS) | ||
518 | pr_err("too many SCU IPC devices"); | ||
519 | else | ||
520 | ipc_devs[ipc_next_dev++] = pdev; | ||
521 | } | ||
522 | |||
523 | static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) | ||
524 | { | ||
525 | struct spi_board_info *new_dev; | ||
526 | |||
527 | if (spi_next_dev == MAX_SCU_SPI) { | ||
528 | pr_err("too many SCU SPI devices"); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); | ||
533 | if (!new_dev) { | ||
534 | pr_err("failed to alloc mem for delayed spi dev %s\n", | ||
535 | sdev->modalias); | ||
536 | return; | ||
537 | } | ||
538 | memcpy(new_dev, sdev, sizeof(*sdev)); | ||
539 | |||
540 | spi_devs[spi_next_dev++] = new_dev; | ||
541 | } | ||
542 | |||
543 | static void __init intel_scu_i2c_device_register(int bus, | ||
544 | struct i2c_board_info *idev) | ||
545 | { | ||
546 | struct i2c_board_info *new_dev; | ||
547 | |||
548 | if (i2c_next_dev == MAX_SCU_I2C) { | ||
549 | pr_err("too many SCU I2C devices"); | ||
550 | return; | ||
551 | } | ||
552 | |||
553 | new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); | ||
554 | if (!new_dev) { | ||
555 | pr_err("failed to alloc mem for delayed i2c dev %s\n", | ||
556 | idev->type); | ||
557 | return; | ||
558 | } | ||
559 | memcpy(new_dev, idev, sizeof(*idev)); | ||
560 | |||
561 | i2c_bus[i2c_next_dev] = bus; | ||
562 | i2c_devs[i2c_next_dev++] = new_dev; | ||
563 | } | ||
564 | |||
565 | /* Called by IPC driver */ | ||
566 | void intel_scu_devices_create(void) | ||
567 | { | ||
568 | int i; | ||
569 | |||
570 | for (i = 0; i < ipc_next_dev; i++) | ||
571 | platform_device_add(ipc_devs[i]); | ||
572 | |||
573 | for (i = 0; i < spi_next_dev; i++) | ||
574 | spi_register_board_info(spi_devs[i], 1); | ||
575 | |||
576 | for (i = 0; i < i2c_next_dev; i++) { | ||
577 | struct i2c_adapter *adapter; | ||
578 | struct i2c_client *client; | ||
579 | |||
580 | adapter = i2c_get_adapter(i2c_bus[i]); | ||
581 | if (adapter) { | ||
582 | client = i2c_new_device(adapter, i2c_devs[i]); | ||
583 | if (!client) | ||
584 | pr_err("can't create i2c device %s\n", | ||
585 | i2c_devs[i]->type); | ||
586 | } else | ||
587 | i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); | ||
588 | } | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(intel_scu_devices_create); | ||
591 | |||
592 | /* Called by IPC driver */ | ||
593 | void intel_scu_devices_destroy(void) | ||
594 | { | ||
595 | int i; | ||
596 | |||
597 | for (i = 0; i < ipc_next_dev; i++) | ||
598 | platform_device_del(ipc_devs[i]); | ||
599 | } | ||
600 | EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); | ||
601 | |||
602 | static void __init install_irq_resource(struct platform_device *pdev, int irq) | ||
603 | { | ||
604 | /* Single threaded */ | ||
605 | static struct resource __initdata res = { | ||
606 | .name = "IRQ", | ||
607 | .flags = IORESOURCE_IRQ, | ||
608 | }; | ||
609 | res.start = irq; | ||
610 | platform_device_add_resources(pdev, &res, 1); | ||
611 | } | ||
612 | |||
613 | static void __init sfi_handle_ipc_dev(struct platform_device *pdev) | ||
614 | { | ||
615 | const struct devs_id *dev = device_ids; | ||
616 | void *pdata = NULL; | ||
617 | |||
618 | while (dev->name[0]) { | ||
619 | if (dev->type == SFI_DEV_TYPE_IPC && | ||
620 | !strncmp(dev->name, pdev->name, SFI_NAME_LEN)) { | ||
621 | pdata = dev->get_platform_data(pdev); | ||
622 | break; | ||
623 | } | ||
624 | dev++; | ||
625 | } | ||
626 | pdev->dev.platform_data = pdata; | ||
627 | intel_scu_device_register(pdev); | ||
628 | } | ||
629 | |||
630 | static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) | ||
631 | { | ||
632 | const struct devs_id *dev = device_ids; | ||
633 | void *pdata = NULL; | ||
634 | |||
635 | while (dev->name[0]) { | ||
636 | if (dev->type == SFI_DEV_TYPE_SPI && | ||
637 | !strncmp(dev->name, spi_info->modalias, SFI_NAME_LEN)) { | ||
638 | pdata = dev->get_platform_data(spi_info); | ||
639 | break; | ||
640 | } | ||
641 | dev++; | ||
642 | } | ||
643 | spi_info->platform_data = pdata; | ||
644 | if (dev->delay) | ||
645 | intel_scu_spi_device_register(spi_info); | ||
646 | else | ||
647 | spi_register_board_info(spi_info, 1); | ||
648 | } | ||
649 | |||
650 | static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) | ||
651 | { | ||
652 | const struct devs_id *dev = device_ids; | ||
653 | void *pdata = NULL; | ||
654 | |||
655 | while (dev->name[0]) { | ||
656 | if (dev->type == SFI_DEV_TYPE_I2C && | ||
657 | !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { | ||
658 | pdata = dev->get_platform_data(i2c_info); | ||
659 | break; | ||
660 | } | ||
661 | dev++; | ||
662 | } | ||
663 | i2c_info->platform_data = pdata; | ||
664 | |||
665 | if (dev->delay) | ||
666 | intel_scu_i2c_device_register(bus, i2c_info); | ||
667 | else | ||
668 | i2c_register_board_info(bus, i2c_info, 1); | ||
669 | } | ||
670 | |||
671 | |||
672 | static int __init sfi_parse_devs(struct sfi_table_header *table) | ||
673 | { | ||
674 | struct sfi_table_simple *sb; | ||
675 | struct sfi_device_table_entry *pentry; | ||
676 | struct spi_board_info spi_info; | ||
677 | struct i2c_board_info i2c_info; | ||
678 | struct platform_device *pdev; | ||
679 | int num, i, bus; | ||
680 | int ioapic; | ||
681 | struct io_apic_irq_attr irq_attr; | ||
682 | |||
683 | sb = (struct sfi_table_simple *)table; | ||
684 | num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); | ||
685 | pentry = (struct sfi_device_table_entry *)sb->pentry; | ||
686 | |||
687 | for (i = 0; i < num; i++, pentry++) { | ||
688 | if (pentry->irq != (u8)0xff) { /* native RTE case */ | ||
689 | /* these SPI2 devices are not exposed to system as PCI | ||
690 | * devices, but they have separate RTE entry in IOAPIC | ||
691 | * so we have to enable them one by one here | ||
692 | */ | ||
693 | ioapic = mp_find_ioapic(pentry->irq); | ||
694 | irq_attr.ioapic = ioapic; | ||
695 | irq_attr.ioapic_pin = pentry->irq; | ||
696 | irq_attr.trigger = 1; | ||
697 | irq_attr.polarity = 1; | ||
698 | io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr); | ||
699 | } | ||
700 | switch (pentry->type) { | ||
701 | case SFI_DEV_TYPE_IPC: | ||
702 | /* ID as IRQ is a hack that will go away */ | ||
703 | pdev = platform_device_alloc(pentry->name, pentry->irq); | ||
704 | if (pdev == NULL) { | ||
705 | pr_err("out of memory for SFI platform device '%s'.\n", | ||
706 | pentry->name); | ||
707 | continue; | ||
708 | } | ||
709 | install_irq_resource(pdev, pentry->irq); | ||
710 | pr_debug("info[%2d]: IPC bus, name = %16.16s, " | ||
711 | "irq = 0x%2x\n", i, pentry->name, pentry->irq); | ||
712 | sfi_handle_ipc_dev(pdev); | ||
713 | break; | ||
714 | case SFI_DEV_TYPE_SPI: | ||
715 | memset(&spi_info, 0, sizeof(spi_info)); | ||
716 | strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); | ||
717 | spi_info.irq = pentry->irq; | ||
718 | spi_info.bus_num = pentry->host_num; | ||
719 | spi_info.chip_select = pentry->addr; | ||
720 | spi_info.max_speed_hz = pentry->max_freq; | ||
721 | pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " | ||
722 | "irq = 0x%2x, max_freq = %d, cs = %d\n", i, | ||
723 | spi_info.bus_num, | ||
724 | spi_info.modalias, | ||
725 | spi_info.irq, | ||
726 | spi_info.max_speed_hz, | ||
727 | spi_info.chip_select); | ||
728 | sfi_handle_spi_dev(&spi_info); | ||
729 | break; | ||
730 | case SFI_DEV_TYPE_I2C: | ||
731 | memset(&i2c_info, 0, sizeof(i2c_info)); | ||
732 | bus = pentry->host_num; | ||
733 | strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); | ||
734 | i2c_info.irq = pentry->irq; | ||
735 | i2c_info.addr = pentry->addr; | ||
736 | pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " | ||
737 | "irq = 0x%2x, addr = 0x%x\n", i, bus, | ||
738 | i2c_info.type, | ||
739 | i2c_info.irq, | ||
740 | i2c_info.addr); | ||
741 | sfi_handle_i2c_dev(bus, &i2c_info); | ||
742 | break; | ||
743 | case SFI_DEV_TYPE_UART: | ||
744 | case SFI_DEV_TYPE_HSI: | ||
745 | default: | ||
746 | ; | ||
747 | } | ||
748 | } | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static int __init mrst_platform_init(void) | ||
753 | { | ||
754 | sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); | ||
755 | sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); | ||
756 | return 0; | ||
757 | } | ||
758 | arch_initcall(mrst_platform_init); | ||
759 | |||
760 | /* | ||
761 | * we will search these buttons in SFI GPIO table (by name) | ||
762 | * and register them dynamically. Please add all possible | ||
763 | * buttons here, we will shrink them if no GPIO found. | ||
764 | */ | ||
765 | static struct gpio_keys_button gpio_button[] = { | ||
766 | {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, | ||
767 | {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, | ||
768 | {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, | ||
769 | {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, | ||
770 | {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, | ||
771 | {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, | ||
772 | {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, | ||
773 | {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, | ||
774 | {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, | ||
775 | {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, | ||
776 | }; | ||
777 | |||
778 | static struct gpio_keys_platform_data mrst_gpio_keys = { | ||
779 | .buttons = gpio_button, | ||
780 | .rep = 1, | ||
781 | .nbuttons = -1, /* will fill it after search */ | ||
782 | }; | ||
783 | |||
784 | static struct platform_device pb_device = { | ||
785 | .name = "gpio-keys", | ||
786 | .id = -1, | ||
787 | .dev = { | ||
788 | .platform_data = &mrst_gpio_keys, | ||
789 | }, | ||
790 | }; | ||
791 | |||
792 | /* | ||
793 | * Shrink the non-existent buttons, register the gpio button | ||
794 | * device if there is some | ||
795 | */ | ||
796 | static int __init pb_keys_init(void) | ||
797 | { | ||
798 | struct gpio_keys_button *gb = gpio_button; | ||
799 | int i, num, good = 0; | ||
800 | |||
801 | num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); | ||
802 | for (i = 0; i < num; i++) { | ||
803 | gb[i].gpio = get_gpio_by_name(gb[i].desc); | ||
804 | if (gb[i].gpio == -1) | ||
805 | continue; | ||
806 | |||
807 | if (i != good) | ||
808 | gb[good] = gb[i]; | ||
809 | good++; | ||
810 | } | ||
811 | |||
812 | if (good) { | ||
813 | mrst_gpio_keys.nbuttons = good; | ||
814 | return platform_device_register(&pb_device); | ||
815 | } | ||
816 | return 0; | ||
817 | } | ||
818 | late_initcall(pb_keys_init); | ||
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 41a9e34899ac..ca35b0ce944a 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/sfi.h> | 26 | #include <linux/sfi.h> |
27 | #include <asm/mrst.h> | 27 | #include <asm/mrst.h> |
28 | #include <asm/intel_scu_ipc.h> | 28 | #include <asm/intel_scu_ipc.h> |
29 | #include <asm/mrst.h> | ||
29 | 30 | ||
30 | /* IPC defines the following message types */ | 31 | /* IPC defines the following message types */ |
31 | #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ | 32 | #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ |
@@ -699,6 +700,9 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
699 | iounmap(ipcdev.ipc_base); | 700 | iounmap(ipcdev.ipc_base); |
700 | return -ENOMEM; | 701 | return -ENOMEM; |
701 | } | 702 | } |
703 | |||
704 | intel_scu_devices_create(); | ||
705 | |||
702 | return 0; | 706 | return 0; |
703 | } | 707 | } |
704 | 708 | ||
@@ -720,6 +724,7 @@ static void ipc_remove(struct pci_dev *pdev) | |||
720 | iounmap(ipcdev.ipc_base); | 724 | iounmap(ipcdev.ipc_base); |
721 | iounmap(ipcdev.i2c_base); | 725 | iounmap(ipcdev.i2c_base); |
722 | ipcdev.pdev = NULL; | 726 | ipcdev.pdev = NULL; |
727 | intel_scu_devices_destroy(); | ||
723 | } | 728 | } |
724 | 729 | ||
725 | static const struct pci_device_id pci_ids[] = { | 730 | static const struct pci_device_id pci_ids[] = { |
diff --git a/include/linux/sfi.h b/include/linux/sfi.h index 7f770c638e99..fe817918b30e 100644 --- a/include/linux/sfi.h +++ b/include/linux/sfi.h | |||
@@ -77,6 +77,8 @@ | |||
77 | #define SFI_OEM_ID_SIZE 6 | 77 | #define SFI_OEM_ID_SIZE 6 |
78 | #define SFI_OEM_TABLE_ID_SIZE 8 | 78 | #define SFI_OEM_TABLE_ID_SIZE 8 |
79 | 79 | ||
80 | #define SFI_NAME_LEN 16 | ||
81 | |||
80 | #define SFI_SYST_SEARCH_BEGIN 0x000E0000 | 82 | #define SFI_SYST_SEARCH_BEGIN 0x000E0000 |
81 | #define SFI_SYST_SEARCH_END 0x000FFFFF | 83 | #define SFI_SYST_SEARCH_END 0x000FFFFF |
82 | 84 | ||
@@ -156,13 +158,13 @@ struct sfi_device_table_entry { | |||
156 | u16 addr; | 158 | u16 addr; |
157 | u8 irq; | 159 | u8 irq; |
158 | u32 max_freq; | 160 | u32 max_freq; |
159 | char name[16]; | 161 | char name[SFI_NAME_LEN]; |
160 | } __packed; | 162 | } __packed; |
161 | 163 | ||
162 | struct sfi_gpio_table_entry { | 164 | struct sfi_gpio_table_entry { |
163 | char controller_name[16]; | 165 | char controller_name[SFI_NAME_LEN]; |
164 | u16 pin_no; | 166 | u16 pin_no; |
165 | char pin_name[16]; | 167 | char pin_name[SFI_NAME_LEN]; |
166 | } __packed; | 168 | } __packed; |
167 | 169 | ||
168 | typedef int (*sfi_table_handler) (struct sfi_table_header *table); | 170 | typedef int (*sfi_table_handler) (struct sfi_table_header *table); |