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