diff options
-rw-r--r-- | arch/x86/platform/mrst/mrst.c | 169 |
1 files changed, 154 insertions, 15 deletions
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 51ec016c20d6..8a7cb3259562 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/mfd/intel_msic.h> | ||
28 | 29 | ||
29 | #include <asm/setup.h> | 30 | #include <asm/setup.h> |
30 | #include <asm/mpspec_def.h> | 31 | #include <asm/mpspec_def.h> |
@@ -481,6 +482,128 @@ static void __init *no_platform_data(void *info) | |||
481 | return NULL; | 482 | return NULL; |
482 | } | 483 | } |
483 | 484 | ||
485 | static struct resource msic_resources[] = { | ||
486 | { | ||
487 | .start = INTEL_MSIC_IRQ_PHYS_BASE, | ||
488 | .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1, | ||
489 | .flags = IORESOURCE_MEM, | ||
490 | }, | ||
491 | }; | ||
492 | |||
493 | static struct intel_msic_platform_data msic_pdata; | ||
494 | |||
495 | static struct platform_device msic_device = { | ||
496 | .name = "intel_msic", | ||
497 | .id = -1, | ||
498 | .dev = { | ||
499 | .platform_data = &msic_pdata, | ||
500 | }, | ||
501 | .num_resources = ARRAY_SIZE(msic_resources), | ||
502 | .resource = msic_resources, | ||
503 | }; | ||
504 | |||
505 | static inline bool mrst_has_msic(void) | ||
506 | { | ||
507 | return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL; | ||
508 | } | ||
509 | |||
510 | static int msic_scu_status_change(struct notifier_block *nb, | ||
511 | unsigned long code, void *data) | ||
512 | { | ||
513 | if (code == SCU_DOWN) { | ||
514 | platform_device_unregister(&msic_device); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | return platform_device_register(&msic_device); | ||
519 | } | ||
520 | |||
521 | static int __init msic_init(void) | ||
522 | { | ||
523 | static struct notifier_block msic_scu_notifier = { | ||
524 | .notifier_call = msic_scu_status_change, | ||
525 | }; | ||
526 | |||
527 | /* | ||
528 | * We need to be sure that the SCU IPC is ready before MSIC device | ||
529 | * can be registered. | ||
530 | */ | ||
531 | if (mrst_has_msic()) | ||
532 | intel_scu_notifier_add(&msic_scu_notifier); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | arch_initcall(msic_init); | ||
537 | |||
538 | /* | ||
539 | * msic_generic_platform_data - sets generic platform data for the block | ||
540 | * @info: pointer to the SFI device table entry for this block | ||
541 | * @block: MSIC block | ||
542 | * | ||
543 | * Function sets IRQ number from the SFI table entry for given device to | ||
544 | * the MSIC platform data. | ||
545 | */ | ||
546 | static void *msic_generic_platform_data(void *info, enum intel_msic_block block) | ||
547 | { | ||
548 | struct sfi_device_table_entry *entry = info; | ||
549 | |||
550 | BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST); | ||
551 | msic_pdata.irq[block] = entry->irq; | ||
552 | |||
553 | return no_platform_data(info); | ||
554 | } | ||
555 | |||
556 | static void *msic_battery_platform_data(void *info) | ||
557 | { | ||
558 | return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY); | ||
559 | } | ||
560 | |||
561 | static void *msic_gpio_platform_data(void *info) | ||
562 | { | ||
563 | static struct intel_msic_gpio_pdata pdata; | ||
564 | int gpio = get_gpio_by_name("msic_gpio_base"); | ||
565 | |||
566 | if (gpio < 0) | ||
567 | return NULL; | ||
568 | |||
569 | pdata.gpio_base = gpio; | ||
570 | msic_pdata.gpio = &pdata; | ||
571 | |||
572 | return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO); | ||
573 | } | ||
574 | |||
575 | static void *msic_audio_platform_data(void *info) | ||
576 | { | ||
577 | struct platform_device *pdev; | ||
578 | |||
579 | pdev = platform_device_register_simple("sst-platform", -1, NULL, 0); | ||
580 | if (IS_ERR(pdev)) { | ||
581 | pr_err("failed to create audio platform device\n"); | ||
582 | return NULL; | ||
583 | } | ||
584 | |||
585 | return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO); | ||
586 | } | ||
587 | |||
588 | static void *msic_power_btn_platform_data(void *info) | ||
589 | { | ||
590 | return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN); | ||
591 | } | ||
592 | |||
593 | static void *msic_ocd_platform_data(void *info) | ||
594 | { | ||
595 | static struct intel_msic_ocd_pdata pdata; | ||
596 | int gpio = get_gpio_by_name("ocd_gpio"); | ||
597 | |||
598 | if (gpio < 0) | ||
599 | return NULL; | ||
600 | |||
601 | pdata.gpio = gpio; | ||
602 | msic_pdata.ocd = &pdata; | ||
603 | |||
604 | return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); | ||
605 | } | ||
606 | |||
484 | static const struct devs_id __initconst device_ids[] = { | 607 | static const struct devs_id __initconst device_ids[] = { |
485 | {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, | 608 | {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, |
486 | {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, | 609 | {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, |
@@ -489,7 +612,14 @@ static const struct devs_id __initconst device_ids[] = { | |||
489 | {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, | 612 | {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, |
490 | {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, | 613 | {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, |
491 | {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, | 614 | {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, |
492 | {"msic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, | 615 | |
616 | /* MSIC subdevices */ | ||
617 | {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, | ||
618 | {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data}, | ||
619 | {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, | ||
620 | {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, | ||
621 | {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, | ||
622 | |||
493 | {}, | 623 | {}, |
494 | }; | 624 | }; |
495 | 625 | ||
@@ -610,19 +740,37 @@ static void __init install_irq_resource(struct platform_device *pdev, int irq) | |||
610 | platform_device_add_resources(pdev, &res, 1); | 740 | platform_device_add_resources(pdev, &res, 1); |
611 | } | 741 | } |
612 | 742 | ||
613 | static void __init sfi_handle_ipc_dev(struct platform_device *pdev) | 743 | static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry) |
614 | { | 744 | { |
615 | const struct devs_id *dev = device_ids; | 745 | const struct devs_id *dev = device_ids; |
746 | struct platform_device *pdev; | ||
616 | void *pdata = NULL; | 747 | void *pdata = NULL; |
617 | 748 | ||
618 | while (dev->name[0]) { | 749 | while (dev->name[0]) { |
619 | if (dev->type == SFI_DEV_TYPE_IPC && | 750 | if (dev->type == SFI_DEV_TYPE_IPC && |
620 | !strncmp(dev->name, pdev->name, SFI_NAME_LEN)) { | 751 | !strncmp(dev->name, entry->name, SFI_NAME_LEN)) { |
621 | pdata = dev->get_platform_data(pdev); | 752 | pdata = dev->get_platform_data(entry); |
622 | break; | 753 | break; |
623 | } | 754 | } |
624 | dev++; | 755 | dev++; |
625 | } | 756 | } |
757 | |||
758 | /* | ||
759 | * On Medfield the platform device creation is handled by the MSIC | ||
760 | * MFD driver so we don't need to do it here. | ||
761 | */ | ||
762 | if (mrst_has_msic()) | ||
763 | return; | ||
764 | |||
765 | /* ID as IRQ is a hack that will go away */ | ||
766 | pdev = platform_device_alloc(entry->name, entry->irq); | ||
767 | if (pdev == NULL) { | ||
768 | pr_err("out of memory for SFI platform device '%s'.\n", | ||
769 | entry->name); | ||
770 | return; | ||
771 | } | ||
772 | install_irq_resource(pdev, entry->irq); | ||
773 | |||
626 | pdev->dev.platform_data = pdata; | 774 | pdev->dev.platform_data = pdata; |
627 | intel_scu_device_register(pdev); | 775 | intel_scu_device_register(pdev); |
628 | } | 776 | } |
@@ -675,7 +823,6 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) | |||
675 | struct sfi_device_table_entry *pentry; | 823 | struct sfi_device_table_entry *pentry; |
676 | struct spi_board_info spi_info; | 824 | struct spi_board_info spi_info; |
677 | struct i2c_board_info i2c_info; | 825 | struct i2c_board_info i2c_info; |
678 | struct platform_device *pdev; | ||
679 | int num, i, bus; | 826 | int num, i, bus; |
680 | int ioapic; | 827 | int ioapic; |
681 | struct io_apic_irq_attr irq_attr; | 828 | struct io_apic_irq_attr irq_attr; |
@@ -703,17 +850,9 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) | |||
703 | 850 | ||
704 | switch (pentry->type) { | 851 | switch (pentry->type) { |
705 | case SFI_DEV_TYPE_IPC: | 852 | case SFI_DEV_TYPE_IPC: |
706 | /* ID as IRQ is a hack that will go away */ | ||
707 | pdev = platform_device_alloc(pentry->name, irq); | ||
708 | if (pdev == NULL) { | ||
709 | pr_err("out of memory for SFI platform device '%s'.\n", | ||
710 | pentry->name); | ||
711 | continue; | ||
712 | } | ||
713 | install_irq_resource(pdev, irq); | ||
714 | pr_debug("info[%2d]: IPC bus, name = %16.16s, " | 853 | pr_debug("info[%2d]: IPC bus, name = %16.16s, " |
715 | "irq = 0x%2x\n", i, pentry->name, irq); | 854 | "irq = 0x%2x\n", i, pentry->name, pentry->irq); |
716 | sfi_handle_ipc_dev(pdev); | 855 | sfi_handle_ipc_dev(pentry); |
717 | break; | 856 | break; |
718 | case SFI_DEV_TYPE_SPI: | 857 | case SFI_DEV_TYPE_SPI: |
719 | memset(&spi_info, 0, sizeof(spi_info)); | 858 | memset(&spi_info, 0, sizeof(spi_info)); |