1*05454c26SKuppuswamy Sathyanarayanan /* 2*05454c26SKuppuswamy Sathyanarayanan * intel-mid.c: Intel MID platform setup code 3*05454c26SKuppuswamy Sathyanarayanan * 4*05454c26SKuppuswamy Sathyanarayanan * (C) Copyright 2008, 2012 Intel Corporation 5*05454c26SKuppuswamy Sathyanarayanan * Author: Jacob Pan (jacob.jun.pan@intel.com) 6*05454c26SKuppuswamy Sathyanarayanan * Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com> 7*05454c26SKuppuswamy Sathyanarayanan * 8*05454c26SKuppuswamy Sathyanarayanan * This program is free software; you can redistribute it and/or 9*05454c26SKuppuswamy Sathyanarayanan * modify it under the terms of the GNU General Public License 10*05454c26SKuppuswamy Sathyanarayanan * as published by the Free Software Foundation; version 2 11*05454c26SKuppuswamy Sathyanarayanan * of the License. 12*05454c26SKuppuswamy Sathyanarayanan */ 13*05454c26SKuppuswamy Sathyanarayanan 14*05454c26SKuppuswamy Sathyanarayanan #define pr_fmt(fmt) "mrst: " fmt 15*05454c26SKuppuswamy Sathyanarayanan 16*05454c26SKuppuswamy Sathyanarayanan #include <linux/init.h> 17*05454c26SKuppuswamy Sathyanarayanan #include <linux/kernel.h> 18*05454c26SKuppuswamy Sathyanarayanan #include <linux/interrupt.h> 19*05454c26SKuppuswamy Sathyanarayanan #include <linux/scatterlist.h> 20*05454c26SKuppuswamy Sathyanarayanan #include <linux/sfi.h> 21*05454c26SKuppuswamy Sathyanarayanan #include <linux/intel_pmic_gpio.h> 22*05454c26SKuppuswamy Sathyanarayanan #include <linux/spi/spi.h> 23*05454c26SKuppuswamy Sathyanarayanan #include <linux/i2c.h> 24*05454c26SKuppuswamy Sathyanarayanan #include <linux/platform_data/pca953x.h> 25*05454c26SKuppuswamy Sathyanarayanan #include <linux/gpio_keys.h> 26*05454c26SKuppuswamy Sathyanarayanan #include <linux/input.h> 27*05454c26SKuppuswamy Sathyanarayanan #include <linux/platform_device.h> 28*05454c26SKuppuswamy Sathyanarayanan #include <linux/irq.h> 29*05454c26SKuppuswamy Sathyanarayanan #include <linux/module.h> 30*05454c26SKuppuswamy Sathyanarayanan #include <linux/notifier.h> 31*05454c26SKuppuswamy Sathyanarayanan #include <linux/mfd/intel_msic.h> 32*05454c26SKuppuswamy Sathyanarayanan #include <linux/gpio.h> 33*05454c26SKuppuswamy Sathyanarayanan #include <linux/i2c/tc35876x.h> 34*05454c26SKuppuswamy Sathyanarayanan 35*05454c26SKuppuswamy Sathyanarayanan #include <asm/setup.h> 36*05454c26SKuppuswamy Sathyanarayanan #include <asm/mpspec_def.h> 37*05454c26SKuppuswamy Sathyanarayanan #include <asm/hw_irq.h> 38*05454c26SKuppuswamy Sathyanarayanan #include <asm/apic.h> 39*05454c26SKuppuswamy Sathyanarayanan #include <asm/io_apic.h> 40*05454c26SKuppuswamy Sathyanarayanan #include <asm/intel-mid.h> 41*05454c26SKuppuswamy Sathyanarayanan #include <asm/intel_mid_vrtc.h> 42*05454c26SKuppuswamy Sathyanarayanan #include <asm/io.h> 43*05454c26SKuppuswamy Sathyanarayanan #include <asm/i8259.h> 44*05454c26SKuppuswamy Sathyanarayanan #include <asm/intel_scu_ipc.h> 45*05454c26SKuppuswamy Sathyanarayanan #include <asm/apb_timer.h> 46*05454c26SKuppuswamy Sathyanarayanan #include <asm/reboot.h> 47*05454c26SKuppuswamy Sathyanarayanan 48*05454c26SKuppuswamy Sathyanarayanan /* 49*05454c26SKuppuswamy Sathyanarayanan * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, 50*05454c26SKuppuswamy Sathyanarayanan * cmdline option x86_mrst_timer can be used to override the configuration 51*05454c26SKuppuswamy Sathyanarayanan * to prefer one or the other. 52*05454c26SKuppuswamy Sathyanarayanan * at runtime, there are basically three timer configurations: 53*05454c26SKuppuswamy Sathyanarayanan * 1. per cpu apbt clock only 54*05454c26SKuppuswamy Sathyanarayanan * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only 55*05454c26SKuppuswamy Sathyanarayanan * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. 56*05454c26SKuppuswamy Sathyanarayanan * 57*05454c26SKuppuswamy Sathyanarayanan * by default (without cmdline option), platform code first detects cpu type 58*05454c26SKuppuswamy Sathyanarayanan * to see if we are on lincroft or penwell, then set up both lapic or apbt 59*05454c26SKuppuswamy Sathyanarayanan * clocks accordingly. 60*05454c26SKuppuswamy Sathyanarayanan * i.e. by default, medfield uses configuration #2, moorestown uses #1. 61*05454c26SKuppuswamy Sathyanarayanan * config #3 is supported but not recommended on medfield. 62*05454c26SKuppuswamy Sathyanarayanan * 63*05454c26SKuppuswamy Sathyanarayanan * rating and feature summary: 64*05454c26SKuppuswamy Sathyanarayanan * lapic (with C3STOP) --------- 100 65*05454c26SKuppuswamy Sathyanarayanan * apbt (always-on) ------------ 110 66*05454c26SKuppuswamy Sathyanarayanan * lapic (always-on,ARAT) ------ 150 67*05454c26SKuppuswamy Sathyanarayanan */ 68*05454c26SKuppuswamy Sathyanarayanan 69*05454c26SKuppuswamy Sathyanarayanan enum mrst_timer_options mrst_timer_options; 70*05454c26SKuppuswamy Sathyanarayanan 71*05454c26SKuppuswamy Sathyanarayanan static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; 72*05454c26SKuppuswamy Sathyanarayanan static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; 73*05454c26SKuppuswamy Sathyanarayanan enum mrst_cpu_type __mrst_cpu_chip; 74*05454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(__mrst_cpu_chip); 75*05454c26SKuppuswamy Sathyanarayanan 76*05454c26SKuppuswamy Sathyanarayanan int sfi_mtimer_num; 77*05454c26SKuppuswamy Sathyanarayanan 78*05454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; 79*05454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(sfi_mrtc_array); 80*05454c26SKuppuswamy Sathyanarayanan int sfi_mrtc_num; 81*05454c26SKuppuswamy Sathyanarayanan 82*05454c26SKuppuswamy Sathyanarayanan static void mrst_power_off(void) 83*05454c26SKuppuswamy Sathyanarayanan { 84*05454c26SKuppuswamy Sathyanarayanan } 85*05454c26SKuppuswamy Sathyanarayanan 86*05454c26SKuppuswamy Sathyanarayanan static void mrst_reboot(void) 87*05454c26SKuppuswamy Sathyanarayanan { 88*05454c26SKuppuswamy Sathyanarayanan intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); 89*05454c26SKuppuswamy Sathyanarayanan } 90*05454c26SKuppuswamy Sathyanarayanan 91*05454c26SKuppuswamy Sathyanarayanan /* parse all the mtimer info to a static mtimer array */ 92*05454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_mtmr(struct sfi_table_header *table) 93*05454c26SKuppuswamy Sathyanarayanan { 94*05454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 95*05454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry *pentry; 96*05454c26SKuppuswamy Sathyanarayanan struct mpc_intsrc mp_irq; 97*05454c26SKuppuswamy Sathyanarayanan int totallen; 98*05454c26SKuppuswamy Sathyanarayanan 99*05454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 100*05454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_num) { 101*05454c26SKuppuswamy Sathyanarayanan sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, 102*05454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry); 103*05454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_timer_table_entry *) sb->pentry; 104*05454c26SKuppuswamy Sathyanarayanan totallen = sfi_mtimer_num * sizeof(*pentry); 105*05454c26SKuppuswamy Sathyanarayanan memcpy(sfi_mtimer_array, pentry, totallen); 106*05454c26SKuppuswamy Sathyanarayanan } 107*05454c26SKuppuswamy Sathyanarayanan 108*05454c26SKuppuswamy Sathyanarayanan pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); 109*05454c26SKuppuswamy Sathyanarayanan pentry = sfi_mtimer_array; 110*05454c26SKuppuswamy Sathyanarayanan for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { 111*05454c26SKuppuswamy Sathyanarayanan pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," 112*05454c26SKuppuswamy Sathyanarayanan " irq = %d\n", totallen, (u32)pentry->phys_addr, 113*05454c26SKuppuswamy Sathyanarayanan pentry->freq_hz, pentry->irq); 114*05454c26SKuppuswamy Sathyanarayanan if (!pentry->irq) 115*05454c26SKuppuswamy Sathyanarayanan continue; 116*05454c26SKuppuswamy Sathyanarayanan mp_irq.type = MP_INTSRC; 117*05454c26SKuppuswamy Sathyanarayanan mp_irq.irqtype = mp_INT; 118*05454c26SKuppuswamy Sathyanarayanan /* triggering mode edge bit 2-3, active high polarity bit 0-1 */ 119*05454c26SKuppuswamy Sathyanarayanan mp_irq.irqflag = 5; 120*05454c26SKuppuswamy Sathyanarayanan mp_irq.srcbus = MP_BUS_ISA; 121*05454c26SKuppuswamy Sathyanarayanan mp_irq.srcbusirq = pentry->irq; /* IRQ */ 122*05454c26SKuppuswamy Sathyanarayanan mp_irq.dstapic = MP_APIC_ALL; 123*05454c26SKuppuswamy Sathyanarayanan mp_irq.dstirq = pentry->irq; 124*05454c26SKuppuswamy Sathyanarayanan mp_save_irq(&mp_irq); 125*05454c26SKuppuswamy Sathyanarayanan } 126*05454c26SKuppuswamy Sathyanarayanan 127*05454c26SKuppuswamy Sathyanarayanan return 0; 128*05454c26SKuppuswamy Sathyanarayanan } 129*05454c26SKuppuswamy Sathyanarayanan 130*05454c26SKuppuswamy Sathyanarayanan struct sfi_timer_table_entry *sfi_get_mtmr(int hint) 131*05454c26SKuppuswamy Sathyanarayanan { 132*05454c26SKuppuswamy Sathyanarayanan int i; 133*05454c26SKuppuswamy Sathyanarayanan if (hint < sfi_mtimer_num) { 134*05454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_usage[hint]) { 135*05454c26SKuppuswamy Sathyanarayanan pr_debug("hint taken for timer %d irq %d\n", 136*05454c26SKuppuswamy Sathyanarayanan hint, sfi_mtimer_array[hint].irq); 137*05454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[hint] = 1; 138*05454c26SKuppuswamy Sathyanarayanan return &sfi_mtimer_array[hint]; 139*05454c26SKuppuswamy Sathyanarayanan } 140*05454c26SKuppuswamy Sathyanarayanan } 141*05454c26SKuppuswamy Sathyanarayanan /* take the first timer available */ 142*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < sfi_mtimer_num;) { 143*05454c26SKuppuswamy Sathyanarayanan if (!sfi_mtimer_usage[i]) { 144*05454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[i] = 1; 145*05454c26SKuppuswamy Sathyanarayanan return &sfi_mtimer_array[i]; 146*05454c26SKuppuswamy Sathyanarayanan } 147*05454c26SKuppuswamy Sathyanarayanan i++; 148*05454c26SKuppuswamy Sathyanarayanan } 149*05454c26SKuppuswamy Sathyanarayanan return NULL; 150*05454c26SKuppuswamy Sathyanarayanan } 151*05454c26SKuppuswamy Sathyanarayanan 152*05454c26SKuppuswamy Sathyanarayanan void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) 153*05454c26SKuppuswamy Sathyanarayanan { 154*05454c26SKuppuswamy Sathyanarayanan int i; 155*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < sfi_mtimer_num;) { 156*05454c26SKuppuswamy Sathyanarayanan if (mtmr->irq == sfi_mtimer_array[i].irq) { 157*05454c26SKuppuswamy Sathyanarayanan sfi_mtimer_usage[i] = 0; 158*05454c26SKuppuswamy Sathyanarayanan return; 159*05454c26SKuppuswamy Sathyanarayanan } 160*05454c26SKuppuswamy Sathyanarayanan i++; 161*05454c26SKuppuswamy Sathyanarayanan } 162*05454c26SKuppuswamy Sathyanarayanan } 163*05454c26SKuppuswamy Sathyanarayanan 164*05454c26SKuppuswamy Sathyanarayanan /* parse all the mrtc info to a global mrtc array */ 165*05454c26SKuppuswamy Sathyanarayanan int __init sfi_parse_mrtc(struct sfi_table_header *table) 166*05454c26SKuppuswamy Sathyanarayanan { 167*05454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 168*05454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry *pentry; 169*05454c26SKuppuswamy Sathyanarayanan struct mpc_intsrc mp_irq; 170*05454c26SKuppuswamy Sathyanarayanan 171*05454c26SKuppuswamy Sathyanarayanan int totallen; 172*05454c26SKuppuswamy Sathyanarayanan 173*05454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 174*05454c26SKuppuswamy Sathyanarayanan if (!sfi_mrtc_num) { 175*05454c26SKuppuswamy Sathyanarayanan sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, 176*05454c26SKuppuswamy Sathyanarayanan struct sfi_rtc_table_entry); 177*05454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_rtc_table_entry *)sb->pentry; 178*05454c26SKuppuswamy Sathyanarayanan totallen = sfi_mrtc_num * sizeof(*pentry); 179*05454c26SKuppuswamy Sathyanarayanan memcpy(sfi_mrtc_array, pentry, totallen); 180*05454c26SKuppuswamy Sathyanarayanan } 181*05454c26SKuppuswamy Sathyanarayanan 182*05454c26SKuppuswamy Sathyanarayanan pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); 183*05454c26SKuppuswamy Sathyanarayanan pentry = sfi_mrtc_array; 184*05454c26SKuppuswamy Sathyanarayanan for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { 185*05454c26SKuppuswamy Sathyanarayanan pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", 186*05454c26SKuppuswamy Sathyanarayanan totallen, (u32)pentry->phys_addr, pentry->irq); 187*05454c26SKuppuswamy Sathyanarayanan mp_irq.type = MP_INTSRC; 188*05454c26SKuppuswamy Sathyanarayanan mp_irq.irqtype = mp_INT; 189*05454c26SKuppuswamy Sathyanarayanan mp_irq.irqflag = 0xf; /* level trigger and active low */ 190*05454c26SKuppuswamy Sathyanarayanan mp_irq.srcbus = MP_BUS_ISA; 191*05454c26SKuppuswamy Sathyanarayanan mp_irq.srcbusirq = pentry->irq; /* IRQ */ 192*05454c26SKuppuswamy Sathyanarayanan mp_irq.dstapic = MP_APIC_ALL; 193*05454c26SKuppuswamy Sathyanarayanan mp_irq.dstirq = pentry->irq; 194*05454c26SKuppuswamy Sathyanarayanan mp_save_irq(&mp_irq); 195*05454c26SKuppuswamy Sathyanarayanan } 196*05454c26SKuppuswamy Sathyanarayanan return 0; 197*05454c26SKuppuswamy Sathyanarayanan } 198*05454c26SKuppuswamy Sathyanarayanan 199*05454c26SKuppuswamy Sathyanarayanan static unsigned long __init mrst_calibrate_tsc(void) 200*05454c26SKuppuswamy Sathyanarayanan { 201*05454c26SKuppuswamy Sathyanarayanan unsigned long fast_calibrate; 202*05454c26SKuppuswamy Sathyanarayanan u32 lo, hi, ratio, fsb; 203*05454c26SKuppuswamy Sathyanarayanan 204*05454c26SKuppuswamy Sathyanarayanan rdmsr(MSR_IA32_PERF_STATUS, lo, hi); 205*05454c26SKuppuswamy Sathyanarayanan pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); 206*05454c26SKuppuswamy Sathyanarayanan ratio = (hi >> 8) & 0x1f; 207*05454c26SKuppuswamy Sathyanarayanan pr_debug("ratio is %d\n", ratio); 208*05454c26SKuppuswamy Sathyanarayanan if (!ratio) { 209*05454c26SKuppuswamy Sathyanarayanan pr_err("read a zero ratio, should be incorrect!\n"); 210*05454c26SKuppuswamy Sathyanarayanan pr_err("force tsc ratio to 16 ...\n"); 211*05454c26SKuppuswamy Sathyanarayanan ratio = 16; 212*05454c26SKuppuswamy Sathyanarayanan } 213*05454c26SKuppuswamy Sathyanarayanan rdmsr(MSR_FSB_FREQ, lo, hi); 214*05454c26SKuppuswamy Sathyanarayanan if ((lo & 0x7) == 0x7) 215*05454c26SKuppuswamy Sathyanarayanan fsb = PENWELL_FSB_FREQ_83SKU; 216*05454c26SKuppuswamy Sathyanarayanan else 217*05454c26SKuppuswamy Sathyanarayanan fsb = PENWELL_FSB_FREQ_100SKU; 218*05454c26SKuppuswamy Sathyanarayanan fast_calibrate = ratio * fsb; 219*05454c26SKuppuswamy Sathyanarayanan pr_debug("read penwell tsc %lu khz\n", fast_calibrate); 220*05454c26SKuppuswamy Sathyanarayanan lapic_timer_frequency = fsb * 1000 / HZ; 221*05454c26SKuppuswamy Sathyanarayanan /* mark tsc clocksource as reliable */ 222*05454c26SKuppuswamy Sathyanarayanan set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); 223*05454c26SKuppuswamy Sathyanarayanan 224*05454c26SKuppuswamy Sathyanarayanan if (fast_calibrate) 225*05454c26SKuppuswamy Sathyanarayanan return fast_calibrate; 226*05454c26SKuppuswamy Sathyanarayanan 227*05454c26SKuppuswamy Sathyanarayanan return 0; 228*05454c26SKuppuswamy Sathyanarayanan } 229*05454c26SKuppuswamy Sathyanarayanan 230*05454c26SKuppuswamy Sathyanarayanan static void __init mrst_time_init(void) 231*05454c26SKuppuswamy Sathyanarayanan { 232*05454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); 233*05454c26SKuppuswamy Sathyanarayanan switch (mrst_timer_options) { 234*05454c26SKuppuswamy Sathyanarayanan case MRST_TIMER_APBT_ONLY: 235*05454c26SKuppuswamy Sathyanarayanan break; 236*05454c26SKuppuswamy Sathyanarayanan case MRST_TIMER_LAPIC_APBT: 237*05454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; 238*05454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; 239*05454c26SKuppuswamy Sathyanarayanan break; 240*05454c26SKuppuswamy Sathyanarayanan default: 241*05454c26SKuppuswamy Sathyanarayanan if (!boot_cpu_has(X86_FEATURE_ARAT)) 242*05454c26SKuppuswamy Sathyanarayanan break; 243*05454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; 244*05454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; 245*05454c26SKuppuswamy Sathyanarayanan return; 246*05454c26SKuppuswamy Sathyanarayanan } 247*05454c26SKuppuswamy Sathyanarayanan /* we need at least one APB timer */ 248*05454c26SKuppuswamy Sathyanarayanan pre_init_apic_IRQ0(); 249*05454c26SKuppuswamy Sathyanarayanan apbt_time_init(); 250*05454c26SKuppuswamy Sathyanarayanan } 251*05454c26SKuppuswamy Sathyanarayanan 252*05454c26SKuppuswamy Sathyanarayanan static void mrst_arch_setup(void) 253*05454c26SKuppuswamy Sathyanarayanan { 254*05454c26SKuppuswamy Sathyanarayanan if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) 255*05454c26SKuppuswamy Sathyanarayanan __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; 256*05454c26SKuppuswamy Sathyanarayanan else { 257*05454c26SKuppuswamy Sathyanarayanan pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", 258*05454c26SKuppuswamy Sathyanarayanan boot_cpu_data.x86, boot_cpu_data.x86_model); 259*05454c26SKuppuswamy Sathyanarayanan __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; 260*05454c26SKuppuswamy Sathyanarayanan } 261*05454c26SKuppuswamy Sathyanarayanan } 262*05454c26SKuppuswamy Sathyanarayanan 263*05454c26SKuppuswamy Sathyanarayanan /* MID systems don't have i8042 controller */ 264*05454c26SKuppuswamy Sathyanarayanan static int mrst_i8042_detect(void) 265*05454c26SKuppuswamy Sathyanarayanan { 266*05454c26SKuppuswamy Sathyanarayanan return 0; 267*05454c26SKuppuswamy Sathyanarayanan } 268*05454c26SKuppuswamy Sathyanarayanan 269*05454c26SKuppuswamy Sathyanarayanan /* 270*05454c26SKuppuswamy Sathyanarayanan * Moorestown does not have external NMI source nor port 0x61 to report 271*05454c26SKuppuswamy Sathyanarayanan * NMI status. The possible NMI sources are from pmu as a result of NMI 272*05454c26SKuppuswamy Sathyanarayanan * watchdog or lock debug. Reading io port 0x61 results in 0xff which 273*05454c26SKuppuswamy Sathyanarayanan * misled NMI handler. 274*05454c26SKuppuswamy Sathyanarayanan */ 275*05454c26SKuppuswamy Sathyanarayanan static unsigned char mrst_get_nmi_reason(void) 276*05454c26SKuppuswamy Sathyanarayanan { 277*05454c26SKuppuswamy Sathyanarayanan return 0; 278*05454c26SKuppuswamy Sathyanarayanan } 279*05454c26SKuppuswamy Sathyanarayanan 280*05454c26SKuppuswamy Sathyanarayanan /* 281*05454c26SKuppuswamy Sathyanarayanan * Moorestown specific x86_init function overrides and early setup 282*05454c26SKuppuswamy Sathyanarayanan * calls. 283*05454c26SKuppuswamy Sathyanarayanan */ 284*05454c26SKuppuswamy Sathyanarayanan void __init x86_mrst_early_setup(void) 285*05454c26SKuppuswamy Sathyanarayanan { 286*05454c26SKuppuswamy Sathyanarayanan x86_init.resources.probe_roms = x86_init_noop; 287*05454c26SKuppuswamy Sathyanarayanan x86_init.resources.reserve_resources = x86_init_noop; 288*05454c26SKuppuswamy Sathyanarayanan 289*05454c26SKuppuswamy Sathyanarayanan x86_init.timers.timer_init = mrst_time_init; 290*05454c26SKuppuswamy Sathyanarayanan x86_init.timers.setup_percpu_clockev = x86_init_noop; 291*05454c26SKuppuswamy Sathyanarayanan 292*05454c26SKuppuswamy Sathyanarayanan x86_init.irqs.pre_vector_init = x86_init_noop; 293*05454c26SKuppuswamy Sathyanarayanan 294*05454c26SKuppuswamy Sathyanarayanan x86_init.oem.arch_setup = mrst_arch_setup; 295*05454c26SKuppuswamy Sathyanarayanan 296*05454c26SKuppuswamy Sathyanarayanan x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; 297*05454c26SKuppuswamy Sathyanarayanan 298*05454c26SKuppuswamy Sathyanarayanan x86_platform.calibrate_tsc = mrst_calibrate_tsc; 299*05454c26SKuppuswamy Sathyanarayanan x86_platform.i8042_detect = mrst_i8042_detect; 300*05454c26SKuppuswamy Sathyanarayanan x86_init.timers.wallclock_init = mrst_rtc_init; 301*05454c26SKuppuswamy Sathyanarayanan x86_platform.get_nmi_reason = mrst_get_nmi_reason; 302*05454c26SKuppuswamy Sathyanarayanan 303*05454c26SKuppuswamy Sathyanarayanan x86_init.pci.init = pci_mrst_init; 304*05454c26SKuppuswamy Sathyanarayanan x86_init.pci.fixup_irqs = x86_init_noop; 305*05454c26SKuppuswamy Sathyanarayanan 306*05454c26SKuppuswamy Sathyanarayanan legacy_pic = &null_legacy_pic; 307*05454c26SKuppuswamy Sathyanarayanan 308*05454c26SKuppuswamy Sathyanarayanan /* Moorestown specific power_off/restart method */ 309*05454c26SKuppuswamy Sathyanarayanan pm_power_off = mrst_power_off; 310*05454c26SKuppuswamy Sathyanarayanan machine_ops.emergency_restart = mrst_reboot; 311*05454c26SKuppuswamy Sathyanarayanan 312*05454c26SKuppuswamy Sathyanarayanan /* Avoid searching for BIOS MP tables */ 313*05454c26SKuppuswamy Sathyanarayanan x86_init.mpparse.find_smp_config = x86_init_noop; 314*05454c26SKuppuswamy Sathyanarayanan x86_init.mpparse.get_smp_config = x86_init_uint_noop; 315*05454c26SKuppuswamy Sathyanarayanan set_bit(MP_BUS_ISA, mp_bus_not_pci); 316*05454c26SKuppuswamy Sathyanarayanan } 317*05454c26SKuppuswamy Sathyanarayanan 318*05454c26SKuppuswamy Sathyanarayanan /* 319*05454c26SKuppuswamy Sathyanarayanan * if user does not want to use per CPU apb timer, just give it a lower rating 320*05454c26SKuppuswamy Sathyanarayanan * than local apic timer and skip the late per cpu timer init. 321*05454c26SKuppuswamy Sathyanarayanan */ 322*05454c26SKuppuswamy Sathyanarayanan static inline int __init setup_x86_mrst_timer(char *arg) 323*05454c26SKuppuswamy Sathyanarayanan { 324*05454c26SKuppuswamy Sathyanarayanan if (!arg) 325*05454c26SKuppuswamy Sathyanarayanan return -EINVAL; 326*05454c26SKuppuswamy Sathyanarayanan 327*05454c26SKuppuswamy Sathyanarayanan if (strcmp("apbt_only", arg) == 0) 328*05454c26SKuppuswamy Sathyanarayanan mrst_timer_options = MRST_TIMER_APBT_ONLY; 329*05454c26SKuppuswamy Sathyanarayanan else if (strcmp("lapic_and_apbt", arg) == 0) 330*05454c26SKuppuswamy Sathyanarayanan mrst_timer_options = MRST_TIMER_LAPIC_APBT; 331*05454c26SKuppuswamy Sathyanarayanan else { 332*05454c26SKuppuswamy Sathyanarayanan pr_warn("X86 MRST timer option %s not recognised" 333*05454c26SKuppuswamy Sathyanarayanan " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", 334*05454c26SKuppuswamy Sathyanarayanan arg); 335*05454c26SKuppuswamy Sathyanarayanan return -EINVAL; 336*05454c26SKuppuswamy Sathyanarayanan } 337*05454c26SKuppuswamy Sathyanarayanan return 0; 338*05454c26SKuppuswamy Sathyanarayanan } 339*05454c26SKuppuswamy Sathyanarayanan __setup("x86_mrst_timer=", setup_x86_mrst_timer); 340*05454c26SKuppuswamy Sathyanarayanan 341*05454c26SKuppuswamy Sathyanarayanan /* 342*05454c26SKuppuswamy Sathyanarayanan * Parsing GPIO table first, since the DEVS table will need this table 343*05454c26SKuppuswamy Sathyanarayanan * to map the pin name to the actual pin. 344*05454c26SKuppuswamy Sathyanarayanan */ 345*05454c26SKuppuswamy Sathyanarayanan static struct sfi_gpio_table_entry *gpio_table; 346*05454c26SKuppuswamy Sathyanarayanan static int gpio_num_entry; 347*05454c26SKuppuswamy Sathyanarayanan 348*05454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_gpio(struct sfi_table_header *table) 349*05454c26SKuppuswamy Sathyanarayanan { 350*05454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 351*05454c26SKuppuswamy Sathyanarayanan struct sfi_gpio_table_entry *pentry; 352*05454c26SKuppuswamy Sathyanarayanan int num, i; 353*05454c26SKuppuswamy Sathyanarayanan 354*05454c26SKuppuswamy Sathyanarayanan if (gpio_table) 355*05454c26SKuppuswamy Sathyanarayanan return 0; 356*05454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 357*05454c26SKuppuswamy Sathyanarayanan num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); 358*05454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_gpio_table_entry *)sb->pentry; 359*05454c26SKuppuswamy Sathyanarayanan 360*05454c26SKuppuswamy Sathyanarayanan gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL); 361*05454c26SKuppuswamy Sathyanarayanan if (!gpio_table) 362*05454c26SKuppuswamy Sathyanarayanan return -1; 363*05454c26SKuppuswamy Sathyanarayanan memcpy(gpio_table, pentry, num * sizeof(*pentry)); 364*05454c26SKuppuswamy Sathyanarayanan gpio_num_entry = num; 365*05454c26SKuppuswamy Sathyanarayanan 366*05454c26SKuppuswamy Sathyanarayanan pr_debug("GPIO pin info:\n"); 367*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++, pentry++) 368*05454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," 369*05454c26SKuppuswamy Sathyanarayanan " pin = %d\n", i, 370*05454c26SKuppuswamy Sathyanarayanan pentry->controller_name, 371*05454c26SKuppuswamy Sathyanarayanan pentry->pin_name, 372*05454c26SKuppuswamy Sathyanarayanan pentry->pin_no); 373*05454c26SKuppuswamy Sathyanarayanan return 0; 374*05454c26SKuppuswamy Sathyanarayanan } 375*05454c26SKuppuswamy Sathyanarayanan 376*05454c26SKuppuswamy Sathyanarayanan static int get_gpio_by_name(const char *name) 377*05454c26SKuppuswamy Sathyanarayanan { 378*05454c26SKuppuswamy Sathyanarayanan struct sfi_gpio_table_entry *pentry = gpio_table; 379*05454c26SKuppuswamy Sathyanarayanan int i; 380*05454c26SKuppuswamy Sathyanarayanan 381*05454c26SKuppuswamy Sathyanarayanan if (!pentry) 382*05454c26SKuppuswamy Sathyanarayanan return -1; 383*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < gpio_num_entry; i++, pentry++) { 384*05454c26SKuppuswamy Sathyanarayanan if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) 385*05454c26SKuppuswamy Sathyanarayanan return pentry->pin_no; 386*05454c26SKuppuswamy Sathyanarayanan } 387*05454c26SKuppuswamy Sathyanarayanan return -1; 388*05454c26SKuppuswamy Sathyanarayanan } 389*05454c26SKuppuswamy Sathyanarayanan 390*05454c26SKuppuswamy Sathyanarayanan /* 391*05454c26SKuppuswamy Sathyanarayanan * Here defines the array of devices platform data that IAFW would export 392*05454c26SKuppuswamy Sathyanarayanan * through SFI "DEVS" table, we use name and type to match the device and 393*05454c26SKuppuswamy Sathyanarayanan * its platform data. 394*05454c26SKuppuswamy Sathyanarayanan */ 395*05454c26SKuppuswamy Sathyanarayanan struct devs_id { 396*05454c26SKuppuswamy Sathyanarayanan char name[SFI_NAME_LEN + 1]; 397*05454c26SKuppuswamy Sathyanarayanan u8 type; 398*05454c26SKuppuswamy Sathyanarayanan u8 delay; 399*05454c26SKuppuswamy Sathyanarayanan void *(*get_platform_data)(void *info); 400*05454c26SKuppuswamy Sathyanarayanan }; 401*05454c26SKuppuswamy Sathyanarayanan 402*05454c26SKuppuswamy Sathyanarayanan /* the offset for the mapping of global gpio pin to irq */ 403*05454c26SKuppuswamy Sathyanarayanan #define MRST_IRQ_OFFSET 0x100 404*05454c26SKuppuswamy Sathyanarayanan 405*05454c26SKuppuswamy Sathyanarayanan static void __init *pmic_gpio_platform_data(void *info) 406*05454c26SKuppuswamy Sathyanarayanan { 407*05454c26SKuppuswamy Sathyanarayanan static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; 408*05454c26SKuppuswamy Sathyanarayanan int gpio_base = get_gpio_by_name("pmic_gpio_base"); 409*05454c26SKuppuswamy Sathyanarayanan 410*05454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 411*05454c26SKuppuswamy Sathyanarayanan gpio_base = 64; 412*05454c26SKuppuswamy Sathyanarayanan pmic_gpio_pdata.gpio_base = gpio_base; 413*05454c26SKuppuswamy Sathyanarayanan pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET; 414*05454c26SKuppuswamy Sathyanarayanan pmic_gpio_pdata.gpiointr = 0xffffeff8; 415*05454c26SKuppuswamy Sathyanarayanan 416*05454c26SKuppuswamy Sathyanarayanan return &pmic_gpio_pdata; 417*05454c26SKuppuswamy Sathyanarayanan } 418*05454c26SKuppuswamy Sathyanarayanan 419*05454c26SKuppuswamy Sathyanarayanan static void __init *max3111_platform_data(void *info) 420*05454c26SKuppuswamy Sathyanarayanan { 421*05454c26SKuppuswamy Sathyanarayanan struct spi_board_info *spi_info = info; 422*05454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("max3111_int"); 423*05454c26SKuppuswamy Sathyanarayanan 424*05454c26SKuppuswamy Sathyanarayanan spi_info->mode = SPI_MODE_0; 425*05454c26SKuppuswamy Sathyanarayanan if (intr == -1) 426*05454c26SKuppuswamy Sathyanarayanan return NULL; 427*05454c26SKuppuswamy Sathyanarayanan spi_info->irq = intr + MRST_IRQ_OFFSET; 428*05454c26SKuppuswamy Sathyanarayanan return NULL; 429*05454c26SKuppuswamy Sathyanarayanan } 430*05454c26SKuppuswamy Sathyanarayanan 431*05454c26SKuppuswamy Sathyanarayanan /* we have multiple max7315 on the board ... */ 432*05454c26SKuppuswamy Sathyanarayanan #define MAX7315_NUM 2 433*05454c26SKuppuswamy Sathyanarayanan static void __init *max7315_platform_data(void *info) 434*05454c26SKuppuswamy Sathyanarayanan { 435*05454c26SKuppuswamy Sathyanarayanan static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; 436*05454c26SKuppuswamy Sathyanarayanan static int nr; 437*05454c26SKuppuswamy Sathyanarayanan struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; 438*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 439*05454c26SKuppuswamy Sathyanarayanan int gpio_base, intr; 440*05454c26SKuppuswamy Sathyanarayanan char base_pin_name[SFI_NAME_LEN + 1]; 441*05454c26SKuppuswamy Sathyanarayanan char intr_pin_name[SFI_NAME_LEN + 1]; 442*05454c26SKuppuswamy Sathyanarayanan 443*05454c26SKuppuswamy Sathyanarayanan if (nr == MAX7315_NUM) { 444*05454c26SKuppuswamy Sathyanarayanan pr_err("too many max7315s, we only support %d\n", 445*05454c26SKuppuswamy Sathyanarayanan MAX7315_NUM); 446*05454c26SKuppuswamy Sathyanarayanan return NULL; 447*05454c26SKuppuswamy Sathyanarayanan } 448*05454c26SKuppuswamy Sathyanarayanan /* we have several max7315 on the board, we only need load several 449*05454c26SKuppuswamy Sathyanarayanan * instances of the same pca953x driver to cover them 450*05454c26SKuppuswamy Sathyanarayanan */ 451*05454c26SKuppuswamy Sathyanarayanan strcpy(i2c_info->type, "max7315"); 452*05454c26SKuppuswamy Sathyanarayanan if (nr++) { 453*05454c26SKuppuswamy Sathyanarayanan sprintf(base_pin_name, "max7315_%d_base", nr); 454*05454c26SKuppuswamy Sathyanarayanan sprintf(intr_pin_name, "max7315_%d_int", nr); 455*05454c26SKuppuswamy Sathyanarayanan } else { 456*05454c26SKuppuswamy Sathyanarayanan strcpy(base_pin_name, "max7315_base"); 457*05454c26SKuppuswamy Sathyanarayanan strcpy(intr_pin_name, "max7315_int"); 458*05454c26SKuppuswamy Sathyanarayanan } 459*05454c26SKuppuswamy Sathyanarayanan 460*05454c26SKuppuswamy Sathyanarayanan gpio_base = get_gpio_by_name(base_pin_name); 461*05454c26SKuppuswamy Sathyanarayanan intr = get_gpio_by_name(intr_pin_name); 462*05454c26SKuppuswamy Sathyanarayanan 463*05454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 464*05454c26SKuppuswamy Sathyanarayanan return NULL; 465*05454c26SKuppuswamy Sathyanarayanan max7315->gpio_base = gpio_base; 466*05454c26SKuppuswamy Sathyanarayanan if (intr != -1) { 467*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = intr + MRST_IRQ_OFFSET; 468*05454c26SKuppuswamy Sathyanarayanan max7315->irq_base = gpio_base + MRST_IRQ_OFFSET; 469*05454c26SKuppuswamy Sathyanarayanan } else { 470*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = -1; 471*05454c26SKuppuswamy Sathyanarayanan max7315->irq_base = -1; 472*05454c26SKuppuswamy Sathyanarayanan } 473*05454c26SKuppuswamy Sathyanarayanan return max7315; 474*05454c26SKuppuswamy Sathyanarayanan } 475*05454c26SKuppuswamy Sathyanarayanan 476*05454c26SKuppuswamy Sathyanarayanan static void *tca6416_platform_data(void *info) 477*05454c26SKuppuswamy Sathyanarayanan { 478*05454c26SKuppuswamy Sathyanarayanan static struct pca953x_platform_data tca6416; 479*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 480*05454c26SKuppuswamy Sathyanarayanan int gpio_base, intr; 481*05454c26SKuppuswamy Sathyanarayanan char base_pin_name[SFI_NAME_LEN + 1]; 482*05454c26SKuppuswamy Sathyanarayanan char intr_pin_name[SFI_NAME_LEN + 1]; 483*05454c26SKuppuswamy Sathyanarayanan 484*05454c26SKuppuswamy Sathyanarayanan strcpy(i2c_info->type, "tca6416"); 485*05454c26SKuppuswamy Sathyanarayanan strcpy(base_pin_name, "tca6416_base"); 486*05454c26SKuppuswamy Sathyanarayanan strcpy(intr_pin_name, "tca6416_int"); 487*05454c26SKuppuswamy Sathyanarayanan 488*05454c26SKuppuswamy Sathyanarayanan gpio_base = get_gpio_by_name(base_pin_name); 489*05454c26SKuppuswamy Sathyanarayanan intr = get_gpio_by_name(intr_pin_name); 490*05454c26SKuppuswamy Sathyanarayanan 491*05454c26SKuppuswamy Sathyanarayanan if (gpio_base == -1) 492*05454c26SKuppuswamy Sathyanarayanan return NULL; 493*05454c26SKuppuswamy Sathyanarayanan tca6416.gpio_base = gpio_base; 494*05454c26SKuppuswamy Sathyanarayanan if (intr != -1) { 495*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = intr + MRST_IRQ_OFFSET; 496*05454c26SKuppuswamy Sathyanarayanan tca6416.irq_base = gpio_base + MRST_IRQ_OFFSET; 497*05454c26SKuppuswamy Sathyanarayanan } else { 498*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = -1; 499*05454c26SKuppuswamy Sathyanarayanan tca6416.irq_base = -1; 500*05454c26SKuppuswamy Sathyanarayanan } 501*05454c26SKuppuswamy Sathyanarayanan return &tca6416; 502*05454c26SKuppuswamy Sathyanarayanan } 503*05454c26SKuppuswamy Sathyanarayanan 504*05454c26SKuppuswamy Sathyanarayanan static void *mpu3050_platform_data(void *info) 505*05454c26SKuppuswamy Sathyanarayanan { 506*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 507*05454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("mpu3050_int"); 508*05454c26SKuppuswamy Sathyanarayanan 509*05454c26SKuppuswamy Sathyanarayanan if (intr == -1) 510*05454c26SKuppuswamy Sathyanarayanan return NULL; 511*05454c26SKuppuswamy Sathyanarayanan 512*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = intr + MRST_IRQ_OFFSET; 513*05454c26SKuppuswamy Sathyanarayanan return NULL; 514*05454c26SKuppuswamy Sathyanarayanan } 515*05454c26SKuppuswamy Sathyanarayanan 516*05454c26SKuppuswamy Sathyanarayanan static void __init *emc1403_platform_data(void *info) 517*05454c26SKuppuswamy Sathyanarayanan { 518*05454c26SKuppuswamy Sathyanarayanan static short intr2nd_pdata; 519*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 520*05454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("thermal_int"); 521*05454c26SKuppuswamy Sathyanarayanan int intr2nd = get_gpio_by_name("thermal_alert"); 522*05454c26SKuppuswamy Sathyanarayanan 523*05454c26SKuppuswamy Sathyanarayanan if (intr == -1 || intr2nd == -1) 524*05454c26SKuppuswamy Sathyanarayanan return NULL; 525*05454c26SKuppuswamy Sathyanarayanan 526*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = intr + MRST_IRQ_OFFSET; 527*05454c26SKuppuswamy Sathyanarayanan intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; 528*05454c26SKuppuswamy Sathyanarayanan 529*05454c26SKuppuswamy Sathyanarayanan return &intr2nd_pdata; 530*05454c26SKuppuswamy Sathyanarayanan } 531*05454c26SKuppuswamy Sathyanarayanan 532*05454c26SKuppuswamy Sathyanarayanan static void __init *lis331dl_platform_data(void *info) 533*05454c26SKuppuswamy Sathyanarayanan { 534*05454c26SKuppuswamy Sathyanarayanan static short intr2nd_pdata; 535*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *i2c_info = info; 536*05454c26SKuppuswamy Sathyanarayanan int intr = get_gpio_by_name("accel_int"); 537*05454c26SKuppuswamy Sathyanarayanan int intr2nd = get_gpio_by_name("accel_2"); 538*05454c26SKuppuswamy Sathyanarayanan 539*05454c26SKuppuswamy Sathyanarayanan if (intr == -1 || intr2nd == -1) 540*05454c26SKuppuswamy Sathyanarayanan return NULL; 541*05454c26SKuppuswamy Sathyanarayanan 542*05454c26SKuppuswamy Sathyanarayanan i2c_info->irq = intr + MRST_IRQ_OFFSET; 543*05454c26SKuppuswamy Sathyanarayanan intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; 544*05454c26SKuppuswamy Sathyanarayanan 545*05454c26SKuppuswamy Sathyanarayanan return &intr2nd_pdata; 546*05454c26SKuppuswamy Sathyanarayanan } 547*05454c26SKuppuswamy Sathyanarayanan 548*05454c26SKuppuswamy Sathyanarayanan static void __init *no_platform_data(void *info) 549*05454c26SKuppuswamy Sathyanarayanan { 550*05454c26SKuppuswamy Sathyanarayanan return NULL; 551*05454c26SKuppuswamy Sathyanarayanan } 552*05454c26SKuppuswamy Sathyanarayanan 553*05454c26SKuppuswamy Sathyanarayanan static struct resource msic_resources[] = { 554*05454c26SKuppuswamy Sathyanarayanan { 555*05454c26SKuppuswamy Sathyanarayanan .start = INTEL_MSIC_IRQ_PHYS_BASE, 556*05454c26SKuppuswamy Sathyanarayanan .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1, 557*05454c26SKuppuswamy Sathyanarayanan .flags = IORESOURCE_MEM, 558*05454c26SKuppuswamy Sathyanarayanan }, 559*05454c26SKuppuswamy Sathyanarayanan }; 560*05454c26SKuppuswamy Sathyanarayanan 561*05454c26SKuppuswamy Sathyanarayanan static struct intel_msic_platform_data msic_pdata; 562*05454c26SKuppuswamy Sathyanarayanan 563*05454c26SKuppuswamy Sathyanarayanan static struct platform_device msic_device = { 564*05454c26SKuppuswamy Sathyanarayanan .name = "intel_msic", 565*05454c26SKuppuswamy Sathyanarayanan .id = -1, 566*05454c26SKuppuswamy Sathyanarayanan .dev = { 567*05454c26SKuppuswamy Sathyanarayanan .platform_data = &msic_pdata, 568*05454c26SKuppuswamy Sathyanarayanan }, 569*05454c26SKuppuswamy Sathyanarayanan .num_resources = ARRAY_SIZE(msic_resources), 570*05454c26SKuppuswamy Sathyanarayanan .resource = msic_resources, 571*05454c26SKuppuswamy Sathyanarayanan }; 572*05454c26SKuppuswamy Sathyanarayanan 573*05454c26SKuppuswamy Sathyanarayanan static inline bool mrst_has_msic(void) 574*05454c26SKuppuswamy Sathyanarayanan { 575*05454c26SKuppuswamy Sathyanarayanan return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL; 576*05454c26SKuppuswamy Sathyanarayanan } 577*05454c26SKuppuswamy Sathyanarayanan 578*05454c26SKuppuswamy Sathyanarayanan static int msic_scu_status_change(struct notifier_block *nb, 579*05454c26SKuppuswamy Sathyanarayanan unsigned long code, void *data) 580*05454c26SKuppuswamy Sathyanarayanan { 581*05454c26SKuppuswamy Sathyanarayanan if (code == SCU_DOWN) { 582*05454c26SKuppuswamy Sathyanarayanan platform_device_unregister(&msic_device); 583*05454c26SKuppuswamy Sathyanarayanan return 0; 584*05454c26SKuppuswamy Sathyanarayanan } 585*05454c26SKuppuswamy Sathyanarayanan 586*05454c26SKuppuswamy Sathyanarayanan return platform_device_register(&msic_device); 587*05454c26SKuppuswamy Sathyanarayanan } 588*05454c26SKuppuswamy Sathyanarayanan 589*05454c26SKuppuswamy Sathyanarayanan static int __init msic_init(void) 590*05454c26SKuppuswamy Sathyanarayanan { 591*05454c26SKuppuswamy Sathyanarayanan static struct notifier_block msic_scu_notifier = { 592*05454c26SKuppuswamy Sathyanarayanan .notifier_call = msic_scu_status_change, 593*05454c26SKuppuswamy Sathyanarayanan }; 594*05454c26SKuppuswamy Sathyanarayanan 595*05454c26SKuppuswamy Sathyanarayanan /* 596*05454c26SKuppuswamy Sathyanarayanan * We need to be sure that the SCU IPC is ready before MSIC device 597*05454c26SKuppuswamy Sathyanarayanan * can be registered. 598*05454c26SKuppuswamy Sathyanarayanan */ 599*05454c26SKuppuswamy Sathyanarayanan if (mrst_has_msic()) 600*05454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_add(&msic_scu_notifier); 601*05454c26SKuppuswamy Sathyanarayanan 602*05454c26SKuppuswamy Sathyanarayanan return 0; 603*05454c26SKuppuswamy Sathyanarayanan } 604*05454c26SKuppuswamy Sathyanarayanan arch_initcall(msic_init); 605*05454c26SKuppuswamy Sathyanarayanan 606*05454c26SKuppuswamy Sathyanarayanan /* 607*05454c26SKuppuswamy Sathyanarayanan * msic_generic_platform_data - sets generic platform data for the block 608*05454c26SKuppuswamy Sathyanarayanan * @info: pointer to the SFI device table entry for this block 609*05454c26SKuppuswamy Sathyanarayanan * @block: MSIC block 610*05454c26SKuppuswamy Sathyanarayanan * 611*05454c26SKuppuswamy Sathyanarayanan * Function sets IRQ number from the SFI table entry for given device to 612*05454c26SKuppuswamy Sathyanarayanan * the MSIC platform data. 613*05454c26SKuppuswamy Sathyanarayanan */ 614*05454c26SKuppuswamy Sathyanarayanan static void *msic_generic_platform_data(void *info, enum intel_msic_block block) 615*05454c26SKuppuswamy Sathyanarayanan { 616*05454c26SKuppuswamy Sathyanarayanan struct sfi_device_table_entry *entry = info; 617*05454c26SKuppuswamy Sathyanarayanan 618*05454c26SKuppuswamy Sathyanarayanan BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST); 619*05454c26SKuppuswamy Sathyanarayanan msic_pdata.irq[block] = entry->irq; 620*05454c26SKuppuswamy Sathyanarayanan 621*05454c26SKuppuswamy Sathyanarayanan return no_platform_data(info); 622*05454c26SKuppuswamy Sathyanarayanan } 623*05454c26SKuppuswamy Sathyanarayanan 624*05454c26SKuppuswamy Sathyanarayanan static void *msic_battery_platform_data(void *info) 625*05454c26SKuppuswamy Sathyanarayanan { 626*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY); 627*05454c26SKuppuswamy Sathyanarayanan } 628*05454c26SKuppuswamy Sathyanarayanan 629*05454c26SKuppuswamy Sathyanarayanan static void *msic_gpio_platform_data(void *info) 630*05454c26SKuppuswamy Sathyanarayanan { 631*05454c26SKuppuswamy Sathyanarayanan static struct intel_msic_gpio_pdata pdata; 632*05454c26SKuppuswamy Sathyanarayanan int gpio = get_gpio_by_name("msic_gpio_base"); 633*05454c26SKuppuswamy Sathyanarayanan 634*05454c26SKuppuswamy Sathyanarayanan if (gpio < 0) 635*05454c26SKuppuswamy Sathyanarayanan return NULL; 636*05454c26SKuppuswamy Sathyanarayanan 637*05454c26SKuppuswamy Sathyanarayanan pdata.gpio_base = gpio; 638*05454c26SKuppuswamy Sathyanarayanan msic_pdata.gpio = &pdata; 639*05454c26SKuppuswamy Sathyanarayanan 640*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO); 641*05454c26SKuppuswamy Sathyanarayanan } 642*05454c26SKuppuswamy Sathyanarayanan 643*05454c26SKuppuswamy Sathyanarayanan static void *msic_audio_platform_data(void *info) 644*05454c26SKuppuswamy Sathyanarayanan { 645*05454c26SKuppuswamy Sathyanarayanan struct platform_device *pdev; 646*05454c26SKuppuswamy Sathyanarayanan 647*05454c26SKuppuswamy Sathyanarayanan pdev = platform_device_register_simple("sst-platform", -1, NULL, 0); 648*05454c26SKuppuswamy Sathyanarayanan if (IS_ERR(pdev)) { 649*05454c26SKuppuswamy Sathyanarayanan pr_err("failed to create audio platform device\n"); 650*05454c26SKuppuswamy Sathyanarayanan return NULL; 651*05454c26SKuppuswamy Sathyanarayanan } 652*05454c26SKuppuswamy Sathyanarayanan 653*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO); 654*05454c26SKuppuswamy Sathyanarayanan } 655*05454c26SKuppuswamy Sathyanarayanan 656*05454c26SKuppuswamy Sathyanarayanan static void *msic_power_btn_platform_data(void *info) 657*05454c26SKuppuswamy Sathyanarayanan { 658*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN); 659*05454c26SKuppuswamy Sathyanarayanan } 660*05454c26SKuppuswamy Sathyanarayanan 661*05454c26SKuppuswamy Sathyanarayanan static void *msic_ocd_platform_data(void *info) 662*05454c26SKuppuswamy Sathyanarayanan { 663*05454c26SKuppuswamy Sathyanarayanan static struct intel_msic_ocd_pdata pdata; 664*05454c26SKuppuswamy Sathyanarayanan int gpio = get_gpio_by_name("ocd_gpio"); 665*05454c26SKuppuswamy Sathyanarayanan 666*05454c26SKuppuswamy Sathyanarayanan if (gpio < 0) 667*05454c26SKuppuswamy Sathyanarayanan return NULL; 668*05454c26SKuppuswamy Sathyanarayanan 669*05454c26SKuppuswamy Sathyanarayanan pdata.gpio = gpio; 670*05454c26SKuppuswamy Sathyanarayanan msic_pdata.ocd = &pdata; 671*05454c26SKuppuswamy Sathyanarayanan 672*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); 673*05454c26SKuppuswamy Sathyanarayanan } 674*05454c26SKuppuswamy Sathyanarayanan 675*05454c26SKuppuswamy Sathyanarayanan static void *msic_thermal_platform_data(void *info) 676*05454c26SKuppuswamy Sathyanarayanan { 677*05454c26SKuppuswamy Sathyanarayanan return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL); 678*05454c26SKuppuswamy Sathyanarayanan } 679*05454c26SKuppuswamy Sathyanarayanan 680*05454c26SKuppuswamy Sathyanarayanan /* tc35876x DSI-LVDS bridge chip and panel platform data */ 681*05454c26SKuppuswamy Sathyanarayanan static void *tc35876x_platform_data(void *data) 682*05454c26SKuppuswamy Sathyanarayanan { 683*05454c26SKuppuswamy Sathyanarayanan static struct tc35876x_platform_data pdata; 684*05454c26SKuppuswamy Sathyanarayanan 685*05454c26SKuppuswamy Sathyanarayanan /* gpio pins set to -1 will not be used by the driver */ 686*05454c26SKuppuswamy Sathyanarayanan pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); 687*05454c26SKuppuswamy Sathyanarayanan pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); 688*05454c26SKuppuswamy Sathyanarayanan pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); 689*05454c26SKuppuswamy Sathyanarayanan 690*05454c26SKuppuswamy Sathyanarayanan return &pdata; 691*05454c26SKuppuswamy Sathyanarayanan } 692*05454c26SKuppuswamy Sathyanarayanan 693*05454c26SKuppuswamy Sathyanarayanan static const struct devs_id __initconst device_ids[] = { 694*05454c26SKuppuswamy Sathyanarayanan {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, 695*05454c26SKuppuswamy Sathyanarayanan {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, 696*05454c26SKuppuswamy Sathyanarayanan {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data}, 697*05454c26SKuppuswamy Sathyanarayanan {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, 698*05454c26SKuppuswamy Sathyanarayanan {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, 699*05454c26SKuppuswamy Sathyanarayanan {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, 700*05454c26SKuppuswamy Sathyanarayanan {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data}, 701*05454c26SKuppuswamy Sathyanarayanan {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, 702*05454c26SKuppuswamy Sathyanarayanan {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, 703*05454c26SKuppuswamy Sathyanarayanan {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, 704*05454c26SKuppuswamy Sathyanarayanan {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, 705*05454c26SKuppuswamy Sathyanarayanan {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, 706*05454c26SKuppuswamy Sathyanarayanan 707*05454c26SKuppuswamy Sathyanarayanan /* MSIC subdevices */ 708*05454c26SKuppuswamy Sathyanarayanan {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, 709*05454c26SKuppuswamy Sathyanarayanan {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data}, 710*05454c26SKuppuswamy Sathyanarayanan {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, 711*05454c26SKuppuswamy Sathyanarayanan {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, 712*05454c26SKuppuswamy Sathyanarayanan {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, 713*05454c26SKuppuswamy Sathyanarayanan {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data}, 714*05454c26SKuppuswamy Sathyanarayanan 715*05454c26SKuppuswamy Sathyanarayanan {}, 716*05454c26SKuppuswamy Sathyanarayanan }; 717*05454c26SKuppuswamy Sathyanarayanan 718*05454c26SKuppuswamy Sathyanarayanan #define MAX_IPCDEVS 24 719*05454c26SKuppuswamy Sathyanarayanan static struct platform_device *ipc_devs[MAX_IPCDEVS]; 720*05454c26SKuppuswamy Sathyanarayanan static int ipc_next_dev; 721*05454c26SKuppuswamy Sathyanarayanan 722*05454c26SKuppuswamy Sathyanarayanan #define MAX_SCU_SPI 24 723*05454c26SKuppuswamy Sathyanarayanan static struct spi_board_info *spi_devs[MAX_SCU_SPI]; 724*05454c26SKuppuswamy Sathyanarayanan static int spi_next_dev; 725*05454c26SKuppuswamy Sathyanarayanan 726*05454c26SKuppuswamy Sathyanarayanan #define MAX_SCU_I2C 24 727*05454c26SKuppuswamy Sathyanarayanan static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; 728*05454c26SKuppuswamy Sathyanarayanan static int i2c_bus[MAX_SCU_I2C]; 729*05454c26SKuppuswamy Sathyanarayanan static int i2c_next_dev; 730*05454c26SKuppuswamy Sathyanarayanan 731*05454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_device_register(struct platform_device *pdev) 732*05454c26SKuppuswamy Sathyanarayanan { 733*05454c26SKuppuswamy Sathyanarayanan if (ipc_next_dev == MAX_IPCDEVS) 734*05454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU IPC devices"); 735*05454c26SKuppuswamy Sathyanarayanan else 736*05454c26SKuppuswamy Sathyanarayanan ipc_devs[ipc_next_dev++] = pdev; 737*05454c26SKuppuswamy Sathyanarayanan } 738*05454c26SKuppuswamy Sathyanarayanan 739*05454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) 740*05454c26SKuppuswamy Sathyanarayanan { 741*05454c26SKuppuswamy Sathyanarayanan struct spi_board_info *new_dev; 742*05454c26SKuppuswamy Sathyanarayanan 743*05454c26SKuppuswamy Sathyanarayanan if (spi_next_dev == MAX_SCU_SPI) { 744*05454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU SPI devices"); 745*05454c26SKuppuswamy Sathyanarayanan return; 746*05454c26SKuppuswamy Sathyanarayanan } 747*05454c26SKuppuswamy Sathyanarayanan 748*05454c26SKuppuswamy Sathyanarayanan new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); 749*05454c26SKuppuswamy Sathyanarayanan if (!new_dev) { 750*05454c26SKuppuswamy Sathyanarayanan pr_err("failed to alloc mem for delayed spi dev %s\n", 751*05454c26SKuppuswamy Sathyanarayanan sdev->modalias); 752*05454c26SKuppuswamy Sathyanarayanan return; 753*05454c26SKuppuswamy Sathyanarayanan } 754*05454c26SKuppuswamy Sathyanarayanan memcpy(new_dev, sdev, sizeof(*sdev)); 755*05454c26SKuppuswamy Sathyanarayanan 756*05454c26SKuppuswamy Sathyanarayanan spi_devs[spi_next_dev++] = new_dev; 757*05454c26SKuppuswamy Sathyanarayanan } 758*05454c26SKuppuswamy Sathyanarayanan 759*05454c26SKuppuswamy Sathyanarayanan static void __init intel_scu_i2c_device_register(int bus, 760*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *idev) 761*05454c26SKuppuswamy Sathyanarayanan { 762*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info *new_dev; 763*05454c26SKuppuswamy Sathyanarayanan 764*05454c26SKuppuswamy Sathyanarayanan if (i2c_next_dev == MAX_SCU_I2C) { 765*05454c26SKuppuswamy Sathyanarayanan pr_err("too many SCU I2C devices"); 766*05454c26SKuppuswamy Sathyanarayanan return; 767*05454c26SKuppuswamy Sathyanarayanan } 768*05454c26SKuppuswamy Sathyanarayanan 769*05454c26SKuppuswamy Sathyanarayanan new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); 770*05454c26SKuppuswamy Sathyanarayanan if (!new_dev) { 771*05454c26SKuppuswamy Sathyanarayanan pr_err("failed to alloc mem for delayed i2c dev %s\n", 772*05454c26SKuppuswamy Sathyanarayanan idev->type); 773*05454c26SKuppuswamy Sathyanarayanan return; 774*05454c26SKuppuswamy Sathyanarayanan } 775*05454c26SKuppuswamy Sathyanarayanan memcpy(new_dev, idev, sizeof(*idev)); 776*05454c26SKuppuswamy Sathyanarayanan 777*05454c26SKuppuswamy Sathyanarayanan i2c_bus[i2c_next_dev] = bus; 778*05454c26SKuppuswamy Sathyanarayanan i2c_devs[i2c_next_dev++] = new_dev; 779*05454c26SKuppuswamy Sathyanarayanan } 780*05454c26SKuppuswamy Sathyanarayanan 781*05454c26SKuppuswamy Sathyanarayanan BLOCKING_NOTIFIER_HEAD(intel_scu_notifier); 782*05454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_notifier); 783*05454c26SKuppuswamy Sathyanarayanan 784*05454c26SKuppuswamy Sathyanarayanan /* Called by IPC driver */ 785*05454c26SKuppuswamy Sathyanarayanan void intel_scu_devices_create(void) 786*05454c26SKuppuswamy Sathyanarayanan { 787*05454c26SKuppuswamy Sathyanarayanan int i; 788*05454c26SKuppuswamy Sathyanarayanan 789*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < ipc_next_dev; i++) 790*05454c26SKuppuswamy Sathyanarayanan platform_device_add(ipc_devs[i]); 791*05454c26SKuppuswamy Sathyanarayanan 792*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < spi_next_dev; i++) 793*05454c26SKuppuswamy Sathyanarayanan spi_register_board_info(spi_devs[i], 1); 794*05454c26SKuppuswamy Sathyanarayanan 795*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < i2c_next_dev; i++) { 796*05454c26SKuppuswamy Sathyanarayanan struct i2c_adapter *adapter; 797*05454c26SKuppuswamy Sathyanarayanan struct i2c_client *client; 798*05454c26SKuppuswamy Sathyanarayanan 799*05454c26SKuppuswamy Sathyanarayanan adapter = i2c_get_adapter(i2c_bus[i]); 800*05454c26SKuppuswamy Sathyanarayanan if (adapter) { 801*05454c26SKuppuswamy Sathyanarayanan client = i2c_new_device(adapter, i2c_devs[i]); 802*05454c26SKuppuswamy Sathyanarayanan if (!client) 803*05454c26SKuppuswamy Sathyanarayanan pr_err("can't create i2c device %s\n", 804*05454c26SKuppuswamy Sathyanarayanan i2c_devs[i]->type); 805*05454c26SKuppuswamy Sathyanarayanan } else 806*05454c26SKuppuswamy Sathyanarayanan i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); 807*05454c26SKuppuswamy Sathyanarayanan } 808*05454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_post(SCU_AVAILABLE, NULL); 809*05454c26SKuppuswamy Sathyanarayanan } 810*05454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_devices_create); 811*05454c26SKuppuswamy Sathyanarayanan 812*05454c26SKuppuswamy Sathyanarayanan /* Called by IPC driver */ 813*05454c26SKuppuswamy Sathyanarayanan void intel_scu_devices_destroy(void) 814*05454c26SKuppuswamy Sathyanarayanan { 815*05454c26SKuppuswamy Sathyanarayanan int i; 816*05454c26SKuppuswamy Sathyanarayanan 817*05454c26SKuppuswamy Sathyanarayanan intel_scu_notifier_post(SCU_DOWN, NULL); 818*05454c26SKuppuswamy Sathyanarayanan 819*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < ipc_next_dev; i++) 820*05454c26SKuppuswamy Sathyanarayanan platform_device_del(ipc_devs[i]); 821*05454c26SKuppuswamy Sathyanarayanan } 822*05454c26SKuppuswamy Sathyanarayanan EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); 823*05454c26SKuppuswamy Sathyanarayanan 824*05454c26SKuppuswamy Sathyanarayanan static void __init install_irq_resource(struct platform_device *pdev, int irq) 825*05454c26SKuppuswamy Sathyanarayanan { 826*05454c26SKuppuswamy Sathyanarayanan /* Single threaded */ 827*05454c26SKuppuswamy Sathyanarayanan static struct resource __initdata res = { 828*05454c26SKuppuswamy Sathyanarayanan .name = "IRQ", 829*05454c26SKuppuswamy Sathyanarayanan .flags = IORESOURCE_IRQ, 830*05454c26SKuppuswamy Sathyanarayanan }; 831*05454c26SKuppuswamy Sathyanarayanan res.start = irq; 832*05454c26SKuppuswamy Sathyanarayanan platform_device_add_resources(pdev, &res, 1); 833*05454c26SKuppuswamy Sathyanarayanan } 834*05454c26SKuppuswamy Sathyanarayanan 835*05454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry) 836*05454c26SKuppuswamy Sathyanarayanan { 837*05454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 838*05454c26SKuppuswamy Sathyanarayanan struct platform_device *pdev; 839*05454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 840*05454c26SKuppuswamy Sathyanarayanan 841*05454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 842*05454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_IPC && 843*05454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, entry->name, SFI_NAME_LEN)) { 844*05454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(entry); 845*05454c26SKuppuswamy Sathyanarayanan break; 846*05454c26SKuppuswamy Sathyanarayanan } 847*05454c26SKuppuswamy Sathyanarayanan dev++; 848*05454c26SKuppuswamy Sathyanarayanan } 849*05454c26SKuppuswamy Sathyanarayanan 850*05454c26SKuppuswamy Sathyanarayanan /* 851*05454c26SKuppuswamy Sathyanarayanan * On Medfield the platform device creation is handled by the MSIC 852*05454c26SKuppuswamy Sathyanarayanan * MFD driver so we don't need to do it here. 853*05454c26SKuppuswamy Sathyanarayanan */ 854*05454c26SKuppuswamy Sathyanarayanan if (mrst_has_msic()) 855*05454c26SKuppuswamy Sathyanarayanan return; 856*05454c26SKuppuswamy Sathyanarayanan 857*05454c26SKuppuswamy Sathyanarayanan pdev = platform_device_alloc(entry->name, 0); 858*05454c26SKuppuswamy Sathyanarayanan if (pdev == NULL) { 859*05454c26SKuppuswamy Sathyanarayanan pr_err("out of memory for SFI platform device '%s'.\n", 860*05454c26SKuppuswamy Sathyanarayanan entry->name); 861*05454c26SKuppuswamy Sathyanarayanan return; 862*05454c26SKuppuswamy Sathyanarayanan } 863*05454c26SKuppuswamy Sathyanarayanan install_irq_resource(pdev, entry->irq); 864*05454c26SKuppuswamy Sathyanarayanan 865*05454c26SKuppuswamy Sathyanarayanan pdev->dev.platform_data = pdata; 866*05454c26SKuppuswamy Sathyanarayanan intel_scu_device_register(pdev); 867*05454c26SKuppuswamy Sathyanarayanan } 868*05454c26SKuppuswamy Sathyanarayanan 869*05454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) 870*05454c26SKuppuswamy Sathyanarayanan { 871*05454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 872*05454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 873*05454c26SKuppuswamy Sathyanarayanan 874*05454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 875*05454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_SPI && 876*05454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, spi_info->modalias, 877*05454c26SKuppuswamy Sathyanarayanan SFI_NAME_LEN)) { 878*05454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(spi_info); 879*05454c26SKuppuswamy Sathyanarayanan break; 880*05454c26SKuppuswamy Sathyanarayanan } 881*05454c26SKuppuswamy Sathyanarayanan dev++; 882*05454c26SKuppuswamy Sathyanarayanan } 883*05454c26SKuppuswamy Sathyanarayanan spi_info->platform_data = pdata; 884*05454c26SKuppuswamy Sathyanarayanan if (dev->delay) 885*05454c26SKuppuswamy Sathyanarayanan intel_scu_spi_device_register(spi_info); 886*05454c26SKuppuswamy Sathyanarayanan else 887*05454c26SKuppuswamy Sathyanarayanan spi_register_board_info(spi_info, 1); 888*05454c26SKuppuswamy Sathyanarayanan } 889*05454c26SKuppuswamy Sathyanarayanan 890*05454c26SKuppuswamy Sathyanarayanan static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) 891*05454c26SKuppuswamy Sathyanarayanan { 892*05454c26SKuppuswamy Sathyanarayanan const struct devs_id *dev = device_ids; 893*05454c26SKuppuswamy Sathyanarayanan void *pdata = NULL; 894*05454c26SKuppuswamy Sathyanarayanan 895*05454c26SKuppuswamy Sathyanarayanan while (dev->name[0]) { 896*05454c26SKuppuswamy Sathyanarayanan if (dev->type == SFI_DEV_TYPE_I2C && 897*05454c26SKuppuswamy Sathyanarayanan !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { 898*05454c26SKuppuswamy Sathyanarayanan pdata = dev->get_platform_data(i2c_info); 899*05454c26SKuppuswamy Sathyanarayanan break; 900*05454c26SKuppuswamy Sathyanarayanan } 901*05454c26SKuppuswamy Sathyanarayanan dev++; 902*05454c26SKuppuswamy Sathyanarayanan } 903*05454c26SKuppuswamy Sathyanarayanan i2c_info->platform_data = pdata; 904*05454c26SKuppuswamy Sathyanarayanan 905*05454c26SKuppuswamy Sathyanarayanan if (dev->delay) 906*05454c26SKuppuswamy Sathyanarayanan intel_scu_i2c_device_register(bus, i2c_info); 907*05454c26SKuppuswamy Sathyanarayanan else 908*05454c26SKuppuswamy Sathyanarayanan i2c_register_board_info(bus, i2c_info, 1); 909*05454c26SKuppuswamy Sathyanarayanan } 910*05454c26SKuppuswamy Sathyanarayanan 911*05454c26SKuppuswamy Sathyanarayanan 912*05454c26SKuppuswamy Sathyanarayanan static int __init sfi_parse_devs(struct sfi_table_header *table) 913*05454c26SKuppuswamy Sathyanarayanan { 914*05454c26SKuppuswamy Sathyanarayanan struct sfi_table_simple *sb; 915*05454c26SKuppuswamy Sathyanarayanan struct sfi_device_table_entry *pentry; 916*05454c26SKuppuswamy Sathyanarayanan struct spi_board_info spi_info; 917*05454c26SKuppuswamy Sathyanarayanan struct i2c_board_info i2c_info; 918*05454c26SKuppuswamy Sathyanarayanan int num, i, bus; 919*05454c26SKuppuswamy Sathyanarayanan int ioapic; 920*05454c26SKuppuswamy Sathyanarayanan struct io_apic_irq_attr irq_attr; 921*05454c26SKuppuswamy Sathyanarayanan 922*05454c26SKuppuswamy Sathyanarayanan sb = (struct sfi_table_simple *)table; 923*05454c26SKuppuswamy Sathyanarayanan num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); 924*05454c26SKuppuswamy Sathyanarayanan pentry = (struct sfi_device_table_entry *)sb->pentry; 925*05454c26SKuppuswamy Sathyanarayanan 926*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++, pentry++) { 927*05454c26SKuppuswamy Sathyanarayanan int irq = pentry->irq; 928*05454c26SKuppuswamy Sathyanarayanan 929*05454c26SKuppuswamy Sathyanarayanan if (irq != (u8)0xff) { /* native RTE case */ 930*05454c26SKuppuswamy Sathyanarayanan /* these SPI2 devices are not exposed to system as PCI 931*05454c26SKuppuswamy Sathyanarayanan * devices, but they have separate RTE entry in IOAPIC 932*05454c26SKuppuswamy Sathyanarayanan * so we have to enable them one by one here 933*05454c26SKuppuswamy Sathyanarayanan */ 934*05454c26SKuppuswamy Sathyanarayanan ioapic = mp_find_ioapic(irq); 935*05454c26SKuppuswamy Sathyanarayanan irq_attr.ioapic = ioapic; 936*05454c26SKuppuswamy Sathyanarayanan irq_attr.ioapic_pin = irq; 937*05454c26SKuppuswamy Sathyanarayanan irq_attr.trigger = 1; 938*05454c26SKuppuswamy Sathyanarayanan irq_attr.polarity = 1; 939*05454c26SKuppuswamy Sathyanarayanan io_apic_set_pci_routing(NULL, irq, &irq_attr); 940*05454c26SKuppuswamy Sathyanarayanan } else 941*05454c26SKuppuswamy Sathyanarayanan irq = 0; /* No irq */ 942*05454c26SKuppuswamy Sathyanarayanan 943*05454c26SKuppuswamy Sathyanarayanan switch (pentry->type) { 944*05454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_IPC: 945*05454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: IPC bus, name = %16.16s, " 946*05454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x\n", i, pentry->name, pentry->irq); 947*05454c26SKuppuswamy Sathyanarayanan sfi_handle_ipc_dev(pentry); 948*05454c26SKuppuswamy Sathyanarayanan break; 949*05454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_SPI: 950*05454c26SKuppuswamy Sathyanarayanan memset(&spi_info, 0, sizeof(spi_info)); 951*05454c26SKuppuswamy Sathyanarayanan strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); 952*05454c26SKuppuswamy Sathyanarayanan spi_info.irq = irq; 953*05454c26SKuppuswamy Sathyanarayanan spi_info.bus_num = pentry->host_num; 954*05454c26SKuppuswamy Sathyanarayanan spi_info.chip_select = pentry->addr; 955*05454c26SKuppuswamy Sathyanarayanan spi_info.max_speed_hz = pentry->max_freq; 956*05454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " 957*05454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x, max_freq = %d, cs = %d\n", i, 958*05454c26SKuppuswamy Sathyanarayanan spi_info.bus_num, 959*05454c26SKuppuswamy Sathyanarayanan spi_info.modalias, 960*05454c26SKuppuswamy Sathyanarayanan spi_info.irq, 961*05454c26SKuppuswamy Sathyanarayanan spi_info.max_speed_hz, 962*05454c26SKuppuswamy Sathyanarayanan spi_info.chip_select); 963*05454c26SKuppuswamy Sathyanarayanan sfi_handle_spi_dev(&spi_info); 964*05454c26SKuppuswamy Sathyanarayanan break; 965*05454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_I2C: 966*05454c26SKuppuswamy Sathyanarayanan memset(&i2c_info, 0, sizeof(i2c_info)); 967*05454c26SKuppuswamy Sathyanarayanan bus = pentry->host_num; 968*05454c26SKuppuswamy Sathyanarayanan strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); 969*05454c26SKuppuswamy Sathyanarayanan i2c_info.irq = irq; 970*05454c26SKuppuswamy Sathyanarayanan i2c_info.addr = pentry->addr; 971*05454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " 972*05454c26SKuppuswamy Sathyanarayanan "irq = 0x%2x, addr = 0x%x\n", i, bus, 973*05454c26SKuppuswamy Sathyanarayanan i2c_info.type, 974*05454c26SKuppuswamy Sathyanarayanan i2c_info.irq, 975*05454c26SKuppuswamy Sathyanarayanan i2c_info.addr); 976*05454c26SKuppuswamy Sathyanarayanan sfi_handle_i2c_dev(bus, &i2c_info); 977*05454c26SKuppuswamy Sathyanarayanan break; 978*05454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_UART: 979*05454c26SKuppuswamy Sathyanarayanan case SFI_DEV_TYPE_HSI: 980*05454c26SKuppuswamy Sathyanarayanan default: 981*05454c26SKuppuswamy Sathyanarayanan ; 982*05454c26SKuppuswamy Sathyanarayanan } 983*05454c26SKuppuswamy Sathyanarayanan } 984*05454c26SKuppuswamy Sathyanarayanan return 0; 985*05454c26SKuppuswamy Sathyanarayanan } 986*05454c26SKuppuswamy Sathyanarayanan 987*05454c26SKuppuswamy Sathyanarayanan static int __init mrst_platform_init(void) 988*05454c26SKuppuswamy Sathyanarayanan { 989*05454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); 990*05454c26SKuppuswamy Sathyanarayanan sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); 991*05454c26SKuppuswamy Sathyanarayanan return 0; 992*05454c26SKuppuswamy Sathyanarayanan } 993*05454c26SKuppuswamy Sathyanarayanan arch_initcall(mrst_platform_init); 994*05454c26SKuppuswamy Sathyanarayanan 995*05454c26SKuppuswamy Sathyanarayanan /* 996*05454c26SKuppuswamy Sathyanarayanan * we will search these buttons in SFI GPIO table (by name) 997*05454c26SKuppuswamy Sathyanarayanan * and register them dynamically. Please add all possible 998*05454c26SKuppuswamy Sathyanarayanan * buttons here, we will shrink them if no GPIO found. 999*05454c26SKuppuswamy Sathyanarayanan */ 1000*05454c26SKuppuswamy Sathyanarayanan static struct gpio_keys_button gpio_button[] = { 1001*05454c26SKuppuswamy Sathyanarayanan {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, 1002*05454c26SKuppuswamy Sathyanarayanan {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, 1003*05454c26SKuppuswamy Sathyanarayanan {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, 1004*05454c26SKuppuswamy Sathyanarayanan {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, 1005*05454c26SKuppuswamy Sathyanarayanan {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, 1006*05454c26SKuppuswamy Sathyanarayanan {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, 1007*05454c26SKuppuswamy Sathyanarayanan {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, 1008*05454c26SKuppuswamy Sathyanarayanan {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, 1009*05454c26SKuppuswamy Sathyanarayanan {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, 1010*05454c26SKuppuswamy Sathyanarayanan {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, 1011*05454c26SKuppuswamy Sathyanarayanan }; 1012*05454c26SKuppuswamy Sathyanarayanan 1013*05454c26SKuppuswamy Sathyanarayanan static struct gpio_keys_platform_data mrst_gpio_keys = { 1014*05454c26SKuppuswamy Sathyanarayanan .buttons = gpio_button, 1015*05454c26SKuppuswamy Sathyanarayanan .rep = 1, 1016*05454c26SKuppuswamy Sathyanarayanan .nbuttons = -1, /* will fill it after search */ 1017*05454c26SKuppuswamy Sathyanarayanan }; 1018*05454c26SKuppuswamy Sathyanarayanan 1019*05454c26SKuppuswamy Sathyanarayanan static struct platform_device pb_device = { 1020*05454c26SKuppuswamy Sathyanarayanan .name = "gpio-keys", 1021*05454c26SKuppuswamy Sathyanarayanan .id = -1, 1022*05454c26SKuppuswamy Sathyanarayanan .dev = { 1023*05454c26SKuppuswamy Sathyanarayanan .platform_data = &mrst_gpio_keys, 1024*05454c26SKuppuswamy Sathyanarayanan }, 1025*05454c26SKuppuswamy Sathyanarayanan }; 1026*05454c26SKuppuswamy Sathyanarayanan 1027*05454c26SKuppuswamy Sathyanarayanan /* 1028*05454c26SKuppuswamy Sathyanarayanan * Shrink the non-existent buttons, register the gpio button 1029*05454c26SKuppuswamy Sathyanarayanan * device if there is some 1030*05454c26SKuppuswamy Sathyanarayanan */ 1031*05454c26SKuppuswamy Sathyanarayanan static int __init pb_keys_init(void) 1032*05454c26SKuppuswamy Sathyanarayanan { 1033*05454c26SKuppuswamy Sathyanarayanan struct gpio_keys_button *gb = gpio_button; 1034*05454c26SKuppuswamy Sathyanarayanan int i, num, good = 0; 1035*05454c26SKuppuswamy Sathyanarayanan 1036*05454c26SKuppuswamy Sathyanarayanan num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); 1037*05454c26SKuppuswamy Sathyanarayanan for (i = 0; i < num; i++) { 1038*05454c26SKuppuswamy Sathyanarayanan gb[i].gpio = get_gpio_by_name(gb[i].desc); 1039*05454c26SKuppuswamy Sathyanarayanan pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, 1040*05454c26SKuppuswamy Sathyanarayanan gb[i].gpio); 1041*05454c26SKuppuswamy Sathyanarayanan if (gb[i].gpio == -1) 1042*05454c26SKuppuswamy Sathyanarayanan continue; 1043*05454c26SKuppuswamy Sathyanarayanan 1044*05454c26SKuppuswamy Sathyanarayanan if (i != good) 1045*05454c26SKuppuswamy Sathyanarayanan gb[good] = gb[i]; 1046*05454c26SKuppuswamy Sathyanarayanan good++; 1047*05454c26SKuppuswamy Sathyanarayanan } 1048*05454c26SKuppuswamy Sathyanarayanan 1049*05454c26SKuppuswamy Sathyanarayanan if (good) { 1050*05454c26SKuppuswamy Sathyanarayanan mrst_gpio_keys.nbuttons = good; 1051*05454c26SKuppuswamy Sathyanarayanan return platform_device_register(&pb_device); 1052*05454c26SKuppuswamy Sathyanarayanan } 1053*05454c26SKuppuswamy Sathyanarayanan return 0; 1054*05454c26SKuppuswamy Sathyanarayanan } 1055*05454c26SKuppuswamy Sathyanarayanan late_initcall(pb_keys_init); 1056