1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
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 | * |
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 | |
15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> |
17 | #include <linux/io.h> |
18 | #include <linux/string.h> |
19 | #include <linux/leds.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/input.h> |
22 | #include <linux/gpio_keys.h> |
23 | #include <linux/gpio/machine.h> |
24 | |
25 | #include <asm/geode.h> |
26 | |
27 | #define BIOS_REGION_BASE 0xffff0000 |
28 | #define BIOS_REGION_SIZE 0x00010000 |
29 | |
30 | static 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 | }; |
42 | static 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 | |
48 | static 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 | |
56 | static struct gpio_led net5501_leds[] = { |
57 | { |
58 | .name = "net5501:1" , |
59 | .default_trigger = "default-on" , |
60 | }, |
61 | }; |
62 | |
63 | static struct gpio_led_platform_data net5501_leds_data = { |
64 | .num_leds = ARRAY_SIZE(net5501_leds), |
65 | .leds = net5501_leds, |
66 | }; |
67 | |
68 | static struct gpiod_lookup_table net5501_leds_gpio_table = { |
69 | .dev_id = "leds-gpio" , |
70 | .table = { |
71 | /* The Geode GPIOs should be on the CS5535 companion chip */ |
72 | GPIO_LOOKUP_IDX("cs5535-gpio" , 6, NULL, 0, GPIO_ACTIVE_HIGH), |
73 | { } |
74 | }, |
75 | }; |
76 | |
77 | static struct platform_device net5501_leds_dev = { |
78 | .name = "leds-gpio" , |
79 | .id = -1, |
80 | .dev.platform_data = &net5501_leds_data, |
81 | }; |
82 | |
83 | static struct platform_device *net5501_devs[] __initdata = { |
84 | &net5501_buttons_dev, |
85 | &net5501_leds_dev, |
86 | }; |
87 | |
88 | static void __init register_net5501(void) |
89 | { |
90 | /* Setup LED control through leds-gpio driver */ |
91 | gpiod_add_lookup_table(table: &net5501_leds_gpio_table); |
92 | platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs)); |
93 | } |
94 | |
95 | struct net5501_board { |
96 | u16 offset; |
97 | u16 len; |
98 | char *sig; |
99 | }; |
100 | |
101 | static struct net5501_board __initdata boards[] = { |
102 | { 0xb7b, 7, "net5501" }, /* net5501 v1.33/1.33c */ |
103 | { 0xb1f, 7, "net5501" }, /* net5501 v1.32i */ |
104 | }; |
105 | |
106 | static bool __init net5501_present(void) |
107 | { |
108 | int i; |
109 | unsigned char *rombase, *bios; |
110 | bool found = false; |
111 | |
112 | rombase = ioremap(BIOS_REGION_BASE, BIOS_REGION_SIZE - 1); |
113 | if (!rombase) { |
114 | printk(KERN_ERR "%s: failed to get rombase\n" , KBUILD_MODNAME); |
115 | return found; |
116 | } |
117 | |
118 | bios = rombase + 0x20; /* null terminated */ |
119 | |
120 | if (memcmp(p: bios, q: "comBIOS" , size: 7)) |
121 | goto unmap; |
122 | |
123 | for (i = 0; i < ARRAY_SIZE(boards); i++) { |
124 | unsigned char *model = rombase + boards[i].offset; |
125 | |
126 | if (!memcmp(p: model, q: boards[i].sig, size: boards[i].len)) { |
127 | printk(KERN_INFO "%s: system is recognized as \"%s\"\n" , |
128 | KBUILD_MODNAME, model); |
129 | |
130 | found = true; |
131 | break; |
132 | } |
133 | } |
134 | |
135 | unmap: |
136 | iounmap(addr: rombase); |
137 | return found; |
138 | } |
139 | |
140 | static int __init net5501_init(void) |
141 | { |
142 | if (!is_geode()) |
143 | return 0; |
144 | |
145 | if (!net5501_present()) |
146 | return 0; |
147 | |
148 | register_net5501(); |
149 | |
150 | return 0; |
151 | } |
152 | device_initcall(net5501_init); |
153 | |