xref: /openbmc/linux/drivers/platform/x86/pcengines-apuv2.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1f8eb0235SEnrico Weigelt, metux IT consult // SPDX-License-Identifier: GPL-2.0+
2f8eb0235SEnrico Weigelt, metux IT consult 
3f8eb0235SEnrico Weigelt, metux IT consult /*
4f8eb0235SEnrico Weigelt, metux IT consult  * PC-Engines APUv2/APUv3 board platform driver
502abbda1SAndy Shevchenko  * for GPIO buttons and LEDs
6f8eb0235SEnrico Weigelt, metux IT consult  *
7f8eb0235SEnrico Weigelt, metux IT consult  * Copyright (C) 2018 metux IT consult
8f8eb0235SEnrico Weigelt, metux IT consult  * Author: Enrico Weigelt <info@metux.net>
9f8eb0235SEnrico Weigelt, metux IT consult  */
10f8eb0235SEnrico Weigelt, metux IT consult 
11f8eb0235SEnrico Weigelt, metux IT consult #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
12f8eb0235SEnrico Weigelt, metux IT consult 
13f8eb0235SEnrico Weigelt, metux IT consult #include <linux/dmi.h>
14f8eb0235SEnrico Weigelt, metux IT consult #include <linux/err.h>
15f8eb0235SEnrico Weigelt, metux IT consult #include <linux/kernel.h>
16f8eb0235SEnrico Weigelt, metux IT consult #include <linux/leds.h>
17f8eb0235SEnrico Weigelt, metux IT consult #include <linux/module.h>
18f8eb0235SEnrico Weigelt, metux IT consult #include <linux/platform_device.h>
19f8eb0235SEnrico Weigelt, metux IT consult #include <linux/gpio_keys.h>
20f8eb0235SEnrico Weigelt, metux IT consult #include <linux/gpio/machine.h>
21f8eb0235SEnrico Weigelt, metux IT consult #include <linux/input.h>
22f8eb0235SEnrico Weigelt, metux IT consult #include <linux/platform_data/gpio/gpio-amd-fch.h>
23f8eb0235SEnrico Weigelt, metux IT consult 
24f8eb0235SEnrico Weigelt, metux IT consult /*
25f8eb0235SEnrico Weigelt, metux IT consult  * NOTE: this driver only supports APUv2/3 - not APUv1, as this one
2602abbda1SAndy Shevchenko  * has completely different register layouts.
27f8eb0235SEnrico Weigelt, metux IT consult  */
28f8eb0235SEnrico Weigelt, metux IT consult 
2902abbda1SAndy Shevchenko /* Register mappings */
30f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_REG_LED1		AMD_FCH_GPIO_REG_GPIO57
31f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_REG_LED2		AMD_FCH_GPIO_REG_GPIO58
32f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_REG_LED3		AMD_FCH_GPIO_REG_GPIO59_DEVSLP1
33f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_REG_MODESW		AMD_FCH_GPIO_REG_GPIO32_GE1
34f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_REG_SIMSWAP		AMD_FCH_GPIO_REG_GPIO33_GE2
35fce55cc8SEd Wildgoose #define APU2_GPIO_REG_MPCIE2		AMD_FCH_GPIO_REG_GPIO55_DEVSLP0
366a0694b6SFlorian Eckert #define APU2_GPIO_REG_MPCIE3		AMD_FCH_GPIO_REG_GPIO51
37f8eb0235SEnrico Weigelt, metux IT consult 
3802abbda1SAndy Shevchenko /* Order in which the GPIO lines are defined in the register list */
39f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_LINE_LED1		0
40f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_LINE_LED2		1
41f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_LINE_LED3		2
42f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_LINE_MODESW		3
43f8eb0235SEnrico Weigelt, metux IT consult #define APU2_GPIO_LINE_SIMSWAP		4
446a0694b6SFlorian Eckert #define APU2_GPIO_LINE_MPCIE2		5
456a0694b6SFlorian Eckert #define APU2_GPIO_LINE_MPCIE3		6
46f8eb0235SEnrico Weigelt, metux IT consult 
4702abbda1SAndy Shevchenko /* GPIO device */
48f8eb0235SEnrico Weigelt, metux IT consult 
49f8eb0235SEnrico Weigelt, metux IT consult static int apu2_gpio_regs[] = {
50f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED1]		= APU2_GPIO_REG_LED1,
51f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED2]		= APU2_GPIO_REG_LED2,
52f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED3]		= APU2_GPIO_REG_LED3,
53f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_MODESW]		= APU2_GPIO_REG_MODESW,
54f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_SIMSWAP]	= APU2_GPIO_REG_SIMSWAP,
556a0694b6SFlorian Eckert 	[APU2_GPIO_LINE_MPCIE2]		= APU2_GPIO_REG_MPCIE2,
566a0694b6SFlorian Eckert 	[APU2_GPIO_LINE_MPCIE3]		= APU2_GPIO_REG_MPCIE3,
57f8eb0235SEnrico Weigelt, metux IT consult };
58f8eb0235SEnrico Weigelt, metux IT consult 
59f8eb0235SEnrico Weigelt, metux IT consult static const char * const apu2_gpio_names[] = {
60f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED1]		= "front-led1",
61f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED2]		= "front-led2",
62f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_LED3]		= "front-led3",
63f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_MODESW]		= "front-button",
64f8eb0235SEnrico Weigelt, metux IT consult 	[APU2_GPIO_LINE_SIMSWAP]	= "simswap",
656a0694b6SFlorian Eckert 	[APU2_GPIO_LINE_MPCIE2]		= "mpcie2_reset",
666a0694b6SFlorian Eckert 	[APU2_GPIO_LINE_MPCIE3]		= "mpcie3_reset",
67f8eb0235SEnrico Weigelt, metux IT consult };
68f8eb0235SEnrico Weigelt, metux IT consult 
69f8eb0235SEnrico Weigelt, metux IT consult static const struct amd_fch_gpio_pdata board_apu2 = {
70f8eb0235SEnrico Weigelt, metux IT consult 	.gpio_num	= ARRAY_SIZE(apu2_gpio_regs),
71f8eb0235SEnrico Weigelt, metux IT consult 	.gpio_reg	= apu2_gpio_regs,
72f8eb0235SEnrico Weigelt, metux IT consult 	.gpio_names	= apu2_gpio_names,
73f8eb0235SEnrico Weigelt, metux IT consult };
74f8eb0235SEnrico Weigelt, metux IT consult 
7502abbda1SAndy Shevchenko /* GPIO LEDs device */
76f8eb0235SEnrico Weigelt, metux IT consult 
77f8eb0235SEnrico Weigelt, metux IT consult static const struct gpio_led apu2_leds[] = {
78f8eb0235SEnrico Weigelt, metux IT consult 	{ .name = "apu:green:1" },
79f8eb0235SEnrico Weigelt, metux IT consult 	{ .name = "apu:green:2" },
805037d4ddSEnrico Weigelt 	{ .name = "apu:green:3" },
81f8eb0235SEnrico Weigelt, metux IT consult };
82f8eb0235SEnrico Weigelt, metux IT consult 
83f8eb0235SEnrico Weigelt, metux IT consult static const struct gpio_led_platform_data apu2_leds_pdata = {
84f8eb0235SEnrico Weigelt, metux IT consult 	.num_leds	= ARRAY_SIZE(apu2_leds),
85f8eb0235SEnrico Weigelt, metux IT consult 	.leds		= apu2_leds,
86f8eb0235SEnrico Weigelt, metux IT consult };
87f8eb0235SEnrico Weigelt, metux IT consult 
8884f669b4SYueHaibing static struct gpiod_lookup_table gpios_led_table = {
89f8eb0235SEnrico Weigelt, metux IT consult 	.dev_id = "leds-gpio",
90f8eb0235SEnrico Weigelt, metux IT consult 	.table = {
91f8eb0235SEnrico Weigelt, metux IT consult 		GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED1,
92f8eb0235SEnrico Weigelt, metux IT consult 				NULL, 0, GPIO_ACTIVE_LOW),
93f8eb0235SEnrico Weigelt, metux IT consult 		GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED2,
94f8eb0235SEnrico Weigelt, metux IT consult 				NULL, 1, GPIO_ACTIVE_LOW),
95f8eb0235SEnrico Weigelt, metux IT consult 		GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED3,
96f8eb0235SEnrico Weigelt, metux IT consult 				NULL, 2, GPIO_ACTIVE_LOW),
97*9d7b132eSHans de Goede 		{} /* Terminating entry */
98f8eb0235SEnrico Weigelt, metux IT consult 	}
99f8eb0235SEnrico Weigelt, metux IT consult };
100f8eb0235SEnrico Weigelt, metux IT consult 
10102abbda1SAndy Shevchenko /* GPIO keyboard device */
102f8eb0235SEnrico Weigelt, metux IT consult 
103f8eb0235SEnrico Weigelt, metux IT consult static struct gpio_keys_button apu2_keys_buttons[] = {
104f8eb0235SEnrico Weigelt, metux IT consult 	{
105f14312a9SEnrico Weigelt 		.code			= KEY_RESTART,
106f8eb0235SEnrico Weigelt, metux IT consult 		.active_low		= 1,
107f8eb0235SEnrico Weigelt, metux IT consult 		.desc			= "front button",
108f8eb0235SEnrico Weigelt, metux IT consult 		.type			= EV_KEY,
109f8eb0235SEnrico Weigelt, metux IT consult 		.debounce_interval	= 10,
110f8eb0235SEnrico Weigelt, metux IT consult 		.value			= 1,
111f8eb0235SEnrico Weigelt, metux IT consult 	},
112f8eb0235SEnrico Weigelt, metux IT consult };
113f8eb0235SEnrico Weigelt, metux IT consult 
114f8eb0235SEnrico Weigelt, metux IT consult static const struct gpio_keys_platform_data apu2_keys_pdata = {
115f8eb0235SEnrico Weigelt, metux IT consult 	.buttons	= apu2_keys_buttons,
116f8eb0235SEnrico Weigelt, metux IT consult 	.nbuttons	= ARRAY_SIZE(apu2_keys_buttons),
117f8eb0235SEnrico Weigelt, metux IT consult 	.poll_interval	= 100,
118f8eb0235SEnrico Weigelt, metux IT consult 	.rep		= 0,
119f8eb0235SEnrico Weigelt, metux IT consult 	.name		= "apu2-keys",
120f8eb0235SEnrico Weigelt, metux IT consult };
121f8eb0235SEnrico Weigelt, metux IT consult 
12284f669b4SYueHaibing static struct gpiod_lookup_table gpios_key_table = {
123f8eb0235SEnrico Weigelt, metux IT consult 	.dev_id = "gpio-keys-polled",
124f8eb0235SEnrico Weigelt, metux IT consult 	.table = {
125f8eb0235SEnrico Weigelt, metux IT consult 		GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_MODESW,
126f8eb0235SEnrico Weigelt, metux IT consult 				NULL, 0, GPIO_ACTIVE_LOW),
127*9d7b132eSHans de Goede 		{} /* Terminating entry */
128f8eb0235SEnrico Weigelt, metux IT consult 	}
129f8eb0235SEnrico Weigelt, metux IT consult };
130f8eb0235SEnrico Weigelt, metux IT consult 
13102abbda1SAndy Shevchenko /* Board setup */
132f8eb0235SEnrico Weigelt, metux IT consult 
13302abbda1SAndy Shevchenko /* Note: matching works on string prefix, so "apu2" must come before "apu" */
134f8eb0235SEnrico Weigelt, metux IT consult static const struct dmi_system_id apu_gpio_dmi_table[] __initconst = {
135f8eb0235SEnrico Weigelt, metux IT consult 
13602abbda1SAndy Shevchenko 	/* APU2 w/ legacy BIOS < 4.0.8 */
137f8eb0235SEnrico Weigelt, metux IT consult 	{
138f8eb0235SEnrico Weigelt, metux IT consult 		.ident		= "apu2",
139f8eb0235SEnrico Weigelt, metux IT consult 		.matches	= {
140f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
141f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "APU2")
142f8eb0235SEnrico Weigelt, metux IT consult 		},
143f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data	= (void *)&board_apu2,
144f8eb0235SEnrico Weigelt, metux IT consult 	},
14502abbda1SAndy Shevchenko 	/* APU2 w/ legacy BIOS >= 4.0.8 */
146f8eb0235SEnrico Weigelt, metux IT consult 	{
147f8eb0235SEnrico Weigelt, metux IT consult 		.ident		= "apu2",
148f8eb0235SEnrico Weigelt, metux IT consult 		.matches	= {
149f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
150f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "apu2")
151f8eb0235SEnrico Weigelt, metux IT consult 		},
152f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data	= (void *)&board_apu2,
153f8eb0235SEnrico Weigelt, metux IT consult 	},
15402abbda1SAndy Shevchenko 	/* APU2 w/ mainline BIOS */
155f8eb0235SEnrico Weigelt, metux IT consult 	{
156f8eb0235SEnrico Weigelt, metux IT consult 		.ident		= "apu2",
157f8eb0235SEnrico Weigelt, metux IT consult 		.matches	= {
158f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
159f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2")
160f8eb0235SEnrico Weigelt, metux IT consult 		},
161f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data	= (void *)&board_apu2,
162f8eb0235SEnrico Weigelt, metux IT consult 	},
163f8eb0235SEnrico Weigelt, metux IT consult 
16402abbda1SAndy Shevchenko 	/* APU3 w/ legacy BIOS < 4.0.8 */
165f8eb0235SEnrico Weigelt, metux IT consult 	{
166f8eb0235SEnrico Weigelt, metux IT consult 		.ident		= "apu3",
167f8eb0235SEnrico Weigelt, metux IT consult 		.matches	= {
168f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
169f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "APU3")
170f8eb0235SEnrico Weigelt, metux IT consult 		},
171f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
172f8eb0235SEnrico Weigelt, metux IT consult 	},
17302abbda1SAndy Shevchenko 	/* APU3 w/ legacy BIOS >= 4.0.8 */
174f8eb0235SEnrico Weigelt, metux IT consult 	{
175f8eb0235SEnrico Weigelt, metux IT consult 		.ident       = "apu3",
176f8eb0235SEnrico Weigelt, metux IT consult 		.matches     = {
177f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
178f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "apu3")
179f8eb0235SEnrico Weigelt, metux IT consult 		},
180f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
181f8eb0235SEnrico Weigelt, metux IT consult 	},
18202abbda1SAndy Shevchenko 	/* APU3 w/ mainline BIOS */
183f8eb0235SEnrico Weigelt, metux IT consult 	{
184f8eb0235SEnrico Weigelt, metux IT consult 		.ident       = "apu3",
185f8eb0235SEnrico Weigelt, metux IT consult 		.matches     = {
186f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
187f8eb0235SEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu3")
188f8eb0235SEnrico Weigelt, metux IT consult 		},
189f8eb0235SEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
190f8eb0235SEnrico Weigelt, metux IT consult 	},
19102abbda1SAndy Shevchenko 	/* APU4 w/ legacy BIOS < 4.0.8 */
1923d00da1dSEnrico Weigelt, metux IT consult 	{
1933d00da1dSEnrico Weigelt, metux IT consult 		.ident        = "apu4",
1943d00da1dSEnrico Weigelt, metux IT consult 		.matches    = {
1953d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
1963d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "APU4")
1973d00da1dSEnrico Weigelt, metux IT consult 		},
1983d00da1dSEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
1993d00da1dSEnrico Weigelt, metux IT consult 	},
20002abbda1SAndy Shevchenko 	/* APU4 w/ legacy BIOS >= 4.0.8 */
2013d00da1dSEnrico Weigelt, metux IT consult 	{
2023d00da1dSEnrico Weigelt, metux IT consult 		.ident       = "apu4",
2033d00da1dSEnrico Weigelt, metux IT consult 		.matches     = {
2043d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
2053d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "apu4")
2063d00da1dSEnrico Weigelt, metux IT consult 		},
2073d00da1dSEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
2083d00da1dSEnrico Weigelt, metux IT consult 	},
20902abbda1SAndy Shevchenko 	/* APU4 w/ mainline BIOS */
2103d00da1dSEnrico Weigelt, metux IT consult 	{
2113d00da1dSEnrico Weigelt, metux IT consult 		.ident       = "apu4",
2123d00da1dSEnrico Weigelt, metux IT consult 		.matches     = {
2133d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
2143d00da1dSEnrico Weigelt, metux IT consult 			DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu4")
2153d00da1dSEnrico Weigelt, metux IT consult 		},
2163d00da1dSEnrico Weigelt, metux IT consult 		.driver_data = (void *)&board_apu2,
2173d00da1dSEnrico Weigelt, metux IT consult 	},
218f8eb0235SEnrico Weigelt, metux IT consult 	{}
219f8eb0235SEnrico Weigelt, metux IT consult };
220f8eb0235SEnrico Weigelt, metux IT consult 
221f8eb0235SEnrico Weigelt, metux IT consult static struct platform_device *apu_gpio_pdev;
222f8eb0235SEnrico Weigelt, metux IT consult static struct platform_device *apu_leds_pdev;
223f8eb0235SEnrico Weigelt, metux IT consult static struct platform_device *apu_keys_pdev;
224f8eb0235SEnrico Weigelt, metux IT consult 
apu_create_pdev(const char * name,const void * pdata,size_t sz)225f8eb0235SEnrico Weigelt, metux IT consult static struct platform_device * __init apu_create_pdev(
226f8eb0235SEnrico Weigelt, metux IT consult 	const char *name,
227f8eb0235SEnrico Weigelt, metux IT consult 	const void *pdata,
228f8eb0235SEnrico Weigelt, metux IT consult 	size_t sz)
229f8eb0235SEnrico Weigelt, metux IT consult {
230f8eb0235SEnrico Weigelt, metux IT consult 	struct platform_device *pdev;
231f8eb0235SEnrico Weigelt, metux IT consult 
232f8eb0235SEnrico Weigelt, metux IT consult 	pdev = platform_device_register_resndata(NULL,
233f8eb0235SEnrico Weigelt, metux IT consult 		name,
234f8eb0235SEnrico Weigelt, metux IT consult 		PLATFORM_DEVID_NONE,
235f8eb0235SEnrico Weigelt, metux IT consult 		NULL,
236f8eb0235SEnrico Weigelt, metux IT consult 		0,
237f8eb0235SEnrico Weigelt, metux IT consult 		pdata,
238f8eb0235SEnrico Weigelt, metux IT consult 		sz);
239f8eb0235SEnrico Weigelt, metux IT consult 
240f8eb0235SEnrico Weigelt, metux IT consult 	if (IS_ERR(pdev))
241f8eb0235SEnrico Weigelt, metux IT consult 		pr_err("failed registering %s: %ld\n", name, PTR_ERR(pdev));
242f8eb0235SEnrico Weigelt, metux IT consult 
243f8eb0235SEnrico Weigelt, metux IT consult 	return pdev;
244f8eb0235SEnrico Weigelt, metux IT consult }
245f8eb0235SEnrico Weigelt, metux IT consult 
apu_board_init(void)246f8eb0235SEnrico Weigelt, metux IT consult static int __init apu_board_init(void)
247f8eb0235SEnrico Weigelt, metux IT consult {
248f8eb0235SEnrico Weigelt, metux IT consult 	const struct dmi_system_id *id;
249f8eb0235SEnrico Weigelt, metux IT consult 
250f8eb0235SEnrico Weigelt, metux IT consult 	id = dmi_first_match(apu_gpio_dmi_table);
251f8eb0235SEnrico Weigelt, metux IT consult 	if (!id) {
25202abbda1SAndy Shevchenko 		pr_err("failed to detect APU board via DMI\n");
253f8eb0235SEnrico Weigelt, metux IT consult 		return -ENODEV;
254f8eb0235SEnrico Weigelt, metux IT consult 	}
255f8eb0235SEnrico Weigelt, metux IT consult 
256f8eb0235SEnrico Weigelt, metux IT consult 	gpiod_add_lookup_table(&gpios_led_table);
257f8eb0235SEnrico Weigelt, metux IT consult 	gpiod_add_lookup_table(&gpios_key_table);
258f8eb0235SEnrico Weigelt, metux IT consult 
259f8eb0235SEnrico Weigelt, metux IT consult 	apu_gpio_pdev = apu_create_pdev(
260f8eb0235SEnrico Weigelt, metux IT consult 		AMD_FCH_GPIO_DRIVER_NAME,
261f8eb0235SEnrico Weigelt, metux IT consult 		id->driver_data,
262f8eb0235SEnrico Weigelt, metux IT consult 		sizeof(struct amd_fch_gpio_pdata));
263f8eb0235SEnrico Weigelt, metux IT consult 
264f8eb0235SEnrico Weigelt, metux IT consult 	apu_leds_pdev = apu_create_pdev(
265f8eb0235SEnrico Weigelt, metux IT consult 		"leds-gpio",
266f8eb0235SEnrico Weigelt, metux IT consult 		&apu2_leds_pdata,
267f8eb0235SEnrico Weigelt, metux IT consult 		sizeof(apu2_leds_pdata));
268f8eb0235SEnrico Weigelt, metux IT consult 
269f8eb0235SEnrico Weigelt, metux IT consult 	apu_keys_pdev = apu_create_pdev(
270f8eb0235SEnrico Weigelt, metux IT consult 		"gpio-keys-polled",
271f8eb0235SEnrico Weigelt, metux IT consult 		&apu2_keys_pdata,
272f8eb0235SEnrico Weigelt, metux IT consult 		sizeof(apu2_keys_pdata));
273f8eb0235SEnrico Weigelt, metux IT consult 
274f8eb0235SEnrico Weigelt, metux IT consult 	return 0;
275f8eb0235SEnrico Weigelt, metux IT consult }
276f8eb0235SEnrico Weigelt, metux IT consult 
apu_board_exit(void)277f8eb0235SEnrico Weigelt, metux IT consult static void __exit apu_board_exit(void)
278f8eb0235SEnrico Weigelt, metux IT consult {
279f8eb0235SEnrico Weigelt, metux IT consult 	gpiod_remove_lookup_table(&gpios_led_table);
280f8eb0235SEnrico Weigelt, metux IT consult 	gpiod_remove_lookup_table(&gpios_key_table);
281f8eb0235SEnrico Weigelt, metux IT consult 
282f8eb0235SEnrico Weigelt, metux IT consult 	platform_device_unregister(apu_keys_pdev);
283f8eb0235SEnrico Weigelt, metux IT consult 	platform_device_unregister(apu_leds_pdev);
284f8eb0235SEnrico Weigelt, metux IT consult 	platform_device_unregister(apu_gpio_pdev);
285f8eb0235SEnrico Weigelt, metux IT consult }
286f8eb0235SEnrico Weigelt, metux IT consult 
287f8eb0235SEnrico Weigelt, metux IT consult module_init(apu_board_init);
288f8eb0235SEnrico Weigelt, metux IT consult module_exit(apu_board_exit);
289f8eb0235SEnrico Weigelt, metux IT consult 
290f8eb0235SEnrico Weigelt, metux IT consult MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
29102abbda1SAndy Shevchenko MODULE_DESCRIPTION("PC Engines APUv2/APUv3 board GPIO/LEDs/keys driver");
292f8eb0235SEnrico Weigelt, metux IT consult MODULE_LICENSE("GPL");
293f8eb0235SEnrico Weigelt, metux IT consult MODULE_DEVICE_TABLE(dmi, apu_gpio_dmi_table);
294edbfe83dSJean Delvare MODULE_SOFTDEP("pre: platform:" AMD_FCH_GPIO_DRIVER_NAME " platform:leds-gpio platform:gpio_keys_polled");
295