aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/platform/mrst/mrst.c169
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
485static 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
493static struct intel_msic_platform_data msic_pdata;
494
495static 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
505static inline bool mrst_has_msic(void)
506{
507 return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL;
508}
509
510static 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
521static 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}
536arch_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 */
546static 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
556static void *msic_battery_platform_data(void *info)
557{
558 return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY);
559}
560
561static 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
575static 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
588static void *msic_power_btn_platform_data(void *info)
589{
590 return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN);
591}
592
593static 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
484static const struct devs_id __initconst device_ids[] = { 607static 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
613static void __init sfi_handle_ipc_dev(struct platform_device *pdev) 743static 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));