105454c26SKuppuswamy Sathyanarayanan /* 205454c26SKuppuswamy Sathyanarayanan * intel-mid.c: Intel MID platform setup code 305454c26SKuppuswamy Sathyanarayanan * 405454c26SKuppuswamy Sathyanarayanan * (C) Copyright 2008, 2012 Intel Corporation 505454c26SKuppuswamy Sathyanarayanan * Author: Jacob Pan (jacob.jun.pan@intel.com) 605454c26SKuppuswamy Sathyanarayanan * Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com> 705454c26SKuppuswamy Sathyanarayanan * 805454c26SKuppuswamy Sathyanarayanan * This program is free software; you can redistribute it and/or 905454c26SKuppuswamy Sathyanarayanan * modify it under the terms of the GNU General Public License 1005454c26SKuppuswamy Sathyanarayanan * as published by the Free Software Foundation; version 2 1105454c26SKuppuswamy Sathyanarayanan * of the License. 1205454c26SKuppuswamy Sathyanarayanan */ 1305454c26SKuppuswamy Sathyanarayanan 14*712b6aa8SKuppuswamy Sathyanarayanan #define pr_fmt(fmt) "intel_mid: " fmt 1505454c26SKuppuswamy Sathyanarayanan 1605454c26SKuppuswamy Sathyanarayanan #include <linux/init.h> 1705454c26SKuppuswamy Sathyanarayanan #include <linux/kernel.h> 1805454c26SKuppuswamy Sathyanarayanan #include <linux/interrupt.h> 1905454c26SKuppuswamy Sathyanarayanan #include <linux/scatterlist.h> 2005454c26SKuppuswamy Sathyanarayanan #include <linux/sfi.h> 2105454c26SKuppuswamy Sathyanarayanan #include <linux/intel_pmic_gpio.h> 2205454c26SKuppuswamy Sathyanarayanan #include <linux/spi/spi.h> 2305454c26SKuppuswamy Sathyanarayanan #include <linux/i2c.h> 2405454c26SKuppuswamy Sathyanarayanan #include <linux/platform_data/pca953x.h> 2505454c26SKuppuswamy Sathyanarayanan #include <linux/gpio_keys.h> 2605454c26SKuppuswamy Sathyanarayanan #include <linux/input.h> 2705454c26SKuppuswamy Sathyanarayanan #include <linux/platform_device.h> 2805454c26SKuppuswamy Sathyanarayanan #include <linux/irq.h> 2905454c26SKuppuswamy Sathyanarayanan #include <linux/module.h> 3005454c26SKuppuswamy Sathyanarayanan #include <linux/notifier.h> 3105454c26SKuppuswamy Sathyanarayanan #include <linux/mfd/intel_msic.h> 3205454c26SKuppuswamy Sathyanarayanan #include <linux/gpio.h> 3305454c26SKuppuswamy Sathyanarayanan #include <linux/i2c/tc35876x.h> 3405454c26SKuppuswamy Sathyanarayanan 3505454c26SKuppuswamy Sathyanarayanan #include <asm/setup.h> 3605454c26SKuppuswamy Sathyanarayanan #include <asm/mpspec_def.h> 3705454c26SKuppuswamy Sathyanarayanan #include <asm/hw_irq.h> 3805454c26SKuppuswamy Sathyanarayanan #include <asm/apic.h> 3905454c26SKuppuswamy Sathyanarayanan #include <asm/io_apic.h> 4005454c26SKuppuswamy Sathyanarayanan #include <asm/intel-mid.h> 4105454c26SKuppuswamy Sathyanarayanan #include <asm/intel_mid_vrtc.h> 4205454c26SKuppuswamy Sathyanarayanan #include <asm/io.h> 4305454c26SKuppuswamy Sathyanarayanan #include <asm/i8259.h> 4405454c26SKuppuswamy Sathyanarayanan #include <asm/intel_scu_ipc.h> 4505454c26SKuppuswamy Sathyanarayanan #include <asm/apb_timer.h> 4605454c26SKuppuswamy Sathyanarayanan #include <asm/reboot.h> 4705454c26SKuppuswamy Sathyanarayanan 4805454c26SKuppuswamy Sathyanarayanan /* 4905454c26SKuppuswamy Sathyanarayanan * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, 50*712b6aa8SKuppuswamy Sathyanarayanan * cmdline option x86_intel_mid_timer can be used to override the configuration 5105454c26SKuppuswamy Sathyanarayanan * to prefer one or the other. 5205454c26SKuppuswamy Sathyanarayanan * at runtime, there are basically three timer configurations: 5305454c26SKuppuswamy Sathyanarayanan * 1. per cpu apbt clock only 5405454c26SKuppuswamy Sathyanarayanan * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only 5505454c26SKuppuswamy Sathyanarayanan * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. 5605454c26SKuppuswamy Sathyanarayanan * 5705454c26SKuppuswamy Sathyanarayanan * by default (without cmdline option), platform code first detects cpu type 5805454c26SKuppuswamy Sathyanarayanan * to see if we are on lincroft or penwell, then set up both lapic or apbt 5905454c26SKuppuswamy Sathyanarayanan * clocks accordingly. 6005454c26SKuppuswamy Sathyanarayanan * i.e. by default, medfield uses configuration #2, moorestown uses #1. 6105454c26SKuppuswamy Sathyanarayanan * config #3 is supported but not recommended on medfield. 6205454c26SKuppuswamy Sathyanarayanan * 6305454c26SKuppuswamy Sathyanarayanan * rating and feature summary: 6405454c26SKuppuswamy Sathyanarayanan * lapic (with C3STOP) --------- 100 6505454c26SKuppuswamy Sathyanarayanan * apbt (always-on) ------------ 110 6605454c26SKuppuswamy Sathyanarayanan * lapic (always-on,ARAT) ------ 150 6705454c26SKuppuswamy Sathyanarayanan */ 6805454c26SKuppuswamy Sathyanarayanan 69*712b6aa8SKuppuswamy Sathyanarayanan enum intel_mid_timer_options intel_mid_timer_options; 7005454c26SKuppuswamy Sathyanarayanan 7105454c26SKuppuswamy Sathyanarayanan static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; 7205454c26SKuppuswamy Sathyanarayanan static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; 73*712b6aa8SKuppuswamy Sathyanarayanan enum intel_mid_cpu_type __intel_mid_cpu_chip; 74*712b6aa8SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip); 7505454c26SKuppuswamy Sathyanarayanan 7605454c26SKuppuswamy Sathyanarayanan int sfi_mtimer_num; 7705454c26SKuppuswamy Sathyanarayanan 7805454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; 7905454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(sfi_mrtc_array); 8005454c26SKuppuswamy Sathyanarayanan int sfi_mrtc_num; 8105454c26SKuppuswamy Sathyanarayanan 82*712b6aa8SKuppuswamy Sathyanarayanan static void intel_mid_power_off(void) 8305454c26SKuppuswamy Sathyanarayanan { 8405454c26SKuppuswamy Sathyanarayanan } 8505454c26SKuppuswamy Sathyanarayanan 86*712b6aa8SKuppuswamy Sathyanarayanan static void intel_mid_reboot(void) 8705454c26SKuppuswamy Sathyanarayanan { 8805454c26SKuppuswamy Sathyanarayanan intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); 8905454c26SKuppuswamy Sathyanarayanan } 9005454c26SKuppuswamy Sathyanarayanan 9105454c26SKuppuswamy Sathyanarayanan /* parse all the mtimer info to a static mtimer array */ 9205454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_mtmr(struct sfi_table_header *table) 9305454c26SKuppuswamy Sathyanarayanan { 9405454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 9505454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry *pentry; 9605454c26SKuppuswamy Sathyanarayanan struct mpc_intsrc mp_irq; 9705454c26SKuppuswamy Sathyanarayanan int totallen; 9805454c26SKuppuswamy Sathyanarayanan 9905454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 10005454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_num) { 10105454c26SKuppuswamy Sathyanarayanan sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, 10205454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry); 10305454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_timer_table_entry *) sb->pentry; 10405454c26SKuppuswamy Sathyanarayanan totallen = sfi_mtimer_num * sizeof(*pentry); 10505454c26SKuppuswamy Sathyanarayanan memcpy(sfi_mtimer_array, pentry, totallen); 10605454c26SKuppuswamy Sathyanarayanan } 10705454c26SKuppuswamy Sathyanarayanan 10805454c26SKuppuswamy Sathyanarayanan pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); 10905454c26SKuppuswamy Sathyanarayanan pentry = sfi_mtimer_array; 11005454c26SKuppuswamy Sathyanarayanan for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { 11105454c26SKuppuswamy Sathyanarayanan pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," 11205454c26SKuppuswamy Sathyanarayanan " irq = %d\n", totallen, (u32)pentry->phys_addr, 11305454c26SKuppuswamy Sathyanarayanan pentry->freq_hz, pentry->irq); 11405454c26SKuppuswamy Sathyanarayanan if (!pentry->irq) 11505454c26SKuppuswamy Sathyanarayanan continue; 11605454c26SKuppuswamy Sathyanarayanan mp_irq.type = MP_INTSRC; 11705454c26SKuppuswamy Sathyanarayanan mp_irq.irqtype = mp_INT; 11805454c26SKuppuswamy Sathyanarayanan /* triggering mode edge bit 2-3, active high polarity bit 0-1 */ 11905454c26SKuppuswamy Sathyanarayanan mp_irq.irqflag = 5; 12005454c26SKuppuswamy Sathyanarayanan mp_irq.srcbus = MP_BUS_ISA; 12105454c26SKuppuswamy Sathyanarayanan mp_irq.srcbusirq = pentry->irq; /* IRQ */ 12205454c26SKuppuswamy Sathyanarayanan mp_irq.dstapic = MP_APIC_ALL; 12305454c26SKuppuswamy Sathyanarayanan mp_irq.dstirq = pentry->irq; 12405454c26SKuppuswamy Sathyanarayanan mp_save_irq(&mp_irq); 12505454c26SKuppuswamy Sathyanarayanan } 12605454c26SKuppuswamy Sathyanarayanan 12705454c26SKuppuswamy Sathyanarayanan return 0; 12805454c26SKuppuswamy Sathyanarayanan } 12905454c26SKuppuswamy Sathyanarayanan 13005454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry *sfi_get_mtmr(int hint) 13105454c26SKuppuswamy Sathyanarayanan { 13205454c26SKuppuswamy Sathyanarayanan int i; 13305454c26SKuppuswamy Sathyanarayanan if (hint < sfi_mtimer_num) { 13405454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_usage[hint]) { 13505454c26SKuppuswamy Sathyanarayanan pr_debug("hint taken for timer %d irq %d\n", 13605454c26SKuppuswamy Sathyanarayanan hint, sfi_mtimer_array[hint].irq); 13705454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[hint] = 1; 13805454c26SKuppuswamy Sathyanarayanan return &sfi_mtimer_array[hint]; 13905454c26SKuppuswamy Sathyanarayanan } 14005454c26SKuppuswamy Sathyanarayanan } 14105454c26SKuppuswamy Sathyanarayanan /* take the first timer available */ 14205454c26SKuppuswamy Sathyanarayanan for (i = 0; i < sfi_mtimer_num;) { 14305454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_usage[i]) { 14405454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[i] = 1; 14505454c26SKuppuswamy Sathyanarayanan return &sfi_mtimer_array[i]; 14605454c26SKuppuswamy Sathyanarayanan } 14705454c26SKuppuswamy Sathyanarayanan i++; 14805454c26SKuppuswamy Sathyanarayanan } 14905454c26SKuppuswamy Sathyanarayanan return NULL; 15005454c26SKuppuswamy Sathyanarayanan } 15105454c26SKuppuswamy Sathyanarayanan 15205454c26SKuppuswamy Sathyanarayanan void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) 15305454c26SKuppuswamy Sathyanarayanan { 15405454c26SKuppuswamy Sathyanarayanan int i; 15505454c26SKuppuswamy Sathyanarayanan for (i = 0; i < sfi_mtimer_num;) { 15605454c26SKuppuswamy Sathyanarayanan if (mtmr->irq == sfi_mtimer_array[i].irq) { 15705454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[i] = 0; 15805454c26SKuppuswamy Sathyanarayanan return; 15905454c26SKuppuswamy Sathyanarayanan } 16005454c26SKuppuswamy Sathyanarayanan i++; 16105454c26SKuppuswamy Sathyanarayanan } 16205454c26SKuppuswamy Sathyanarayanan } 16305454c26SKuppuswamy Sathyanarayanan 16405454c26SKuppuswamy Sathyanarayanan /* parse all the mrtc info to a global mrtc array */ 16505454c26SKuppuswamy Sathyanarayanan int __init sfi_parse_mrtc(struct sfi_table_header *table) 16605454c26SKuppuswamy Sathyanarayanan { 16705454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 16805454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry *pentry; 16905454c26SKuppuswamy Sathyanarayanan struct mpc_intsrc mp_irq; 17005454c26SKuppuswamy Sathyanarayanan 17105454c26SKuppuswamy Sathyanarayanan int totallen; 17205454c26SKuppuswamy Sathyanarayanan 17305454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 17405454c26SKuppuswamy Sathyanarayanan if (!sfi_mrtc_num) { 17505454c26SKuppuswamy Sathyanarayanan sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, 17605454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry); 17705454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_rtc_table_entry *)sb->pentry; 17805454c26SKuppuswamy Sathyanarayanan totallen = sfi_mrtc_num * sizeof(*pentry); 17905454c26SKuppuswamy Sathyanarayanan memcpy(sfi_mrtc_array, pentry, totallen); 18005454c26SKuppuswamy Sathyanarayanan } 18105454c26SKuppuswamy Sathyanarayanan 18205454c26SKuppuswamy Sathyanarayanan pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); 18305454c26SKuppuswamy Sathyanarayanan pentry = sfi_mrtc_array; 18405454c26SKuppuswamy Sathyanarayanan for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { 18505454c26SKuppuswamy Sathyanarayanan pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", 18605454c26SKuppuswamy Sathyanarayanan totallen, (u32)pentry->phys_addr, pentry->irq); 18705454c26SKuppuswamy Sathyanarayanan mp_irq.type = MP_INTSRC; 18805454c26SKuppuswamy Sathyanarayanan mp_irq.irqtype = mp_INT; 18905454c26SKuppuswamy Sathyanarayanan mp_irq.irqflag = 0xf; /* level trigger and active low */ 19005454c26SKuppuswamy Sathyanarayanan mp_irq.srcbus = MP_BUS_ISA; 19105454c26SKuppuswamy Sathyanarayanan mp_irq.srcbusirq = pentry->irq; /* IRQ */ 19205454c26SKuppuswamy Sathyanarayanan mp_irq.dstapic = MP_APIC_ALL; 19305454c26SKuppuswamy Sathyanarayanan mp_irq.dstirq = pentry->irq; 19405454c26SKuppuswamy Sathyanarayanan mp_save_irq(&mp_irq); 19505454c26SKuppuswamy Sathyanarayanan } 19605454c26SKuppuswamy Sathyanarayanan return 0; 19705454c26SKuppuswamy Sathyanarayanan } 19805454c26SKuppuswamy Sathyanarayanan 199*712b6aa8SKuppuswamy Sathyanarayanan static unsigned long __init intel_mid_calibrate_tsc(void) 20005454c26SKuppuswamy Sathyanarayanan { 20105454c26SKuppuswamy Sathyanarayanan unsigned long fast_calibrate; 20205454c26SKuppuswamy Sathyanarayanan u32 lo, hi, ratio, fsb; 20305454c26SKuppuswamy Sathyanarayanan 20405454c26SKuppuswamy Sathyanarayanan rdmsr(MSR_IA32_PERF_STATUS, lo, hi); 20505454c26SKuppuswamy Sathyanarayanan pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); 20605454c26SKuppuswamy Sathyanarayanan ratio = (hi >> 8) & 0x1f; 20705454c26SKuppuswamy Sathyanarayanan pr_debug("ratio is %d\n", ratio); 20805454c26SKuppuswamy Sathyanarayanan if (!ratio) { 20905454c26SKuppuswamy Sathyanarayanan pr_err("read a zero ratio, should be incorrect!\n"); 21005454c26SKuppuswamy Sathyanarayanan pr_err("force tsc ratio to 16 ...\n"); 21105454c26SKuppuswamy Sathyanarayanan ratio = 16; 21205454c26SKuppuswamy Sathyanarayanan } 21305454c26SKuppuswamy Sathyanarayanan rdmsr(MSR_FSB_FREQ, lo, hi); 21405454c26SKuppuswamy Sathyanarayanan if ((lo & 0x7) == 0x7) 21505454c26SKuppuswamy Sathyanarayanan fsb = PENWELL_FSB_FREQ_83SKU; 21605454c26SKuppuswamy Sathyanarayanan else 21705454c26SKuppuswamy Sathyanarayanan fsb = PENWELL_FSB_FREQ_100SKU; 21805454c26SKuppuswamy Sathyanarayanan fast_calibrate = ratio * fsb; 21905454c26SKuppuswamy Sathyanarayanan pr_debug("read penwell tsc %lu khz\n", fast_calibrate); 22005454c26SKuppuswamy Sathyanarayanan lapic_timer_frequency = fsb * 1000 / HZ; 22105454c26SKuppuswamy Sathyanarayanan /* mark tsc clocksource as reliable */ 22205454c26SKuppuswamy Sathyanarayanan set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); 22305454c26SKuppuswamy Sathyanarayanan 22405454c26SKuppuswamy Sathyanarayanan if (fast_calibrate) 22505454c26SKuppuswamy Sathyanarayanan return fast_calibrate; 22605454c26SKuppuswamy Sathyanarayanan 22705454c26SKuppuswamy Sathyanarayanan return 0; 22805454c26SKuppuswamy Sathyanarayanan } 22905454c26SKuppuswamy Sathyanarayanan 230*712b6aa8SKuppuswamy Sathyanarayanan static void __init intel_mid_time_init(void) 23105454c26SKuppuswamy Sathyanarayanan { 23205454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); 233*712b6aa8SKuppuswamy Sathyanarayanan switch (intel_mid_timer_options) { 234*712b6aa8SKuppuswamy Sathyanarayanan case INTEL_MID_TIMER_APBT_ONLY: 23505454c26SKuppuswamy Sathyanarayanan break; 236*712b6aa8SKuppuswamy Sathyanarayanan case INTEL_MID_TIMER_LAPIC_APBT: 23705454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; 23805454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; 23905454c26SKuppuswamy Sathyanarayanan break; 24005454c26SKuppuswamy Sathyanarayanan default: 24105454c26SKuppuswamy Sathyanarayanan if (!boot_cpu_has(X86_FEATURE_ARAT)) 24205454c26SKuppuswamy Sathyanarayanan break; 24305454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; 24405454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; 24505454c26SKuppuswamy Sathyanarayanan return; 24605454c26SKuppuswamy Sathyanarayanan } 24705454c26SKuppuswamy Sathyanarayanan /* we need at least one APB timer */ 24805454c26SKuppuswamy Sathyanarayanan pre_init_apic_IRQ0(); 24905454c26SKuppuswamy Sathyanarayanan apbt_time_init(); 25005454c26SKuppuswamy Sathyanarayanan } 25105454c26SKuppuswamy Sathyanarayanan 252*712b6aa8SKuppuswamy Sathyanarayanan static void __cpuinit intel_mid_arch_setup(void) 25305454c26SKuppuswamy Sathyanarayanan { 25405454c26SKuppuswamy Sathyanarayanan if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) 255*712b6aa8SKuppuswamy Sathyanarayanan __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL; 25605454c26SKuppuswamy Sathyanarayanan else { 25705454c26SKuppuswamy Sathyanarayanan pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", 25805454c26SKuppuswamy Sathyanarayanan boot_cpu_data.x86, boot_cpu_data.x86_model); 259*712b6aa8SKuppuswamy Sathyanarayanan __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL; 26005454c26SKuppuswamy Sathyanarayanan } 26105454c26SKuppuswamy Sathyanarayanan } 26205454c26SKuppuswamy Sathyanarayanan 26305454c26SKuppuswamy Sathyanarayanan /* MID systems don't have i8042 controller */ 264*712b6aa8SKuppuswamy Sathyanarayanan static int intel_mid_i8042_detect(void) 26505454c26SKuppuswamy Sathyanarayanan { 26605454c26SKuppuswamy Sathyanarayanan return 0; 26705454c26SKuppuswamy Sathyanarayanan } 26805454c26SKuppuswamy Sathyanarayanan 26905454c26SKuppuswamy Sathyanarayanan /* 27005454c26SKuppuswamy Sathyanarayanan * Moorestown does not have external NMI source nor port 0x61 to report 27105454c26SKuppuswamy Sathyanarayanan * NMI status. The possible NMI sources are from pmu as a result of NMI 27205454c26SKuppuswamy Sathyanarayanan * watchdog or lock debug. Reading io port 0x61 results in 0xff which 27305454c26SKuppuswamy Sathyanarayanan * misled NMI handler. 27405454c26SKuppuswamy Sathyanarayanan */ 275*712b6aa8SKuppuswamy Sathyanarayanan static unsigned char intel_mid_get_nmi_reason(void) 27605454c26SKuppuswamy Sathyanarayanan { 27705454c26SKuppuswamy Sathyanarayanan return 0; 27805454c26SKuppuswamy Sathyanarayanan } 27905454c26SKuppuswamy Sathyanarayanan 28005454c26SKuppuswamy Sathyanarayanan /* 28105454c26SKuppuswamy Sathyanarayanan * Moorestown specific x86_init function overrides and early setup 28205454c26SKuppuswamy Sathyanarayanan * calls. 28305454c26SKuppuswamy Sathyanarayanan */ 284*712b6aa8SKuppuswamy Sathyanarayanan void __init x86_intel_mid_early_setup(void) 28505454c26SKuppuswamy Sathyanarayanan { 28605454c26SKuppuswamy Sathyanarayanan x86_init.resources.probe_roms = x86_init_noop; 28705454c26SKuppuswamy Sathyanarayanan x86_init.resources.reserve_resources = x86_init_noop; 28805454c26SKuppuswamy Sathyanarayanan 289*712b6aa8SKuppuswamy Sathyanarayanan x86_init.timers.timer_init = intel_mid_time_init; 29005454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = x86_init_noop; 29105454c26SKuppuswamy Sathyanarayanan 29205454c26SKuppuswamy Sathyanarayanan x86_init.irqs.pre_vector_init = x86_init_noop; 29305454c26SKuppuswamy Sathyanarayanan 294*712b6aa8SKuppuswamy Sathyanarayanan x86_init.oem.arch_setup = intel_mid_arch_setup; 29505454c26SKuppuswamy Sathyanarayanan 29605454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; 29705454c26SKuppuswamy Sathyanarayanan 298*712b6aa8SKuppuswamy Sathyanarayanan x86_platform.calibrate_tsc = intel_mid_calibrate_tsc; 299*712b6aa8SKuppuswamy Sathyanarayanan x86_platform.i8042_detect = intel_mid_i8042_detect; 300*712b6aa8SKuppuswamy Sathyanarayanan x86_init.timers.wallclock_init = intel_mid_rtc_init; 301*712b6aa8SKuppuswamy Sathyanarayanan x86_platform.get_nmi_reason = intel_mid_get_nmi_reason; 30205454c26SKuppuswamy Sathyanarayanan 303*712b6aa8SKuppuswamy Sathyanarayanan x86_init.pci.init = intel_mid_pci_init; 30405454c26SKuppuswamy Sathyanarayanan x86_init.pci.fixup_irqs = x86_init_noop; 30505454c26SKuppuswamy Sathyanarayanan 30605454c26SKuppuswamy Sathyanarayanan legacy_pic = &null_legacy_pic; 30705454c26SKuppuswamy Sathyanarayanan 308*712b6aa8SKuppuswamy Sathyanarayanan pm_power_off = intel_mid_power_off; 309*712b6aa8SKuppuswamy Sathyanarayanan machine_ops.emergency_restart = intel_mid_reboot; 31005454c26SKuppuswamy Sathyanarayanan 31105454c26SKuppuswamy Sathyanarayanan /* Avoid searching for BIOS MP tables */ 31205454c26SKuppuswamy Sathyanarayanan x86_init.mpparse.find_smp_config = x86_init_noop; 31305454c26SKuppuswamy Sathyanarayanan x86_init.mpparse.get_smp_config = x86_init_uint_noop; 31405454c26SKuppuswamy Sathyanarayanan set_bit(MP_BUS_ISA, mp_bus_not_pci); 31505454c26SKuppuswamy Sathyanarayanan } 31605454c26SKuppuswamy Sathyanarayanan 31705454c26SKuppuswamy Sathyanarayanan /* 31805454c26SKuppuswamy Sathyanarayanan * if user does not want to use per CPU apb timer, just give it a lower rating 31905454c26SKuppuswamy Sathyanarayanan * than local apic timer and skip the late per cpu timer init. 32005454c26SKuppuswamy Sathyanarayanan */ 321*712b6aa8SKuppuswamy Sathyanarayanan static inline int __init setup_x86_intel_mid_timer(char *arg) 32205454c26SKuppuswamy Sathyanarayanan { 32305454c26SKuppuswamy Sathyanarayanan if (!arg) 32405454c26SKuppuswamy Sathyanarayanan return -EINVAL; 32505454c26SKuppuswamy Sathyanarayanan 32605454c26SKuppuswamy Sathyanarayanan if (strcmp("apbt_only", arg) == 0) 327*712b6aa8SKuppuswamy Sathyanarayanan intel_mid_timer_options = INTEL_MID_TIMER_APBT_ONLY; 32805454c26SKuppuswamy Sathyanarayanan else if (strcmp("lapic_and_apbt", arg) == 0) 329*712b6aa8SKuppuswamy Sathyanarayanan intel_mid_timer_options = INTEL_MID_TIMER_LAPIC_APBT; 33005454c26SKuppuswamy Sathyanarayanan else { 331*712b6aa8SKuppuswamy Sathyanarayanan pr_warn("X86 INTEL_MID timer option %s not recognised" 332*712b6aa8SKuppuswamy Sathyanarayanan " use x86_intel_mid_timer=apbt_only or lapic_and_apbt\n", 33305454c26SKuppuswamy Sathyanarayanan arg); 33405454c26SKuppuswamy Sathyanarayanan return -EINVAL; 33505454c26SKuppuswamy Sathyanarayanan } 33605454c26SKuppuswamy Sathyanarayanan return 0; 33705454c26SKuppuswamy Sathyanarayanan } 338*712b6aa8SKuppuswamy Sathyanarayanan __setup("x86_intel_mid_timer=", setup_x86_intel_mid_timer); 33905454c26SKuppuswamy Sathyanarayanan 34005454c26SKuppuswamy Sathyanarayanan /* 34105454c26SKuppuswamy Sathyanarayanan * Parsing GPIO table first, since the DEVS table will need this table 34205454c26SKuppuswamy Sathyanarayanan * to map the pin name to the actual pin. 34305454c26SKuppuswamy Sathyanarayanan */ 34405454c26SKuppuswamy Sathyanarayanan static struct sfi_gpio_table_entry *gpio_table; 34505454c26SKuppuswamy Sathyanarayanan static int gpio_num_entry; 34605454c26SKuppuswamy Sathyanarayanan 34705454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_gpio(struct sfi_table_header *table) 34805454c26SKuppuswamy Sathyanarayanan { 34905454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 35005454c26SKuppuswamy Sathyanarayanan struct sfi_gpio_table_entry *pentry; 35105454c26SKuppuswamy Sathyanarayanan int num, i; 35205454c26SKuppuswamy Sathyanarayanan 35305454c26SKuppuswamy Sathyanarayanan if (gpio_table) 35405454c26SKuppuswamy Sathyanarayanan return 0; 35505454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 35605454c26SKuppuswamy Sathyanarayanan num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); 35705454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_gpio_table_entry *)sb->pentry; 35805454c26SKuppuswamy Sathyanarayanan 35905454c26SKuppuswamy Sathyanarayanan gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL); 36005454c26SKuppuswamy Sathyanarayanan if (!gpio_table) 36105454c26SKuppuswamy Sathyanarayanan return -1; 36205454c26SKuppuswamy Sathyanarayanan memcpy(gpio_table, pentry, num * sizeof(*pentry)); 36305454c26SKuppuswamy Sathyanarayanan gpio_num_entry = num; 36405454c26SKuppuswamy Sathyanarayanan 36505454c26SKuppuswamy Sathyanarayanan pr_debug("GPIO pin info:\n"); 36605454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++, pentry++) 36705454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," 36805454c26SKuppuswamy Sathyanarayanan " pin = %d\n", i, 36905454c26SKuppuswamy Sathyanarayanan pentry->controller_name, 37005454c26SKuppuswamy Sathyanarayanan pentry->pin_name, 37105454c26SKuppuswamy Sathyanarayanan pentry->pin_no); 37205454c26SKuppuswamy Sathyanarayanan return 0; 37305454c26SKuppuswamy Sathyanarayanan } 37405454c26SKuppuswamy Sathyanarayanan 37505454c26SKuppuswamy Sathyanarayanan static int get_gpio_by_name(const char *name) 37605454c26SKuppuswamy Sathyanarayanan { 37705454c26SKuppuswamy Sathyanarayanan struct sfi_gpio_table_entry *pentry = gpio_table; 37805454c26SKuppuswamy Sathyanarayanan int i; 37905454c26SKuppuswamy Sathyanarayanan 38005454c26SKuppuswamy Sathyanarayanan if (!pentry) 38105454c26SKuppuswamy Sathyanarayanan return -1; 38205454c26SKuppuswamy Sathyanarayanan for (i = 0; i < gpio_num_entry; i++, pentry++) { 38305454c26SKuppuswamy Sathyanarayanan if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) 38405454c26SKuppuswamy Sathyanarayanan return pentry->pin_no; 38505454c26SKuppuswamy Sathyanarayanan } 38605454c26SKuppuswamy Sathyanarayanan return -1; 38705454c26SKuppuswamy Sathyanarayanan } 38805454c26SKuppuswamy Sathyanarayanan 38905454c26SKuppuswamy Sathyanarayanan /* 39005454c26SKuppuswamy Sathyanarayanan * Here defines the array of devices platform data that IAFW would export 39105454c26SKuppuswamy Sathyanarayanan * through SFI "DEVS" table, we use name and type to match the device and 39205454c26SKuppuswamy Sathyanarayanan * its platform data. 39305454c26SKuppuswamy Sathyanarayanan */ 39405454c26SKuppuswamy Sathyanarayanan struct devs_id { 39505454c26SKuppuswamy Sathyanarayanan char name[SFI_NAME_LEN + 1]; 39605454c26SKuppuswamy Sathyanarayanan u8 type; 39705454c26SKuppuswamy Sathyanarayanan u8 delay; 39805454c26SKuppuswamy Sathyanarayanan void *(*get_platform_data)(void *info); 39905454c26SKuppuswamy Sathyanarayanan }; 40005454c26SKuppuswamy Sathyanarayanan 40105454c26SKuppuswamy Sathyanarayanan /* the offset for the mapping of global gpio pin to irq */ 402*712b6aa8SKuppuswamy Sathyanarayanan #define INTEL_MID_IRQ_OFFSET 0x100 40305454c26SKuppuswamy Sathyanarayanan 40405454c26SKuppuswamy Sathyanarayanan static void __init *pmic_gpio_platform_data(void *info) 40505454c26SKuppuswamy Sathyanarayanan { 40605454c26SKuppuswamy Sathyanarayanan static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; 40705454c26SKuppuswamy Sathyanarayanan int gpio_base = get_gpio_by_name("pmic_gpio_base"); 40805454c26SKuppuswamy Sathyanarayanan 40905454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 41005454c26SKuppuswamy Sathyanarayanan gpio_base = 64; 41105454c26SKuppuswamy Sathyanarayanan pmic_gpio_pdata.gpio_base = gpio_base; 412*712b6aa8SKuppuswamy Sathyanarayanan pmic_gpio_pdata.irq_base = gpio_base + INTEL_MID_IRQ_OFFSET; 41305454c26SKuppuswamy Sathyanarayanan pmic_gpio_pdata.gpiointr = 0xffffeff8; 41405454c26SKuppuswamy Sathyanarayanan 41505454c26SKuppuswamy Sathyanarayanan return &pmic_gpio_pdata; 41605454c26SKuppuswamy Sathyanarayanan } 41705454c26SKuppuswamy Sathyanarayanan 41805454c26SKuppuswamy Sathyanarayanan static void __init *max3111_platform_data(void *info) 41905454c26SKuppuswamy Sathyanarayanan { 42005454c26SKuppuswamy Sathyanarayanan struct spi_board_info *spi_info = info; 42105454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("max3111_int"); 42205454c26SKuppuswamy Sathyanarayanan 42305454c26SKuppuswamy Sathyanarayanan spi_info->mode = SPI_MODE_0; 42405454c26SKuppuswamy Sathyanarayanan if (intr == -1) 42505454c26SKuppuswamy Sathyanarayanan return NULL; 426*712b6aa8SKuppuswamy Sathyanarayanan spi_info->irq = intr + INTEL_MID_IRQ_OFFSET; 42705454c26SKuppuswamy Sathyanarayanan return NULL; 42805454c26SKuppuswamy Sathyanarayanan } 42905454c26SKuppuswamy Sathyanarayanan 43005454c26SKuppuswamy Sathyanarayanan /* we have multiple max7315 on the board ... */ 43105454c26SKuppuswamy Sathyanarayanan #define MAX7315_NUM 2 43205454c26SKuppuswamy Sathyanarayanan static void __init *max7315_platform_data(void *info) 43305454c26SKuppuswamy Sathyanarayanan { 43405454c26SKuppuswamy Sathyanarayanan static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; 43505454c26SKuppuswamy Sathyanarayanan static int nr; 43605454c26SKuppuswamy Sathyanarayanan struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; 43705454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 43805454c26SKuppuswamy Sathyanarayanan int gpio_base, intr; 43905454c26SKuppuswamy Sathyanarayanan char base_pin_name[SFI_NAME_LEN + 1]; 44005454c26SKuppuswamy Sathyanarayanan char intr_pin_name[SFI_NAME_LEN + 1]; 44105454c26SKuppuswamy Sathyanarayanan 44205454c26SKuppuswamy Sathyanarayanan if (nr == MAX7315_NUM) { 44305454c26SKuppuswamy Sathyanarayanan pr_err("too many max7315s, we only support %d\n", 44405454c26SKuppuswamy Sathyanarayanan MAX7315_NUM); 44505454c26SKuppuswamy Sathyanarayanan return NULL; 44605454c26SKuppuswamy Sathyanarayanan } 44705454c26SKuppuswamy Sathyanarayanan /* we have several max7315 on the board, we only need load several 44805454c26SKuppuswamy Sathyanarayanan * instances of the same pca953x driver to cover them 44905454c26SKuppuswamy Sathyanarayanan */ 45005454c26SKuppuswamy Sathyanarayanan strcpy(i2c_info->type, "max7315"); 45105454c26SKuppuswamy Sathyanarayanan if (nr++) { 45205454c26SKuppuswamy Sathyanarayanan sprintf(base_pin_name, "max7315_%d_base", nr); 45305454c26SKuppuswamy Sathyanarayanan sprintf(intr_pin_name, "max7315_%d_int", nr); 45405454c26SKuppuswamy Sathyanarayanan } else { 45505454c26SKuppuswamy Sathyanarayanan strcpy(base_pin_name, "max7315_base"); 45605454c26SKuppuswamy Sathyanarayanan strcpy(intr_pin_name, "max7315_int"); 45705454c26SKuppuswamy Sathyanarayanan } 45805454c26SKuppuswamy Sathyanarayanan 45905454c26SKuppuswamy Sathyanarayanan gpio_base = get_gpio_by_name(base_pin_name); 46005454c26SKuppuswamy Sathyanarayanan intr = get_gpio_by_name(intr_pin_name); 46105454c26SKuppuswamy Sathyanarayanan 46205454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 46305454c26SKuppuswamy Sathyanarayanan return NULL; 46405454c26SKuppuswamy Sathyanarayanan max7315->gpio_base = gpio_base; 46505454c26SKuppuswamy Sathyanarayanan if (intr != -1) { 466*712b6aa8SKuppuswamy Sathyanarayanan i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; 467*712b6aa8SKuppuswamy Sathyanarayanan max7315->irq_base = gpio_base + INTEL_MID_IRQ_OFFSET; 46805454c26SKuppuswamy Sathyanarayanan } else { 46905454c26SKuppuswamy Sathyanarayanan i2c_info->irq = -1; 47005454c26SKuppuswamy Sathyanarayanan max7315->irq_base = -1; 47105454c26SKuppuswamy Sathyanarayanan } 47205454c26SKuppuswamy Sathyanarayanan return max7315; 47305454c26SKuppuswamy Sathyanarayanan } 47405454c26SKuppuswamy Sathyanarayanan 47505454c26SKuppuswamy Sathyanarayanan static void *tca6416_platform_data(void *info) 47605454c26SKuppuswamy Sathyanarayanan { 47705454c26SKuppuswamy Sathyanarayanan static struct pca953x_platform_data tca6416; 47805454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 47905454c26SKuppuswamy Sathyanarayanan int gpio_base, intr; 48005454c26SKuppuswamy Sathyanarayanan char base_pin_name[SFI_NAME_LEN + 1]; 48105454c26SKuppuswamy Sathyanarayanan char intr_pin_name[SFI_NAME_LEN + 1]; 48205454c26SKuppuswamy Sathyanarayanan 48305454c26SKuppuswamy Sathyanarayanan strcpy(i2c_info->type, "tca6416"); 48405454c26SKuppuswamy Sathyanarayanan strcpy(base_pin_name, "tca6416_base"); 48505454c26SKuppuswamy Sathyanarayanan strcpy(intr_pin_name, "tca6416_int"); 48605454c26SKuppuswamy Sathyanarayanan 48705454c26SKuppuswamy Sathyanarayanan gpio_base = get_gpio_by_name(base_pin_name); 48805454c26SKuppuswamy Sathyanarayanan intr = get_gpio_by_name(intr_pin_name); 48905454c26SKuppuswamy Sathyanarayanan 49005454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 49105454c26SKuppuswamy Sathyanarayanan return NULL; 49205454c26SKuppuswamy Sathyanarayanan tca6416.gpio_base = gpio_base; 49305454c26SKuppuswamy Sathyanarayanan if (intr != -1) { 494*712b6aa8SKuppuswamy Sathyanarayanan i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; 495*712b6aa8SKuppuswamy Sathyanarayanan tca6416.irq_base = gpio_base + INTEL_MID_IRQ_OFFSET; 49605454c26SKuppuswamy Sathyanarayanan } else { 49705454c26SKuppuswamy Sathyanarayanan i2c_info->irq = -1; 49805454c26SKuppuswamy Sathyanarayanan tca6416.irq_base = -1; 49905454c26SKuppuswamy Sathyanarayanan } 50005454c26SKuppuswamy Sathyanarayanan return &tca6416; 50105454c26SKuppuswamy Sathyanarayanan } 50205454c26SKuppuswamy Sathyanarayanan 50305454c26SKuppuswamy Sathyanarayanan static void *mpu3050_platform_data(void *info) 50405454c26SKuppuswamy Sathyanarayanan { 50505454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 50605454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("mpu3050_int"); 50705454c26SKuppuswamy Sathyanarayanan 50805454c26SKuppuswamy Sathyanarayanan if (intr == -1) 50905454c26SKuppuswamy Sathyanarayanan return NULL; 51005454c26SKuppuswamy Sathyanarayanan 511*712b6aa8SKuppuswamy Sathyanarayanan i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; 51205454c26SKuppuswamy Sathyanarayanan return NULL; 51305454c26SKuppuswamy Sathyanarayanan } 51405454c26SKuppuswamy Sathyanarayanan 51505454c26SKuppuswamy Sathyanarayanan static void __init *emc1403_platform_data(void *info) 51605454c26SKuppuswamy Sathyanarayanan { 51705454c26SKuppuswamy Sathyanarayanan static short intr2nd_pdata; 51805454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 51905454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("thermal_int"); 52005454c26SKuppuswamy Sathyanarayanan int intr2nd = get_gpio_by_name("thermal_alert"); 52105454c26SKuppuswamy Sathyanarayanan 52205454c26SKuppuswamy Sathyanarayanan if (intr == -1 || intr2nd == -1) 52305454c26SKuppuswamy Sathyanarayanan return NULL; 52405454c26SKuppuswamy Sathyanarayanan 525*712b6aa8SKuppuswamy Sathyanarayanan i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; 526*712b6aa8SKuppuswamy Sathyanarayanan intr2nd_pdata = intr2nd + INTEL_MID_IRQ_OFFSET; 52705454c26SKuppuswamy Sathyanarayanan 52805454c26SKuppuswamy Sathyanarayanan return &intr2nd_pdata; 52905454c26SKuppuswamy Sathyanarayanan } 53005454c26SKuppuswamy Sathyanarayanan 53105454c26SKuppuswamy Sathyanarayanan static void __init *lis331dl_platform_data(void *info) 53205454c26SKuppuswamy Sathyanarayanan { 53305454c26SKuppuswamy Sathyanarayanan static short intr2nd_pdata; 53405454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 53505454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("accel_int"); 53605454c26SKuppuswamy Sathyanarayanan int intr2nd = get_gpio_by_name("accel_2"); 53705454c26SKuppuswamy Sathyanarayanan 53805454c26SKuppuswamy Sathyanarayanan if (intr == -1 || intr2nd == -1) 53905454c26SKuppuswamy Sathyanarayanan return NULL; 54005454c26SKuppuswamy Sathyanarayanan 541*712b6aa8SKuppuswamy Sathyanarayanan i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; 542*712b6aa8SKuppuswamy Sathyanarayanan intr2nd_pdata = intr2nd + INTEL_MID_IRQ_OFFSET; 54305454c26SKuppuswamy Sathyanarayanan 54405454c26SKuppuswamy Sathyanarayanan return &intr2nd_pdata; 54505454c26SKuppuswamy Sathyanarayanan } 54605454c26SKuppuswamy Sathyanarayanan 54705454c26SKuppuswamy Sathyanarayanan static void __init *no_platform_data(void *info) 54805454c26SKuppuswamy Sathyanarayanan { 54905454c26SKuppuswamy Sathyanarayanan return NULL; 55005454c26SKuppuswamy Sathyanarayanan } 55105454c26SKuppuswamy Sathyanarayanan 55205454c26SKuppuswamy Sathyanarayanan static struct resource msic_resources[] = { 55305454c26SKuppuswamy Sathyanarayanan { 55405454c26SKuppuswamy Sathyanarayanan .start = INTEL_MSIC_IRQ_PHYS_BASE, 55505454c26SKuppuswamy Sathyanarayanan .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1, 55605454c26SKuppuswamy Sathyanarayanan .flags = IORESOURCE_MEM, 55705454c26SKuppuswamy Sathyanarayanan }, 55805454c26SKuppuswamy Sathyanarayanan }; 55905454c26SKuppuswamy Sathyanarayanan 56005454c26SKuppuswamy Sathyanarayanan static struct intel_msic_platform_data msic_pdata; 56105454c26SKuppuswamy Sathyanarayanan 56205454c26SKuppuswamy Sathyanarayanan static struct platform_device msic_device = { 56305454c26SKuppuswamy Sathyanarayanan .name = "intel_msic", 56405454c26SKuppuswamy Sathyanarayanan .id = -1, 56505454c26SKuppuswamy Sathyanarayanan .dev = { 56605454c26SKuppuswamy Sathyanarayanan .platform_data = &msic_pdata, 56705454c26SKuppuswamy Sathyanarayanan }, 56805454c26SKuppuswamy Sathyanarayanan .num_resources = ARRAY_SIZE(msic_resources), 56905454c26SKuppuswamy Sathyanarayanan .resource = msic_resources, 57005454c26SKuppuswamy Sathyanarayanan }; 57105454c26SKuppuswamy Sathyanarayanan 572*712b6aa8SKuppuswamy Sathyanarayanan static inline bool intel_mid_has_msic(void) 57305454c26SKuppuswamy Sathyanarayanan { 574*712b6aa8SKuppuswamy Sathyanarayanan return intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL; 57505454c26SKuppuswamy Sathyanarayanan } 57605454c26SKuppuswamy Sathyanarayanan 57705454c26SKuppuswamy Sathyanarayanan static int msic_scu_status_change(struct notifier_block *nb, 57805454c26SKuppuswamy Sathyanarayanan unsigned long code, void *data) 57905454c26SKuppuswamy Sathyanarayanan { 58005454c26SKuppuswamy Sathyanarayanan if (code == SCU_DOWN) { 58105454c26SKuppuswamy Sathyanarayanan platform_device_unregister(&msic_device); 58205454c26SKuppuswamy Sathyanarayanan return 0; 58305454c26SKuppuswamy Sathyanarayanan } 58405454c26SKuppuswamy Sathyanarayanan 58505454c26SKuppuswamy Sathyanarayanan return platform_device_register(&msic_device); 58605454c26SKuppuswamy Sathyanarayanan } 58705454c26SKuppuswamy Sathyanarayanan 58805454c26SKuppuswamy Sathyanarayanan static int __init msic_init(void) 58905454c26SKuppuswamy Sathyanarayanan { 59005454c26SKuppuswamy Sathyanarayanan static struct notifier_block msic_scu_notifier = { 59105454c26SKuppuswamy Sathyanarayanan .notifier_call = msic_scu_status_change, 59205454c26SKuppuswamy Sathyanarayanan }; 59305454c26SKuppuswamy Sathyanarayanan 59405454c26SKuppuswamy Sathyanarayanan /* 59505454c26SKuppuswamy Sathyanarayanan * We need to be sure that the SCU IPC is ready before MSIC device 59605454c26SKuppuswamy Sathyanarayanan * can be registered. 59705454c26SKuppuswamy Sathyanarayanan */ 598*712b6aa8SKuppuswamy Sathyanarayanan if (intel_mid_has_msic()) 59905454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_add(&msic_scu_notifier); 60005454c26SKuppuswamy Sathyanarayanan 60105454c26SKuppuswamy Sathyanarayanan return 0; 60205454c26SKuppuswamy Sathyanarayanan } 60305454c26SKuppuswamy Sathyanarayanan arch_initcall(msic_init); 60405454c26SKuppuswamy Sathyanarayanan 60505454c26SKuppuswamy Sathyanarayanan /* 60605454c26SKuppuswamy Sathyanarayanan * msic_generic_platform_data - sets generic platform data for the block 60705454c26SKuppuswamy Sathyanarayanan * @info: pointer to the SFI device table entry for this block 60805454c26SKuppuswamy Sathyanarayanan * @block: MSIC block 60905454c26SKuppuswamy Sathyanarayanan * 61005454c26SKuppuswamy Sathyanarayanan * Function sets IRQ number from the SFI table entry for given device to 61105454c26SKuppuswamy Sathyanarayanan * the MSIC platform data. 61205454c26SKuppuswamy Sathyanarayanan */ 61305454c26SKuppuswamy Sathyanarayanan static void *msic_generic_platform_data(void *info, enum intel_msic_block block) 61405454c26SKuppuswamy Sathyanarayanan { 61505454c26SKuppuswamy Sathyanarayanan struct sfi_device_table_entry *entry = info; 61605454c26SKuppuswamy Sathyanarayanan 61705454c26SKuppuswamy Sathyanarayanan BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST); 61805454c26SKuppuswamy Sathyanarayanan msic_pdata.irq[block] = entry->irq; 61905454c26SKuppuswamy Sathyanarayanan 62005454c26SKuppuswamy Sathyanarayanan return no_platform_data(info); 62105454c26SKuppuswamy Sathyanarayanan } 62205454c26SKuppuswamy Sathyanarayanan 62305454c26SKuppuswamy Sathyanarayanan static void *msic_battery_platform_data(void *info) 62405454c26SKuppuswamy Sathyanarayanan { 62505454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY); 62605454c26SKuppuswamy Sathyanarayanan } 62705454c26SKuppuswamy Sathyanarayanan 62805454c26SKuppuswamy Sathyanarayanan static void *msic_gpio_platform_data(void *info) 62905454c26SKuppuswamy Sathyanarayanan { 63005454c26SKuppuswamy Sathyanarayanan static struct intel_msic_gpio_pdata pdata; 63105454c26SKuppuswamy Sathyanarayanan int gpio = get_gpio_by_name("msic_gpio_base"); 63205454c26SKuppuswamy Sathyanarayanan 63305454c26SKuppuswamy Sathyanarayanan if (gpio < 0) 63405454c26SKuppuswamy Sathyanarayanan return NULL; 63505454c26SKuppuswamy Sathyanarayanan 63605454c26SKuppuswamy Sathyanarayanan pdata.gpio_base = gpio; 63705454c26SKuppuswamy Sathyanarayanan msic_pdata.gpio = &pdata; 63805454c26SKuppuswamy Sathyanarayanan 63905454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO); 64005454c26SKuppuswamy Sathyanarayanan } 64105454c26SKuppuswamy Sathyanarayanan 64205454c26SKuppuswamy Sathyanarayanan static void *msic_audio_platform_data(void *info) 64305454c26SKuppuswamy Sathyanarayanan { 64405454c26SKuppuswamy Sathyanarayanan struct platform_device *pdev; 64505454c26SKuppuswamy Sathyanarayanan 64605454c26SKuppuswamy Sathyanarayanan pdev = platform_device_register_simple("sst-platform", -1, NULL, 0); 64705454c26SKuppuswamy Sathyanarayanan if (IS_ERR(pdev)) { 64805454c26SKuppuswamy Sathyanarayanan pr_err("failed to create audio platform device\n"); 64905454c26SKuppuswamy Sathyanarayanan return NULL; 65005454c26SKuppuswamy Sathyanarayanan } 65105454c26SKuppuswamy Sathyanarayanan 65205454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO); 65305454c26SKuppuswamy Sathyanarayanan } 65405454c26SKuppuswamy Sathyanarayanan 65505454c26SKuppuswamy Sathyanarayanan static void *msic_power_btn_platform_data(void *info) 65605454c26SKuppuswamy Sathyanarayanan { 65705454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN); 65805454c26SKuppuswamy Sathyanarayanan } 65905454c26SKuppuswamy Sathyanarayanan 66005454c26SKuppuswamy Sathyanarayanan static void *msic_ocd_platform_data(void *info) 66105454c26SKuppuswamy Sathyanarayanan { 66205454c26SKuppuswamy Sathyanarayanan static struct intel_msic_ocd_pdata pdata; 66305454c26SKuppuswamy Sathyanarayanan int gpio = get_gpio_by_name("ocd_gpio"); 66405454c26SKuppuswamy Sathyanarayanan 66505454c26SKuppuswamy Sathyanarayanan if (gpio < 0) 66605454c26SKuppuswamy Sathyanarayanan return NULL; 66705454c26SKuppuswamy Sathyanarayanan 66805454c26SKuppuswamy Sathyanarayanan pdata.gpio = gpio; 66905454c26SKuppuswamy Sathyanarayanan msic_pdata.ocd = &pdata; 67005454c26SKuppuswamy Sathyanarayanan 67105454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); 67205454c26SKuppuswamy Sathyanarayanan } 67305454c26SKuppuswamy Sathyanarayanan 67405454c26SKuppuswamy Sathyanarayanan static void *msic_thermal_platform_data(void *info) 67505454c26SKuppuswamy Sathyanarayanan { 67605454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL); 67705454c26SKuppuswamy Sathyanarayanan } 67805454c26SKuppuswamy Sathyanarayanan 67905454c26SKuppuswamy Sathyanarayanan /* tc35876x DSI-LVDS bridge chip and panel platform data */ 68005454c26SKuppuswamy Sathyanarayanan static void *tc35876x_platform_data(void *data) 68105454c26SKuppuswamy Sathyanarayanan { 68205454c26SKuppuswamy Sathyanarayanan static struct tc35876x_platform_data pdata; 68305454c26SKuppuswamy Sathyanarayanan 68405454c26SKuppuswamy Sathyanarayanan /* gpio pins set to -1 will not be used by the driver */ 68505454c26SKuppuswamy Sathyanarayanan pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); 68605454c26SKuppuswamy Sathyanarayanan pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); 68705454c26SKuppuswamy Sathyanarayanan pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); 68805454c26SKuppuswamy Sathyanarayanan 68905454c26SKuppuswamy Sathyanarayanan return &pdata; 69005454c26SKuppuswamy Sathyanarayanan } 69105454c26SKuppuswamy Sathyanarayanan 69205454c26SKuppuswamy Sathyanarayanan static const struct devs_id __initconst device_ids[] = { 69305454c26SKuppuswamy Sathyanarayanan {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, 69405454c26SKuppuswamy Sathyanarayanan {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, 69505454c26SKuppuswamy Sathyanarayanan {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data}, 69605454c26SKuppuswamy Sathyanarayanan {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, 69705454c26SKuppuswamy Sathyanarayanan {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, 69805454c26SKuppuswamy Sathyanarayanan {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, 69905454c26SKuppuswamy Sathyanarayanan {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data}, 70005454c26SKuppuswamy Sathyanarayanan {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, 70105454c26SKuppuswamy Sathyanarayanan {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, 70205454c26SKuppuswamy Sathyanarayanan {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, 70305454c26SKuppuswamy Sathyanarayanan {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, 70405454c26SKuppuswamy Sathyanarayanan {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, 70505454c26SKuppuswamy Sathyanarayanan 70605454c26SKuppuswamy Sathyanarayanan /* MSIC subdevices */ 70705454c26SKuppuswamy Sathyanarayanan {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, 70805454c26SKuppuswamy Sathyanarayanan {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data}, 70905454c26SKuppuswamy Sathyanarayanan {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, 71005454c26SKuppuswamy Sathyanarayanan {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, 71105454c26SKuppuswamy Sathyanarayanan {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, 71205454c26SKuppuswamy Sathyanarayanan {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data}, 71305454c26SKuppuswamy Sathyanarayanan 71405454c26SKuppuswamy Sathyanarayanan {}, 71505454c26SKuppuswamy Sathyanarayanan }; 71605454c26SKuppuswamy Sathyanarayanan 71705454c26SKuppuswamy Sathyanarayanan #define MAX_IPCDEVS 24 71805454c26SKuppuswamy Sathyanarayanan static struct platform_device *ipc_devs[MAX_IPCDEVS]; 71905454c26SKuppuswamy Sathyanarayanan static int ipc_next_dev; 72005454c26SKuppuswamy Sathyanarayanan 72105454c26SKuppuswamy Sathyanarayanan #define MAX_SCU_SPI 24 72205454c26SKuppuswamy Sathyanarayanan static struct spi_board_info *spi_devs[MAX_SCU_SPI]; 72305454c26SKuppuswamy Sathyanarayanan static int spi_next_dev; 72405454c26SKuppuswamy Sathyanarayanan 72505454c26SKuppuswamy Sathyanarayanan #define MAX_SCU_I2C 24 72605454c26SKuppuswamy Sathyanarayanan static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; 72705454c26SKuppuswamy Sathyanarayanan static int i2c_bus[MAX_SCU_I2C]; 72805454c26SKuppuswamy Sathyanarayanan static int i2c_next_dev; 72905454c26SKuppuswamy Sathyanarayanan 73005454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_device_register(struct platform_device *pdev) 73105454c26SKuppuswamy Sathyanarayanan { 73205454c26SKuppuswamy Sathyanarayanan if (ipc_next_dev == MAX_IPCDEVS) 73305454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU IPC devices"); 73405454c26SKuppuswamy Sathyanarayanan else 73505454c26SKuppuswamy Sathyanarayanan ipc_devs[ipc_next_dev++] = pdev; 73605454c26SKuppuswamy Sathyanarayanan } 73705454c26SKuppuswamy Sathyanarayanan 73805454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) 73905454c26SKuppuswamy Sathyanarayanan { 74005454c26SKuppuswamy Sathyanarayanan struct spi_board_info *new_dev; 74105454c26SKuppuswamy Sathyanarayanan 74205454c26SKuppuswamy Sathyanarayanan if (spi_next_dev == MAX_SCU_SPI) { 74305454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU SPI devices"); 74405454c26SKuppuswamy Sathyanarayanan return; 74505454c26SKuppuswamy Sathyanarayanan } 74605454c26SKuppuswamy Sathyanarayanan 74705454c26SKuppuswamy Sathyanarayanan new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); 74805454c26SKuppuswamy Sathyanarayanan if (!new_dev) { 74905454c26SKuppuswamy Sathyanarayanan pr_err("failed to alloc mem for delayed spi dev %s\n", 75005454c26SKuppuswamy Sathyanarayanan sdev->modalias); 75105454c26SKuppuswamy Sathyanarayanan return; 75205454c26SKuppuswamy Sathyanarayanan } 75305454c26SKuppuswamy Sathyanarayanan memcpy(new_dev, sdev, sizeof(*sdev)); 75405454c26SKuppuswamy Sathyanarayanan 75505454c26SKuppuswamy Sathyanarayanan spi_devs[spi_next_dev++] = new_dev; 75605454c26SKuppuswamy Sathyanarayanan } 75705454c26SKuppuswamy Sathyanarayanan 75805454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_i2c_device_register(int bus, 75905454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *idev) 76005454c26SKuppuswamy Sathyanarayanan { 76105454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *new_dev; 76205454c26SKuppuswamy Sathyanarayanan 76305454c26SKuppuswamy Sathyanarayanan if (i2c_next_dev == MAX_SCU_I2C) { 76405454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU I2C devices"); 76505454c26SKuppuswamy Sathyanarayanan return; 76605454c26SKuppuswamy Sathyanarayanan } 76705454c26SKuppuswamy Sathyanarayanan 76805454c26SKuppuswamy Sathyanarayanan new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); 76905454c26SKuppuswamy Sathyanarayanan if (!new_dev) { 77005454c26SKuppuswamy Sathyanarayanan pr_err("failed to alloc mem for delayed i2c dev %s\n", 77105454c26SKuppuswamy Sathyanarayanan idev->type); 77205454c26SKuppuswamy Sathyanarayanan return; 77305454c26SKuppuswamy Sathyanarayanan } 77405454c26SKuppuswamy Sathyanarayanan memcpy(new_dev, idev, sizeof(*idev)); 77505454c26SKuppuswamy Sathyanarayanan 77605454c26SKuppuswamy Sathyanarayanan i2c_bus[i2c_next_dev] = bus; 77705454c26SKuppuswamy Sathyanarayanan i2c_devs[i2c_next_dev++] = new_dev; 77805454c26SKuppuswamy Sathyanarayanan } 77905454c26SKuppuswamy Sathyanarayanan 78005454c26SKuppuswamy Sathyanarayanan BLOCKING_NOTIFIER_HEAD(intel_scu_notifier); 78105454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_notifier); 78205454c26SKuppuswamy Sathyanarayanan 78305454c26SKuppuswamy Sathyanarayanan /* Called by IPC driver */ 78405454c26SKuppuswamy Sathyanarayanan void intel_scu_devices_create(void) 78505454c26SKuppuswamy Sathyanarayanan { 78605454c26SKuppuswamy Sathyanarayanan int i; 78705454c26SKuppuswamy Sathyanarayanan 78805454c26SKuppuswamy Sathyanarayanan for (i = 0; i < ipc_next_dev; i++) 78905454c26SKuppuswamy Sathyanarayanan platform_device_add(ipc_devs[i]); 79005454c26SKuppuswamy Sathyanarayanan 79105454c26SKuppuswamy Sathyanarayanan for (i = 0; i < spi_next_dev; i++) 79205454c26SKuppuswamy Sathyanarayanan spi_register_board_info(spi_devs[i], 1); 79305454c26SKuppuswamy Sathyanarayanan 79405454c26SKuppuswamy Sathyanarayanan for (i = 0; i < i2c_next_dev; i++) { 79505454c26SKuppuswamy Sathyanarayanan struct i2c_adapter *adapter; 79605454c26SKuppuswamy Sathyanarayanan struct i2c_client *client; 79705454c26SKuppuswamy Sathyanarayanan 79805454c26SKuppuswamy Sathyanarayanan adapter = i2c_get_adapter(i2c_bus[i]); 79905454c26SKuppuswamy Sathyanarayanan if (adapter) { 80005454c26SKuppuswamy Sathyanarayanan client = i2c_new_device(adapter, i2c_devs[i]); 80105454c26SKuppuswamy Sathyanarayanan if (!client) 80205454c26SKuppuswamy Sathyanarayanan pr_err("can't create i2c device %s\n", 80305454c26SKuppuswamy Sathyanarayanan i2c_devs[i]->type); 80405454c26SKuppuswamy Sathyanarayanan } else 80505454c26SKuppuswamy Sathyanarayanan i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); 80605454c26SKuppuswamy Sathyanarayanan } 80705454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_post(SCU_AVAILABLE, NULL); 80805454c26SKuppuswamy Sathyanarayanan } 80905454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_devices_create); 81005454c26SKuppuswamy Sathyanarayanan 81105454c26SKuppuswamy Sathyanarayanan /* Called by IPC driver */ 81205454c26SKuppuswamy Sathyanarayanan void intel_scu_devices_destroy(void) 81305454c26SKuppuswamy Sathyanarayanan { 81405454c26SKuppuswamy Sathyanarayanan int i; 81505454c26SKuppuswamy Sathyanarayanan 81605454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_post(SCU_DOWN, NULL); 81705454c26SKuppuswamy Sathyanarayanan 81805454c26SKuppuswamy Sathyanarayanan for (i = 0; i < ipc_next_dev; i++) 81905454c26SKuppuswamy Sathyanarayanan platform_device_del(ipc_devs[i]); 82005454c26SKuppuswamy Sathyanarayanan } 82105454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); 82205454c26SKuppuswamy Sathyanarayanan 82305454c26SKuppuswamy Sathyanarayanan static void __init install_irq_resource(struct platform_device *pdev, int irq) 82405454c26SKuppuswamy Sathyanarayanan { 82505454c26SKuppuswamy Sathyanarayanan /* Single threaded */ 82605454c26SKuppuswamy Sathyanarayanan static struct resource __initdata res = { 82705454c26SKuppuswamy Sathyanarayanan .name = "IRQ", 82805454c26SKuppuswamy Sathyanarayanan .flags = IORESOURCE_IRQ, 82905454c26SKuppuswamy Sathyanarayanan }; 83005454c26SKuppuswamy Sathyanarayanan res.start = irq; 83105454c26SKuppuswamy Sathyanarayanan platform_device_add_resources(pdev, &res, 1); 83205454c26SKuppuswamy Sathyanarayanan } 83305454c26SKuppuswamy Sathyanarayanan 83405454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry) 83505454c26SKuppuswamy Sathyanarayanan { 83605454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 83705454c26SKuppuswamy Sathyanarayanan struct platform_device *pdev; 83805454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 83905454c26SKuppuswamy Sathyanarayanan 84005454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 84105454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_IPC && 84205454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, entry->name, SFI_NAME_LEN)) { 84305454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(entry); 84405454c26SKuppuswamy Sathyanarayanan break; 84505454c26SKuppuswamy Sathyanarayanan } 84605454c26SKuppuswamy Sathyanarayanan dev++; 84705454c26SKuppuswamy Sathyanarayanan } 84805454c26SKuppuswamy Sathyanarayanan 84905454c26SKuppuswamy Sathyanarayanan /* 85005454c26SKuppuswamy Sathyanarayanan * On Medfield the platform device creation is handled by the MSIC 85105454c26SKuppuswamy Sathyanarayanan * MFD driver so we don't need to do it here. 85205454c26SKuppuswamy Sathyanarayanan */ 853*712b6aa8SKuppuswamy Sathyanarayanan if (intel_mid_has_msic()) 85405454c26SKuppuswamy Sathyanarayanan return; 85505454c26SKuppuswamy Sathyanarayanan 85605454c26SKuppuswamy Sathyanarayanan pdev = platform_device_alloc(entry->name, 0); 85705454c26SKuppuswamy Sathyanarayanan if (pdev == NULL) { 85805454c26SKuppuswamy Sathyanarayanan pr_err("out of memory for SFI platform device '%s'.\n", 85905454c26SKuppuswamy Sathyanarayanan entry->name); 86005454c26SKuppuswamy Sathyanarayanan return; 86105454c26SKuppuswamy Sathyanarayanan } 86205454c26SKuppuswamy Sathyanarayanan install_irq_resource(pdev, entry->irq); 86305454c26SKuppuswamy Sathyanarayanan 86405454c26SKuppuswamy Sathyanarayanan pdev->dev.platform_data = pdata; 86505454c26SKuppuswamy Sathyanarayanan intel_scu_device_register(pdev); 86605454c26SKuppuswamy Sathyanarayanan } 86705454c26SKuppuswamy Sathyanarayanan 86805454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) 86905454c26SKuppuswamy Sathyanarayanan { 87005454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 87105454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 87205454c26SKuppuswamy Sathyanarayanan 87305454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 87405454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_SPI && 87505454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, spi_info->modalias, 87605454c26SKuppuswamy Sathyanarayanan SFI_NAME_LEN)) { 87705454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(spi_info); 87805454c26SKuppuswamy Sathyanarayanan break; 87905454c26SKuppuswamy Sathyanarayanan } 88005454c26SKuppuswamy Sathyanarayanan dev++; 88105454c26SKuppuswamy Sathyanarayanan } 88205454c26SKuppuswamy Sathyanarayanan spi_info->platform_data = pdata; 88305454c26SKuppuswamy Sathyanarayanan if (dev->delay) 88405454c26SKuppuswamy Sathyanarayanan intel_scu_spi_device_register(spi_info); 88505454c26SKuppuswamy Sathyanarayanan else 88605454c26SKuppuswamy Sathyanarayanan spi_register_board_info(spi_info, 1); 88705454c26SKuppuswamy Sathyanarayanan } 88805454c26SKuppuswamy Sathyanarayanan 88905454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) 89005454c26SKuppuswamy Sathyanarayanan { 89105454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 89205454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 89305454c26SKuppuswamy Sathyanarayanan 89405454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 89505454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_I2C && 89605454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { 89705454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(i2c_info); 89805454c26SKuppuswamy Sathyanarayanan break; 89905454c26SKuppuswamy Sathyanarayanan } 90005454c26SKuppuswamy Sathyanarayanan dev++; 90105454c26SKuppuswamy Sathyanarayanan } 90205454c26SKuppuswamy Sathyanarayanan i2c_info->platform_data = pdata; 90305454c26SKuppuswamy Sathyanarayanan 90405454c26SKuppuswamy Sathyanarayanan if (dev->delay) 90505454c26SKuppuswamy Sathyanarayanan intel_scu_i2c_device_register(bus, i2c_info); 90605454c26SKuppuswamy Sathyanarayanan else 90705454c26SKuppuswamy Sathyanarayanan i2c_register_board_info(bus, i2c_info, 1); 90805454c26SKuppuswamy Sathyanarayanan } 90905454c26SKuppuswamy Sathyanarayanan 91005454c26SKuppuswamy Sathyanarayanan 91105454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_devs(struct sfi_table_header *table) 91205454c26SKuppuswamy Sathyanarayanan { 91305454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 91405454c26SKuppuswamy Sathyanarayanan struct sfi_device_table_entry *pentry; 91505454c26SKuppuswamy Sathyanarayanan struct spi_board_info spi_info; 91605454c26SKuppuswamy Sathyanarayanan struct i2c_board_info i2c_info; 91705454c26SKuppuswamy Sathyanarayanan int num, i, bus; 91805454c26SKuppuswamy Sathyanarayanan int ioapic; 91905454c26SKuppuswamy Sathyanarayanan struct io_apic_irq_attr irq_attr; 92005454c26SKuppuswamy Sathyanarayanan 92105454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 92205454c26SKuppuswamy Sathyanarayanan num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); 92305454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_device_table_entry *)sb->pentry; 92405454c26SKuppuswamy Sathyanarayanan 92505454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++, pentry++) { 92605454c26SKuppuswamy Sathyanarayanan int irq = pentry->irq; 92705454c26SKuppuswamy Sathyanarayanan 92805454c26SKuppuswamy Sathyanarayanan if (irq != (u8)0xff) { /* native RTE case */ 92905454c26SKuppuswamy Sathyanarayanan /* these SPI2 devices are not exposed to system as PCI 93005454c26SKuppuswamy Sathyanarayanan * devices, but they have separate RTE entry in IOAPIC 93105454c26SKuppuswamy Sathyanarayanan * so we have to enable them one by one here 93205454c26SKuppuswamy Sathyanarayanan */ 93305454c26SKuppuswamy Sathyanarayanan ioapic = mp_find_ioapic(irq); 93405454c26SKuppuswamy Sathyanarayanan irq_attr.ioapic = ioapic; 93505454c26SKuppuswamy Sathyanarayanan irq_attr.ioapic_pin = irq; 93605454c26SKuppuswamy Sathyanarayanan irq_attr.trigger = 1; 93705454c26SKuppuswamy Sathyanarayanan irq_attr.polarity = 1; 93805454c26SKuppuswamy Sathyanarayanan io_apic_set_pci_routing(NULL, irq, &irq_attr); 93905454c26SKuppuswamy Sathyanarayanan } else 94005454c26SKuppuswamy Sathyanarayanan irq = 0; /* No irq */ 94105454c26SKuppuswamy Sathyanarayanan 94205454c26SKuppuswamy Sathyanarayanan switch (pentry->type) { 94305454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_IPC: 94405454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: IPC bus, name = %16.16s, " 94505454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x\n", i, pentry->name, pentry->irq); 94605454c26SKuppuswamy Sathyanarayanan sfi_handle_ipc_dev(pentry); 94705454c26SKuppuswamy Sathyanarayanan break; 94805454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_SPI: 94905454c26SKuppuswamy Sathyanarayanan memset(&spi_info, 0, sizeof(spi_info)); 95005454c26SKuppuswamy Sathyanarayanan strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); 95105454c26SKuppuswamy Sathyanarayanan spi_info.irq = irq; 95205454c26SKuppuswamy Sathyanarayanan spi_info.bus_num = pentry->host_num; 95305454c26SKuppuswamy Sathyanarayanan spi_info.chip_select = pentry->addr; 95405454c26SKuppuswamy Sathyanarayanan spi_info.max_speed_hz = pentry->max_freq; 95505454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " 95605454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x, max_freq = %d, cs = %d\n", i, 95705454c26SKuppuswamy Sathyanarayanan spi_info.bus_num, 95805454c26SKuppuswamy Sathyanarayanan spi_info.modalias, 95905454c26SKuppuswamy Sathyanarayanan spi_info.irq, 96005454c26SKuppuswamy Sathyanarayanan spi_info.max_speed_hz, 96105454c26SKuppuswamy Sathyanarayanan spi_info.chip_select); 96205454c26SKuppuswamy Sathyanarayanan sfi_handle_spi_dev(&spi_info); 96305454c26SKuppuswamy Sathyanarayanan break; 96405454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_I2C: 96505454c26SKuppuswamy Sathyanarayanan memset(&i2c_info, 0, sizeof(i2c_info)); 96605454c26SKuppuswamy Sathyanarayanan bus = pentry->host_num; 96705454c26SKuppuswamy Sathyanarayanan strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); 96805454c26SKuppuswamy Sathyanarayanan i2c_info.irq = irq; 96905454c26SKuppuswamy Sathyanarayanan i2c_info.addr = pentry->addr; 97005454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " 97105454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x, addr = 0x%x\n", i, bus, 97205454c26SKuppuswamy Sathyanarayanan i2c_info.type, 97305454c26SKuppuswamy Sathyanarayanan i2c_info.irq, 97405454c26SKuppuswamy Sathyanarayanan i2c_info.addr); 97505454c26SKuppuswamy Sathyanarayanan sfi_handle_i2c_dev(bus, &i2c_info); 97605454c26SKuppuswamy Sathyanarayanan break; 97705454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_UART: 97805454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_HSI: 97905454c26SKuppuswamy Sathyanarayanan default: 98005454c26SKuppuswamy Sathyanarayanan ; 98105454c26SKuppuswamy Sathyanarayanan } 98205454c26SKuppuswamy Sathyanarayanan } 98305454c26SKuppuswamy Sathyanarayanan return 0; 98405454c26SKuppuswamy Sathyanarayanan } 98505454c26SKuppuswamy Sathyanarayanan 986*712b6aa8SKuppuswamy Sathyanarayanan static int __init intel_mid_platform_init(void) 98705454c26SKuppuswamy Sathyanarayanan { 98805454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); 98905454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); 99005454c26SKuppuswamy Sathyanarayanan return 0; 99105454c26SKuppuswamy Sathyanarayanan } 992*712b6aa8SKuppuswamy Sathyanarayanan arch_initcall(intel_mid_platform_init); 99305454c26SKuppuswamy Sathyanarayanan 99405454c26SKuppuswamy Sathyanarayanan /* 99505454c26SKuppuswamy Sathyanarayanan * we will search these buttons in SFI GPIO table (by name) 99605454c26SKuppuswamy Sathyanarayanan * and register them dynamically. Please add all possible 99705454c26SKuppuswamy Sathyanarayanan * buttons here, we will shrink them if no GPIO found. 99805454c26SKuppuswamy Sathyanarayanan */ 99905454c26SKuppuswamy Sathyanarayanan static struct gpio_keys_button gpio_button[] = { 100005454c26SKuppuswamy Sathyanarayanan {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, 100105454c26SKuppuswamy Sathyanarayanan {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, 100205454c26SKuppuswamy Sathyanarayanan {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, 100305454c26SKuppuswamy Sathyanarayanan {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, 100405454c26SKuppuswamy Sathyanarayanan {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, 100505454c26SKuppuswamy Sathyanarayanan {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, 100605454c26SKuppuswamy Sathyanarayanan {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, 100705454c26SKuppuswamy Sathyanarayanan {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, 100805454c26SKuppuswamy Sathyanarayanan {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, 100905454c26SKuppuswamy Sathyanarayanan {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, 101005454c26SKuppuswamy Sathyanarayanan }; 101105454c26SKuppuswamy Sathyanarayanan 1012*712b6aa8SKuppuswamy Sathyanarayanan static struct gpio_keys_platform_data intel_mid_gpio_keys = { 101305454c26SKuppuswamy Sathyanarayanan .buttons = gpio_button, 101405454c26SKuppuswamy Sathyanarayanan .rep = 1, 101505454c26SKuppuswamy Sathyanarayanan .nbuttons = -1, /* will fill it after search */ 101605454c26SKuppuswamy Sathyanarayanan }; 101705454c26SKuppuswamy Sathyanarayanan 101805454c26SKuppuswamy Sathyanarayanan static struct platform_device pb_device = { 101905454c26SKuppuswamy Sathyanarayanan .name = "gpio-keys", 102005454c26SKuppuswamy Sathyanarayanan .id = -1, 102105454c26SKuppuswamy Sathyanarayanan .dev = { 1022*712b6aa8SKuppuswamy Sathyanarayanan .platform_data = &intel_mid_gpio_keys, 102305454c26SKuppuswamy Sathyanarayanan }, 102405454c26SKuppuswamy Sathyanarayanan }; 102505454c26SKuppuswamy Sathyanarayanan 102605454c26SKuppuswamy Sathyanarayanan /* 102705454c26SKuppuswamy Sathyanarayanan * Shrink the non-existent buttons, register the gpio button 102805454c26SKuppuswamy Sathyanarayanan * device if there is some 102905454c26SKuppuswamy Sathyanarayanan */ 103005454c26SKuppuswamy Sathyanarayanan static int __init pb_keys_init(void) 103105454c26SKuppuswamy Sathyanarayanan { 103205454c26SKuppuswamy Sathyanarayanan struct gpio_keys_button *gb = gpio_button; 103305454c26SKuppuswamy Sathyanarayanan int i, num, good = 0; 103405454c26SKuppuswamy Sathyanarayanan 103505454c26SKuppuswamy Sathyanarayanan num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); 103605454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++) { 103705454c26SKuppuswamy Sathyanarayanan gb[i].gpio = get_gpio_by_name(gb[i].desc); 103805454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, 103905454c26SKuppuswamy Sathyanarayanan gb[i].gpio); 104005454c26SKuppuswamy Sathyanarayanan if (gb[i].gpio == -1) 104105454c26SKuppuswamy Sathyanarayanan continue; 104205454c26SKuppuswamy Sathyanarayanan 104305454c26SKuppuswamy Sathyanarayanan if (i != good) 104405454c26SKuppuswamy Sathyanarayanan gb[good] = gb[i]; 104505454c26SKuppuswamy Sathyanarayanan good++; 104605454c26SKuppuswamy Sathyanarayanan } 104705454c26SKuppuswamy Sathyanarayanan 104805454c26SKuppuswamy Sathyanarayanan if (good) { 1049*712b6aa8SKuppuswamy Sathyanarayanan intel_mid_gpio_keys.nbuttons = good; 105005454c26SKuppuswamy Sathyanarayanan return platform_device_register(&pb_device); 105105454c26SKuppuswamy Sathyanarayanan } 105205454c26SKuppuswamy Sathyanarayanan return 0; 105305454c26SKuppuswamy Sathyanarayanan } 105405454c26SKuppuswamy Sathyanarayanan late_initcall(pb_keys_init); 1055