blob: 2c24d8d30436521f638b00e11f2177b8c7e78ab1 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Philip Prindevilleda4e3302012-03-05 15:05:15 -08002/*
3 * System Specific setup for Soekris net5501
4 * At the moment this means setup of GPIO control of LEDs and buttons
5 * on net5501 boards.
6 *
Philip Prindevilleda4e3302012-03-05 15:05:15 -08007 * 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>
Philip Prindevilleda4e3302012-03-05 15:05:15 -080013 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/string.h>
Philip Prindevilleda4e3302012-03-05 15:05:15 -080019#include <linux/leds.h>
20#include <linux/platform_device.h>
21#include <linux/gpio.h>
22#include <linux/input.h>
23#include <linux/gpio_keys.h>
24
25#include <asm/geode.h>
26
27#define BIOS_REGION_BASE 0xffff0000
28#define BIOS_REGION_SIZE 0x00010000
29
30static struct gpio_keys_button net5501_gpio_buttons[] = {
31 {
32 .code = KEY_RESTART,
33 .gpio = 24,
34 .active_low = 1,
35 .desc = "Reset button",
36 .type = EV_KEY,
37 .wakeup = 0,
38 .debounce_interval = 100,
39 .can_disable = 0,
40 }
41};
42static struct gpio_keys_platform_data net5501_buttons_data = {
43 .buttons = net5501_gpio_buttons,
44 .nbuttons = ARRAY_SIZE(net5501_gpio_buttons),
45 .poll_interval = 20,
46};
47
48static struct platform_device net5501_buttons_dev = {
49 .name = "gpio-keys-polled",
50 .id = 1,
51 .dev = {
52 .platform_data = &net5501_buttons_data,
53 }
54};
55
56static struct gpio_led net5501_leds[] = {
57 {
58 .name = "net5501:1",
59 .gpio = 6,
60 .default_trigger = "default-on",
Bjarke Istrup Pedersend1d05892012-05-04 14:01:45 -070061 .active_low = 0,
Philip Prindevilleda4e3302012-03-05 15:05:15 -080062 },
63};
64
65static struct gpio_led_platform_data net5501_leds_data = {
66 .num_leds = ARRAY_SIZE(net5501_leds),
67 .leds = net5501_leds,
68};
69
70static struct platform_device net5501_leds_dev = {
71 .name = "leds-gpio",
72 .id = -1,
73 .dev.platform_data = &net5501_leds_data,
74};
75
Bartlomiej Zolnierkiewicza6d30e02013-09-30 15:21:15 +020076static struct platform_device *net5501_devs[] __initdata = {
Philip Prindevilleda4e3302012-03-05 15:05:15 -080077 &net5501_buttons_dev,
78 &net5501_leds_dev,
79};
80
81static void __init register_net5501(void)
82{
83 /* Setup LED control through leds-gpio driver */
84 platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs));
85}
86
87struct net5501_board {
88 u16 offset;
89 u16 len;
90 char *sig;
91};
92
93static struct net5501_board __initdata boards[] = {
94 { 0xb7b, 7, "net5501" }, /* net5501 v1.33/1.33c */
95 { 0xb1f, 7, "net5501" }, /* net5501 v1.32i */
96};
97
98static bool __init net5501_present(void)
99{
100 int i;
101 unsigned char *rombase, *bios;
102 bool found = false;
103
104 rombase = ioremap(BIOS_REGION_BASE, BIOS_REGION_SIZE - 1);
105 if (!rombase) {
106 printk(KERN_ERR "%s: failed to get rombase\n", KBUILD_MODNAME);
107 return found;
108 }
109
110 bios = rombase + 0x20; /* null terminated */
111
112 if (memcmp(bios, "comBIOS", 7))
113 goto unmap;
114
115 for (i = 0; i < ARRAY_SIZE(boards); i++) {
116 unsigned char *model = rombase + boards[i].offset;
117
118 if (!memcmp(model, boards[i].sig, boards[i].len)) {
119 printk(KERN_INFO "%s: system is recognized as \"%s\"\n",
120 KBUILD_MODNAME, model);
121
122 found = true;
123 break;
124 }
125 }
126
127unmap:
128 iounmap(rombase);
129 return found;
130}
131
132static int __init net5501_init(void)
133{
134 if (!is_geode())
135 return 0;
136
137 if (!net5501_present())
138 return 0;
139
140 register_net5501();
141
142 return 0;
143}
Paul Gortmaker605a46e2016-02-14 18:09:56 -0500144device_initcall(net5501_init);