1 /* 2 * System Specific setup for Soekris net5501 3 * At the moment this means setup of GPIO control of LEDs and buttons 4 * on net5501 boards. 5 * 6 * 7 * Copyright (C) 2008-2009 Tower Technologies 8 * Written by Alessandro Zummo <a.zummo@towertech.it> 9 * 10 * Copyright (C) 2008 Constantin Baranov <const@mimas.ru> 11 * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com> 12 * and Philip Prindeville <philipp@redfish-solutions.com> 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License version 2 16 * as published by the Free Software Foundation. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/init.h> 21 #include <linux/io.h> 22 #include <linux/string.h> 23 #include <linux/leds.h> 24 #include <linux/platform_device.h> 25 #include <linux/gpio.h> 26 #include <linux/input.h> 27 #include <linux/gpio_keys.h> 28 29 #include <asm/geode.h> 30 31 #define BIOS_REGION_BASE 0xffff0000 32 #define BIOS_REGION_SIZE 0x00010000 33 34 static struct gpio_keys_button net5501_gpio_buttons[] = { 35 { 36 .code = KEY_RESTART, 37 .gpio = 24, 38 .active_low = 1, 39 .desc = "Reset button", 40 .type = EV_KEY, 41 .wakeup = 0, 42 .debounce_interval = 100, 43 .can_disable = 0, 44 } 45 }; 46 static struct gpio_keys_platform_data net5501_buttons_data = { 47 .buttons = net5501_gpio_buttons, 48 .nbuttons = ARRAY_SIZE(net5501_gpio_buttons), 49 .poll_interval = 20, 50 }; 51 52 static struct platform_device net5501_buttons_dev = { 53 .name = "gpio-keys-polled", 54 .id = 1, 55 .dev = { 56 .platform_data = &net5501_buttons_data, 57 } 58 }; 59 60 static struct gpio_led net5501_leds[] = { 61 { 62 .name = "net5501:1", 63 .gpio = 6, 64 .default_trigger = "default-on", 65 .active_low = 0, 66 }, 67 }; 68 69 static struct gpio_led_platform_data net5501_leds_data = { 70 .num_leds = ARRAY_SIZE(net5501_leds), 71 .leds = net5501_leds, 72 }; 73 74 static struct platform_device net5501_leds_dev = { 75 .name = "leds-gpio", 76 .id = -1, 77 .dev.platform_data = &net5501_leds_data, 78 }; 79 80 static struct platform_device *net5501_devs[] __initdata = { 81 &net5501_buttons_dev, 82 &net5501_leds_dev, 83 }; 84 85 static void __init register_net5501(void) 86 { 87 /* Setup LED control through leds-gpio driver */ 88 platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs)); 89 } 90 91 struct net5501_board { 92 u16 offset; 93 u16 len; 94 char *sig; 95 }; 96 97 static struct net5501_board __initdata boards[] = { 98 { 0xb7b, 7, "net5501" }, /* net5501 v1.33/1.33c */ 99 { 0xb1f, 7, "net5501" }, /* net5501 v1.32i */ 100 }; 101 102 static bool __init net5501_present(void) 103 { 104 int i; 105 unsigned char *rombase, *bios; 106 bool found = false; 107 108 rombase = ioremap(BIOS_REGION_BASE, BIOS_REGION_SIZE - 1); 109 if (!rombase) { 110 printk(KERN_ERR "%s: failed to get rombase\n", KBUILD_MODNAME); 111 return found; 112 } 113 114 bios = rombase + 0x20; /* null terminated */ 115 116 if (memcmp(bios, "comBIOS", 7)) 117 goto unmap; 118 119 for (i = 0; i < ARRAY_SIZE(boards); i++) { 120 unsigned char *model = rombase + boards[i].offset; 121 122 if (!memcmp(model, boards[i].sig, boards[i].len)) { 123 printk(KERN_INFO "%s: system is recognized as \"%s\"\n", 124 KBUILD_MODNAME, model); 125 126 found = true; 127 break; 128 } 129 } 130 131 unmap: 132 iounmap(rombase); 133 return found; 134 } 135 136 static int __init net5501_init(void) 137 { 138 if (!is_geode()) 139 return 0; 140 141 if (!net5501_present()) 142 return 0; 143 144 register_net5501(); 145 146 return 0; 147 } 148 device_initcall(net5501_init); 149