xref: /linux/drivers/mfd/upboard-fpga.c (revision 9e676a024fa1fa2bd8150c2d2ba85478280353bc)
1*c2b148f3SThomas Richard // SPDX-License-Identifier: GPL-2.0-only
2*c2b148f3SThomas Richard /*
3*c2b148f3SThomas Richard  * UP Board FPGA driver.
4*c2b148f3SThomas Richard  *
5*c2b148f3SThomas Richard  * FPGA provides more GPIO driving power, LEDS and pin mux function.
6*c2b148f3SThomas Richard  *
7*c2b148f3SThomas Richard  * Copyright (c) AAEON. All rights reserved.
8*c2b148f3SThomas Richard  * Copyright (C) 2024 Bootlin
9*c2b148f3SThomas Richard  *
10*c2b148f3SThomas Richard  * Author: Gary Wang <garywang@aaeon.com.tw>
11*c2b148f3SThomas Richard  * Author: Thomas Richard <thomas.richard@bootlin.com>
12*c2b148f3SThomas Richard  */
13*c2b148f3SThomas Richard 
14*c2b148f3SThomas Richard #include <linux/acpi.h>
15*c2b148f3SThomas Richard #include <linux/bitfield.h>
16*c2b148f3SThomas Richard #include <linux/device.h>
17*c2b148f3SThomas Richard #include <linux/err.h>
18*c2b148f3SThomas Richard #include <linux/gpio/consumer.h>
19*c2b148f3SThomas Richard #include <linux/mfd/core.h>
20*c2b148f3SThomas Richard #include <linux/mfd/upboard-fpga.h>
21*c2b148f3SThomas Richard #include <linux/module.h>
22*c2b148f3SThomas Richard #include <linux/mod_devicetable.h>
23*c2b148f3SThomas Richard #include <linux/platform_device.h>
24*c2b148f3SThomas Richard #include <linux/property.h>
25*c2b148f3SThomas Richard #include <linux/regmap.h>
26*c2b148f3SThomas Richard #include <linux/sysfs.h>
27*c2b148f3SThomas Richard 
28*c2b148f3SThomas Richard #define UPBOARD_AAEON_MANUFACTURER_ID	0x01
29*c2b148f3SThomas Richard #define UPBOARD_MANUFACTURER_ID_MASK	GENMASK(7, 0)
30*c2b148f3SThomas Richard 
31*c2b148f3SThomas Richard #define UPBOARD_ADDRESS_SIZE  7
32*c2b148f3SThomas Richard #define UPBOARD_REGISTER_SIZE 16
33*c2b148f3SThomas Richard 
34*c2b148f3SThomas Richard #define UPBOARD_READ_FLAG     BIT(UPBOARD_ADDRESS_SIZE)
35*c2b148f3SThomas Richard 
36*c2b148f3SThomas Richard #define UPBOARD_FW_ID_MAJOR_SUPPORTED	0x0
37*c2b148f3SThomas Richard 
38*c2b148f3SThomas Richard #define UPBOARD_FW_ID_BUILD_MASK	GENMASK(15, 12)
39*c2b148f3SThomas Richard #define UPBOARD_FW_ID_MAJOR_MASK	GENMASK(11, 8)
40*c2b148f3SThomas Richard #define UPBOARD_FW_ID_MINOR_MASK	GENMASK(7, 4)
41*c2b148f3SThomas Richard #define UPBOARD_FW_ID_PATCH_MASK	GENMASK(3, 0)
42*c2b148f3SThomas Richard 
43*c2b148f3SThomas Richard static int upboard_fpga_read(void *context, unsigned int reg, unsigned int *val)
44*c2b148f3SThomas Richard {
45*c2b148f3SThomas Richard 	struct upboard_fpga *fpga = context;
46*c2b148f3SThomas Richard 	int i;
47*c2b148f3SThomas Richard 
48*c2b148f3SThomas Richard 	/* Clear to start new transaction */
49*c2b148f3SThomas Richard 	gpiod_set_value(fpga->clear_gpio, 0);
50*c2b148f3SThomas Richard 	gpiod_set_value(fpga->clear_gpio, 1);
51*c2b148f3SThomas Richard 
52*c2b148f3SThomas Richard 	reg |= UPBOARD_READ_FLAG;
53*c2b148f3SThomas Richard 
54*c2b148f3SThomas Richard 	/* Send clock and addr from strobe & datain pins */
55*c2b148f3SThomas Richard 	for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
56*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 0);
57*c2b148f3SThomas Richard 		gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
58*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 1);
59*c2b148f3SThomas Richard 	}
60*c2b148f3SThomas Richard 
61*c2b148f3SThomas Richard 	gpiod_set_value(fpga->strobe_gpio, 0);
62*c2b148f3SThomas Richard 	*val = 0;
63*c2b148f3SThomas Richard 
64*c2b148f3SThomas Richard 	/* Read data from dataout pin */
65*c2b148f3SThomas Richard 	for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) {
66*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 1);
67*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 0);
68*c2b148f3SThomas Richard 		*val |= gpiod_get_value(fpga->dataout_gpio) << i;
69*c2b148f3SThomas Richard 	}
70*c2b148f3SThomas Richard 
71*c2b148f3SThomas Richard 	gpiod_set_value(fpga->strobe_gpio, 1);
72*c2b148f3SThomas Richard 
73*c2b148f3SThomas Richard 	return 0;
74*c2b148f3SThomas Richard }
75*c2b148f3SThomas Richard 
76*c2b148f3SThomas Richard static int upboard_fpga_write(void *context, unsigned int reg, unsigned int val)
77*c2b148f3SThomas Richard {
78*c2b148f3SThomas Richard 	struct upboard_fpga *fpga = context;
79*c2b148f3SThomas Richard 	int i;
80*c2b148f3SThomas Richard 
81*c2b148f3SThomas Richard 	/* Clear to start new transcation */
82*c2b148f3SThomas Richard 	gpiod_set_value(fpga->clear_gpio, 0);
83*c2b148f3SThomas Richard 	gpiod_set_value(fpga->clear_gpio, 1);
84*c2b148f3SThomas Richard 
85*c2b148f3SThomas Richard 	/* Send clock and addr from strobe & datain pins */
86*c2b148f3SThomas Richard 	for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
87*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 0);
88*c2b148f3SThomas Richard 		gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
89*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 1);
90*c2b148f3SThomas Richard 	}
91*c2b148f3SThomas Richard 
92*c2b148f3SThomas Richard 	gpiod_set_value(fpga->strobe_gpio, 0);
93*c2b148f3SThomas Richard 
94*c2b148f3SThomas Richard 	/* Write data to datain pin */
95*c2b148f3SThomas Richard 	for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) {
96*c2b148f3SThomas Richard 		gpiod_set_value(fpga->datain_gpio, !!(val & BIT(i)));
97*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 1);
98*c2b148f3SThomas Richard 		gpiod_set_value(fpga->strobe_gpio, 0);
99*c2b148f3SThomas Richard 	}
100*c2b148f3SThomas Richard 
101*c2b148f3SThomas Richard 	gpiod_set_value(fpga->strobe_gpio, 1);
102*c2b148f3SThomas Richard 
103*c2b148f3SThomas Richard 	return 0;
104*c2b148f3SThomas Richard }
105*c2b148f3SThomas Richard 
106*c2b148f3SThomas Richard static const struct regmap_range upboard_up_readable_ranges[] = {
107*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID),
108*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0),
109*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1),
110*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1),
111*c2b148f3SThomas Richard };
112*c2b148f3SThomas Richard 
113*c2b148f3SThomas Richard static const struct regmap_range upboard_up_writable_ranges[] = {
114*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0),
115*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1),
116*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1),
117*c2b148f3SThomas Richard };
118*c2b148f3SThomas Richard 
119*c2b148f3SThomas Richard static const struct regmap_access_table upboard_up_readable_table = {
120*c2b148f3SThomas Richard 	.yes_ranges = upboard_up_readable_ranges,
121*c2b148f3SThomas Richard 	.n_yes_ranges = ARRAY_SIZE(upboard_up_readable_ranges),
122*c2b148f3SThomas Richard };
123*c2b148f3SThomas Richard 
124*c2b148f3SThomas Richard static const struct regmap_access_table upboard_up_writable_table = {
125*c2b148f3SThomas Richard 	.yes_ranges = upboard_up_writable_ranges,
126*c2b148f3SThomas Richard 	.n_yes_ranges = ARRAY_SIZE(upboard_up_writable_ranges),
127*c2b148f3SThomas Richard };
128*c2b148f3SThomas Richard 
129*c2b148f3SThomas Richard static const struct regmap_config upboard_up_regmap_config = {
130*c2b148f3SThomas Richard 	.reg_bits = UPBOARD_ADDRESS_SIZE,
131*c2b148f3SThomas Richard 	.val_bits = UPBOARD_REGISTER_SIZE,
132*c2b148f3SThomas Richard 	.max_register = UPBOARD_REG_MAX,
133*c2b148f3SThomas Richard 	.reg_read = upboard_fpga_read,
134*c2b148f3SThomas Richard 	.reg_write = upboard_fpga_write,
135*c2b148f3SThomas Richard 	.fast_io = false,
136*c2b148f3SThomas Richard 	.cache_type = REGCACHE_NONE,
137*c2b148f3SThomas Richard 	.rd_table = &upboard_up_readable_table,
138*c2b148f3SThomas Richard 	.wr_table = &upboard_up_writable_table,
139*c2b148f3SThomas Richard };
140*c2b148f3SThomas Richard 
141*c2b148f3SThomas Richard static const struct regmap_range upboard_up2_readable_ranges[] = {
142*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID),
143*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1),
144*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2),
145*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2),
146*c2b148f3SThomas Richard };
147*c2b148f3SThomas Richard 
148*c2b148f3SThomas Richard static const struct regmap_range upboard_up2_writable_ranges[] = {
149*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1),
150*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2),
151*c2b148f3SThomas Richard 	regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2),
152*c2b148f3SThomas Richard };
153*c2b148f3SThomas Richard 
154*c2b148f3SThomas Richard static const struct regmap_access_table upboard_up2_readable_table = {
155*c2b148f3SThomas Richard 	.yes_ranges = upboard_up2_readable_ranges,
156*c2b148f3SThomas Richard 	.n_yes_ranges = ARRAY_SIZE(upboard_up2_readable_ranges),
157*c2b148f3SThomas Richard };
158*c2b148f3SThomas Richard 
159*c2b148f3SThomas Richard static const struct regmap_access_table upboard_up2_writable_table = {
160*c2b148f3SThomas Richard 	.yes_ranges = upboard_up2_writable_ranges,
161*c2b148f3SThomas Richard 	.n_yes_ranges = ARRAY_SIZE(upboard_up2_writable_ranges),
162*c2b148f3SThomas Richard };
163*c2b148f3SThomas Richard 
164*c2b148f3SThomas Richard static const struct regmap_config upboard_up2_regmap_config = {
165*c2b148f3SThomas Richard 	.reg_bits = UPBOARD_ADDRESS_SIZE,
166*c2b148f3SThomas Richard 	.val_bits = UPBOARD_REGISTER_SIZE,
167*c2b148f3SThomas Richard 	.max_register = UPBOARD_REG_MAX,
168*c2b148f3SThomas Richard 	.reg_read = upboard_fpga_read,
169*c2b148f3SThomas Richard 	.reg_write = upboard_fpga_write,
170*c2b148f3SThomas Richard 	.fast_io = false,
171*c2b148f3SThomas Richard 	.cache_type = REGCACHE_NONE,
172*c2b148f3SThomas Richard 	.rd_table = &upboard_up2_readable_table,
173*c2b148f3SThomas Richard 	.wr_table = &upboard_up2_writable_table,
174*c2b148f3SThomas Richard };
175*c2b148f3SThomas Richard 
176*c2b148f3SThomas Richard static const struct mfd_cell upboard_up_mfd_cells[] = {
177*c2b148f3SThomas Richard 	{ .name = "upboard-pinctrl" },
178*c2b148f3SThomas Richard 	{ .name = "upboard-leds" },
179*c2b148f3SThomas Richard };
180*c2b148f3SThomas Richard 
181*c2b148f3SThomas Richard static const struct upboard_fpga_data upboard_up_fpga_data = {
182*c2b148f3SThomas Richard 	.type = UPBOARD_UP_FPGA,
183*c2b148f3SThomas Richard 	.regmap_config = &upboard_up_regmap_config,
184*c2b148f3SThomas Richard };
185*c2b148f3SThomas Richard 
186*c2b148f3SThomas Richard static const struct upboard_fpga_data upboard_up2_fpga_data = {
187*c2b148f3SThomas Richard 	.type = UPBOARD_UP2_FPGA,
188*c2b148f3SThomas Richard 	.regmap_config = &upboard_up2_regmap_config,
189*c2b148f3SThomas Richard };
190*c2b148f3SThomas Richard 
191*c2b148f3SThomas Richard static int upboard_fpga_gpio_init(struct upboard_fpga *fpga)
192*c2b148f3SThomas Richard {
193*c2b148f3SThomas Richard 	fpga->enable_gpio = devm_gpiod_get(fpga->dev, "enable", GPIOD_ASIS);
194*c2b148f3SThomas Richard 	if (IS_ERR(fpga->enable_gpio))
195*c2b148f3SThomas Richard 		return PTR_ERR(fpga->enable_gpio);
196*c2b148f3SThomas Richard 
197*c2b148f3SThomas Richard 	fpga->clear_gpio = devm_gpiod_get(fpga->dev, "clear", GPIOD_OUT_LOW);
198*c2b148f3SThomas Richard 	if (IS_ERR(fpga->clear_gpio))
199*c2b148f3SThomas Richard 		return PTR_ERR(fpga->clear_gpio);
200*c2b148f3SThomas Richard 
201*c2b148f3SThomas Richard 	fpga->strobe_gpio = devm_gpiod_get(fpga->dev, "strobe", GPIOD_OUT_LOW);
202*c2b148f3SThomas Richard 	if (IS_ERR(fpga->strobe_gpio))
203*c2b148f3SThomas Richard 		return PTR_ERR(fpga->strobe_gpio);
204*c2b148f3SThomas Richard 
205*c2b148f3SThomas Richard 	fpga->datain_gpio = devm_gpiod_get(fpga->dev, "datain", GPIOD_OUT_LOW);
206*c2b148f3SThomas Richard 	if (IS_ERR(fpga->datain_gpio))
207*c2b148f3SThomas Richard 		return PTR_ERR(fpga->datain_gpio);
208*c2b148f3SThomas Richard 
209*c2b148f3SThomas Richard 	fpga->dataout_gpio = devm_gpiod_get(fpga->dev, "dataout", GPIOD_IN);
210*c2b148f3SThomas Richard 	if (IS_ERR(fpga->dataout_gpio))
211*c2b148f3SThomas Richard 		return PTR_ERR(fpga->dataout_gpio);
212*c2b148f3SThomas Richard 
213*c2b148f3SThomas Richard 	gpiod_set_value(fpga->enable_gpio, 1);
214*c2b148f3SThomas Richard 
215*c2b148f3SThomas Richard 	return 0;
216*c2b148f3SThomas Richard }
217*c2b148f3SThomas Richard 
218*c2b148f3SThomas Richard static int upboard_fpga_get_firmware_version(struct upboard_fpga *fpga)
219*c2b148f3SThomas Richard {
220*c2b148f3SThomas Richard 	unsigned int platform_id, manufacturer_id;
221*c2b148f3SThomas Richard 	int ret;
222*c2b148f3SThomas Richard 
223*c2b148f3SThomas Richard 	if (!fpga)
224*c2b148f3SThomas Richard 		return -ENOMEM;
225*c2b148f3SThomas Richard 
226*c2b148f3SThomas Richard 	ret = regmap_read(fpga->regmap, UPBOARD_REG_PLATFORM_ID, &platform_id);
227*c2b148f3SThomas Richard 	if (ret)
228*c2b148f3SThomas Richard 		return ret;
229*c2b148f3SThomas Richard 
230*c2b148f3SThomas Richard 	manufacturer_id = platform_id & UPBOARD_MANUFACTURER_ID_MASK;
231*c2b148f3SThomas Richard 	if (manufacturer_id != UPBOARD_AAEON_MANUFACTURER_ID)
232*c2b148f3SThomas Richard 		return dev_err_probe(fpga->dev, -ENODEV,
233*c2b148f3SThomas Richard 				     "driver not compatible with custom FPGA FW from manufacturer id %#02x.",
234*c2b148f3SThomas Richard 				     manufacturer_id);
235*c2b148f3SThomas Richard 
236*c2b148f3SThomas Richard 	ret = regmap_read(fpga->regmap, UPBOARD_REG_FIRMWARE_ID, &fpga->firmware_version);
237*c2b148f3SThomas Richard 	if (ret)
238*c2b148f3SThomas Richard 		return ret;
239*c2b148f3SThomas Richard 
240*c2b148f3SThomas Richard 	if (FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version) !=
241*c2b148f3SThomas Richard 	    UPBOARD_FW_ID_MAJOR_SUPPORTED)
242*c2b148f3SThomas Richard 		return dev_err_probe(fpga->dev, -ENODEV,
243*c2b148f3SThomas Richard 				     "unsupported FPGA FW v%lu.%lu.%lu build %#02lx",
244*c2b148f3SThomas Richard 				     FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version),
245*c2b148f3SThomas Richard 				     FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version),
246*c2b148f3SThomas Richard 				     FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version),
247*c2b148f3SThomas Richard 				     FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version));
248*c2b148f3SThomas Richard 	return 0;
249*c2b148f3SThomas Richard }
250*c2b148f3SThomas Richard 
251*c2b148f3SThomas Richard static ssize_t upboard_fpga_version_show(struct device *dev, struct device_attribute *attr,
252*c2b148f3SThomas Richard 					 char *buf)
253*c2b148f3SThomas Richard {
254*c2b148f3SThomas Richard 	struct upboard_fpga *fpga = dev_get_drvdata(dev);
255*c2b148f3SThomas Richard 
256*c2b148f3SThomas Richard 	return sysfs_emit(buf, "FPGA FW v%lu.%lu.%lu build %#02lx\n",
257*c2b148f3SThomas Richard 			  FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version),
258*c2b148f3SThomas Richard 			  FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version),
259*c2b148f3SThomas Richard 			  FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version),
260*c2b148f3SThomas Richard 			  FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version));
261*c2b148f3SThomas Richard }
262*c2b148f3SThomas Richard 
263*c2b148f3SThomas Richard static DEVICE_ATTR_RO(upboard_fpga_version);
264*c2b148f3SThomas Richard 
265*c2b148f3SThomas Richard static struct attribute *upboard_fpga_attrs[] = {
266*c2b148f3SThomas Richard 	&dev_attr_upboard_fpga_version.attr,
267*c2b148f3SThomas Richard 	NULL
268*c2b148f3SThomas Richard };
269*c2b148f3SThomas Richard 
270*c2b148f3SThomas Richard ATTRIBUTE_GROUPS(upboard_fpga);
271*c2b148f3SThomas Richard 
272*c2b148f3SThomas Richard static int upboard_fpga_probe(struct platform_device *pdev)
273*c2b148f3SThomas Richard {
274*c2b148f3SThomas Richard 	struct device *dev = &pdev->dev;
275*c2b148f3SThomas Richard 	struct upboard_fpga *fpga;
276*c2b148f3SThomas Richard 	int ret;
277*c2b148f3SThomas Richard 
278*c2b148f3SThomas Richard 	fpga = devm_kzalloc(dev, sizeof(*fpga), GFP_KERNEL);
279*c2b148f3SThomas Richard 	if (!fpga)
280*c2b148f3SThomas Richard 		return -ENOMEM;
281*c2b148f3SThomas Richard 
282*c2b148f3SThomas Richard 	fpga->fpga_data = device_get_match_data(dev);
283*c2b148f3SThomas Richard 
284*c2b148f3SThomas Richard 	fpga->dev = dev;
285*c2b148f3SThomas Richard 
286*c2b148f3SThomas Richard 	platform_set_drvdata(pdev, fpga);
287*c2b148f3SThomas Richard 
288*c2b148f3SThomas Richard 	fpga->regmap = devm_regmap_init(dev, NULL, fpga, fpga->fpga_data->regmap_config);
289*c2b148f3SThomas Richard 	if (IS_ERR(fpga->regmap))
290*c2b148f3SThomas Richard 		return PTR_ERR(fpga->regmap);
291*c2b148f3SThomas Richard 
292*c2b148f3SThomas Richard 	ret = upboard_fpga_gpio_init(fpga);
293*c2b148f3SThomas Richard 	if (ret)
294*c2b148f3SThomas Richard 		return dev_err_probe(dev, ret, "Failed to initialize FPGA common GPIOs");
295*c2b148f3SThomas Richard 
296*c2b148f3SThomas Richard 	ret = upboard_fpga_get_firmware_version(fpga);
297*c2b148f3SThomas Richard 	if (ret)
298*c2b148f3SThomas Richard 		return ret;
299*c2b148f3SThomas Richard 
300*c2b148f3SThomas Richard 	return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, upboard_up_mfd_cells,
301*c2b148f3SThomas Richard 				    ARRAY_SIZE(upboard_up_mfd_cells), NULL, 0, NULL);
302*c2b148f3SThomas Richard }
303*c2b148f3SThomas Richard 
304*c2b148f3SThomas Richard static const struct acpi_device_id upboard_fpga_acpi_match[] = {
305*c2b148f3SThomas Richard 	{ "AANT0F01", (kernel_ulong_t)&upboard_up2_fpga_data },
306*c2b148f3SThomas Richard 	{ "AANT0F04", (kernel_ulong_t)&upboard_up_fpga_data },
307*c2b148f3SThomas Richard 	{}
308*c2b148f3SThomas Richard };
309*c2b148f3SThomas Richard MODULE_DEVICE_TABLE(acpi, upboard_fpga_acpi_match);
310*c2b148f3SThomas Richard 
311*c2b148f3SThomas Richard static struct platform_driver upboard_fpga_driver = {
312*c2b148f3SThomas Richard 	.driver = {
313*c2b148f3SThomas Richard 		.name = "upboard-fpga",
314*c2b148f3SThomas Richard 		.acpi_match_table = ACPI_PTR(upboard_fpga_acpi_match),
315*c2b148f3SThomas Richard 		.dev_groups	= upboard_fpga_groups,
316*c2b148f3SThomas Richard 	},
317*c2b148f3SThomas Richard 	.probe = upboard_fpga_probe,
318*c2b148f3SThomas Richard };
319*c2b148f3SThomas Richard 
320*c2b148f3SThomas Richard module_platform_driver(upboard_fpga_driver);
321*c2b148f3SThomas Richard 
322*c2b148f3SThomas Richard MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>");
323*c2b148f3SThomas Richard MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
324*c2b148f3SThomas Richard MODULE_DESCRIPTION("UP Board FPGA driver");
325*c2b148f3SThomas Richard MODULE_LICENSE("GPL");
326