diff options
author | Zhichang Yuan <yuanzhichang@hisilicon.com> | 2018-03-21 18:23:02 -0400 |
---|---|---|
committer | Bjorn Helgaas <helgaas@kernel.org> | 2018-04-04 09:42:48 -0400 |
commit | adf38bb0b5956ab5469acb1ca981a9287c7ad1d8 (patch) | |
tree | c08d2e7f88c69883ae7aff65647e0c9d9589e928 | |
parent | 65af618d2c559f8eb19d80d03a23029651a59de4 (diff) |
HISI LPC: Support the LPC host on Hip06/Hip07 with DT bindings
The low-pin-count (LPC) interface of Hip06/Hip07 accesses I/O port space of
peripherals.
Implement the LPC host controller driver which performs the I/O operations
on the underlying hardware. We don't want to touch existing drivers such
as ipmi-bt, so this driver applies the indirect-IO introduced in the
previous patch after registering an indirect-IO node to the indirect-IO
devices list which will be searched by the I/O accessors to retrieve the
host-local I/O port.
The driver config is set as a bool instead of a tristate. The reason here
is that, by the very nature of the driver providing a logical PIO range, it
does not make sense to have this driver as a loadable module. Another more
specific reason is that the Huawei D03 board which includes Hip06 SoC
requires the LPC bus for UART console, so should be built in.
Tested-by: dann frazier <dann.frazier@canonical.com>
Signed-off-by: Zou Rongrong <zourongrong@huawei.com>
Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Acked-by: Rob Herring <robh@kernel.org> # dts part
-rw-r--r-- | Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt | 33 | ||||
-rw-r--r-- | drivers/bus/Kconfig | 8 | ||||
-rw-r--r-- | drivers/bus/Makefile | 1 | ||||
-rw-r--r-- | drivers/bus/hisi_lpc.c | 415 |
4 files changed, 457 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt new file mode 100644 index 000000000000..10bd35f9207f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | Hisilicon Hip06 Low Pin Count device | ||
2 | Hisilicon Hip06 SoCs implement a Low Pin Count (LPC) controller, which | ||
3 | provides I/O access to some legacy ISA devices. | ||
4 | Hip06 is based on arm64 architecture where there is no I/O space. So, the | ||
5 | I/O ports here are not CPU addresses, and there is no 'ranges' property in | ||
6 | LPC device node. | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: value should be as follows: | ||
10 | (a) "hisilicon,hip06-lpc" | ||
11 | (b) "hisilicon,hip07-lpc" | ||
12 | - #address-cells: must be 2 which stick to the ISA/EISA binding doc. | ||
13 | - #size-cells: must be 1 which stick to the ISA/EISA binding doc. | ||
14 | - reg: base memory range where the LPC register set is mapped. | ||
15 | |||
16 | Note: | ||
17 | The node name before '@' must be "isa" to represent the binding stick to the | ||
18 | ISA/EISA binding specification. | ||
19 | |||
20 | Example: | ||
21 | |||
22 | isa@a01b0000 { | ||
23 | compatible = "hisilicon,hip06-lpc"; | ||
24 | #address-cells = <2>; | ||
25 | #size-cells = <1>; | ||
26 | reg = <0x0 0xa01b0000 0x0 0x1000>; | ||
27 | |||
28 | ipmi0: bt@e4 { | ||
29 | compatible = "ipmi-bt"; | ||
30 | device_type = "ipmi"; | ||
31 | reg = <0x01 0xe4 0x04>; | ||
32 | }; | ||
33 | }; | ||
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 57e011d36a79..a3fad0f0292f 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -65,6 +65,14 @@ config BRCMSTB_GISB_ARB | |||
65 | arbiter. This driver provides timeout and target abort error handling | 65 | arbiter. This driver provides timeout and target abort error handling |
66 | and internal bus master decoding. | 66 | and internal bus master decoding. |
67 | 67 | ||
68 | config HISILICON_LPC | ||
69 | bool "Support for ISA I/O space on HiSilicon Hip06/7" | ||
70 | depends on ARM64 && (ARCH_HISI || COMPILE_TEST) | ||
71 | select INDIRECT_PIO | ||
72 | help | ||
73 | Driver to enable I/O access to devices attached to the Low Pin | ||
74 | Count bus on the HiSilicon Hip06/7 SoC. | ||
75 | |||
68 | config IMX_WEIM | 76 | config IMX_WEIM |
69 | bool "Freescale EIM DRIVER" | 77 | bool "Freescale EIM DRIVER" |
70 | depends on ARCH_MXC | 78 | depends on ARCH_MXC |
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 9bcd0bf3954b..50bb12a971a0 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile | |||
@@ -7,6 +7,7 @@ | |||
7 | obj-$(CONFIG_ARM_CCI) += arm-cci.o | 7 | obj-$(CONFIG_ARM_CCI) += arm-cci.o |
8 | obj-$(CONFIG_ARM_CCN) += arm-ccn.o | 8 | obj-$(CONFIG_ARM_CCN) += arm-ccn.o |
9 | 9 | ||
10 | obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o | ||
10 | obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o | 11 | obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o |
11 | obj-$(CONFIG_IMX_WEIM) += imx-weim.o | 12 | obj-$(CONFIG_IMX_WEIM) += imx-weim.o |
12 | obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o | 13 | obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o |
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c new file mode 100644 index 000000000000..6123bff3215f --- /dev/null +++ b/drivers/bus/hisi_lpc.c | |||
@@ -0,0 +1,415 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved. | ||
4 | * Author: Zhichang Yuan <yuanzhichang@hisilicon.com> | ||
5 | * Author: Zou Rongrong <zourongrong@huawei.com> | ||
6 | * Author: John Garry <john.garry@huawei.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/acpi.h> | ||
10 | #include <linux/console.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/logic_pio.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #define DRV_NAME "hisi-lpc" | ||
22 | |||
23 | /* | ||
24 | * Setting this bit means each IO operation will target a different port | ||
25 | * address; 0 means repeated IO operations will use the same port, | ||
26 | * such as BT. | ||
27 | */ | ||
28 | #define FG_INCRADDR_LPC 0x02 | ||
29 | |||
30 | struct lpc_cycle_para { | ||
31 | unsigned int opflags; | ||
32 | unsigned int csize; /* data length of each operation */ | ||
33 | }; | ||
34 | |||
35 | struct hisi_lpc_dev { | ||
36 | spinlock_t cycle_lock; | ||
37 | void __iomem *membase; | ||
38 | struct logic_pio_hwaddr *io_host; | ||
39 | }; | ||
40 | |||
41 | /* The max IO cycle counts supported is four per operation at maximum */ | ||
42 | #define LPC_MAX_DWIDTH 4 | ||
43 | |||
44 | #define LPC_REG_STARTUP_SIGNAL 0x00 | ||
45 | #define LPC_REG_STARTUP_SIGNAL_START BIT(0) | ||
46 | #define LPC_REG_OP_STATUS 0x04 | ||
47 | #define LPC_REG_OP_STATUS_IDLE BIT(0) | ||
48 | #define LPC_REG_OP_STATUS_FINISHED BIT(1) | ||
49 | #define LPC_REG_OP_LEN 0x10 /* LPC cycles count per start */ | ||
50 | #define LPC_REG_CMD 0x14 | ||
51 | #define LPC_REG_CMD_OP BIT(0) /* 0: read, 1: write */ | ||
52 | #define LPC_REG_CMD_SAMEADDR BIT(3) | ||
53 | #define LPC_REG_ADDR 0x20 /* target address */ | ||
54 | #define LPC_REG_WDATA 0x24 /* write FIFO */ | ||
55 | #define LPC_REG_RDATA 0x28 /* read FIFO */ | ||
56 | |||
57 | /* The minimal nanosecond interval for each query on LPC cycle status */ | ||
58 | #define LPC_NSEC_PERWAIT 100 | ||
59 | |||
60 | /* | ||
61 | * The maximum waiting time is about 128us. It is specific for stream I/O, | ||
62 | * such as ins. | ||
63 | * | ||
64 | * The fastest IO cycle time is about 390ns, but the worst case will wait | ||
65 | * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum burst | ||
66 | * cycles is 16. So, the maximum waiting time is about 128us under worst | ||
67 | * case. | ||
68 | * | ||
69 | * Choose 1300 as the maximum. | ||
70 | */ | ||
71 | #define LPC_MAX_WAITCNT 1300 | ||
72 | |||
73 | /* About 10us. This is specific for single IO operations, such as inb */ | ||
74 | #define LPC_PEROP_WAITCNT 100 | ||
75 | |||
76 | static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt) | ||
77 | { | ||
78 | u32 status; | ||
79 | |||
80 | do { | ||
81 | status = readl(mbase + LPC_REG_OP_STATUS); | ||
82 | if (status & LPC_REG_OP_STATUS_IDLE) | ||
83 | return (status & LPC_REG_OP_STATUS_FINISHED) ? 0 : -EIO; | ||
84 | ndelay(LPC_NSEC_PERWAIT); | ||
85 | } while (--waitcnt); | ||
86 | |||
87 | return -ETIME; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * hisi_lpc_target_in - trigger a series of LPC cycles for read operation | ||
92 | * @lpcdev: pointer to hisi lpc device | ||
93 | * @para: some parameters used to control the lpc I/O operations | ||
94 | * @addr: the lpc I/O target port address | ||
95 | * @buf: where the read back data is stored | ||
96 | * @opcnt: how many I/O operations required, i.e. data width | ||
97 | * | ||
98 | * Returns 0 on success, non-zero on fail. | ||
99 | */ | ||
100 | static int hisi_lpc_target_in(struct hisi_lpc_dev *lpcdev, | ||
101 | struct lpc_cycle_para *para, unsigned long addr, | ||
102 | unsigned char *buf, unsigned long opcnt) | ||
103 | { | ||
104 | unsigned int cmd_word; | ||
105 | unsigned int waitcnt; | ||
106 | unsigned long flags; | ||
107 | int ret; | ||
108 | |||
109 | if (!buf || !opcnt || !para || !para->csize || !lpcdev) | ||
110 | return -EINVAL; | ||
111 | |||
112 | cmd_word = 0; /* IO mode, Read */ | ||
113 | waitcnt = LPC_PEROP_WAITCNT; | ||
114 | if (!(para->opflags & FG_INCRADDR_LPC)) { | ||
115 | cmd_word |= LPC_REG_CMD_SAMEADDR; | ||
116 | waitcnt = LPC_MAX_WAITCNT; | ||
117 | } | ||
118 | |||
119 | /* whole operation must be atomic */ | ||
120 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | ||
121 | |||
122 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | ||
123 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | ||
124 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | ||
125 | |||
126 | writel(LPC_REG_STARTUP_SIGNAL_START, | ||
127 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | ||
128 | |||
129 | /* whether the operation is finished */ | ||
130 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | ||
131 | if (ret) { | ||
132 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | readsb(lpcdev->membase + LPC_REG_RDATA, buf, opcnt); | ||
137 | |||
138 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * hisi_lpc_target_out - trigger a series of LPC cycles for write operation | ||
145 | * @lpcdev: pointer to hisi lpc device | ||
146 | * @para: some parameters used to control the lpc I/O operations | ||
147 | * @addr: the lpc I/O target port address | ||
148 | * @buf: where the data to be written is stored | ||
149 | * @opcnt: how many I/O operations required, i.e. data width | ||
150 | * | ||
151 | * Returns 0 on success, non-zero on fail. | ||
152 | */ | ||
153 | static int hisi_lpc_target_out(struct hisi_lpc_dev *lpcdev, | ||
154 | struct lpc_cycle_para *para, unsigned long addr, | ||
155 | const unsigned char *buf, unsigned long opcnt) | ||
156 | { | ||
157 | unsigned int waitcnt; | ||
158 | unsigned long flags; | ||
159 | u32 cmd_word; | ||
160 | int ret; | ||
161 | |||
162 | if (!buf || !opcnt || !para || !lpcdev) | ||
163 | return -EINVAL; | ||
164 | |||
165 | /* default is increasing address */ | ||
166 | cmd_word = LPC_REG_CMD_OP; /* IO mode, write */ | ||
167 | waitcnt = LPC_PEROP_WAITCNT; | ||
168 | if (!(para->opflags & FG_INCRADDR_LPC)) { | ||
169 | cmd_word |= LPC_REG_CMD_SAMEADDR; | ||
170 | waitcnt = LPC_MAX_WAITCNT; | ||
171 | } | ||
172 | |||
173 | spin_lock_irqsave(&lpcdev->cycle_lock, flags); | ||
174 | |||
175 | writel_relaxed(opcnt, lpcdev->membase + LPC_REG_OP_LEN); | ||
176 | writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); | ||
177 | writel_relaxed(addr, lpcdev->membase + LPC_REG_ADDR); | ||
178 | |||
179 | writesb(lpcdev->membase + LPC_REG_WDATA, buf, opcnt); | ||
180 | |||
181 | writel(LPC_REG_STARTUP_SIGNAL_START, | ||
182 | lpcdev->membase + LPC_REG_STARTUP_SIGNAL); | ||
183 | |||
184 | /* whether the operation is finished */ | ||
185 | ret = wait_lpc_idle(lpcdev->membase, waitcnt); | ||
186 | |||
187 | spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); | ||
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static unsigned long hisi_lpc_pio_to_addr(struct hisi_lpc_dev *lpcdev, | ||
193 | unsigned long pio) | ||
194 | { | ||
195 | return pio - lpcdev->io_host->io_start + lpcdev->io_host->hw_start; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * hisi_lpc_comm_in - input the data in a single operation | ||
200 | * @hostdata: pointer to the device information relevant to LPC controller | ||
201 | * @pio: the target I/O port address | ||
202 | * @dwidth: the data length required to read from the target I/O port | ||
203 | * | ||
204 | * When success, data is returned. Otherwise, ~0 is returned. | ||
205 | */ | ||
206 | static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth) | ||
207 | { | ||
208 | struct hisi_lpc_dev *lpcdev = hostdata; | ||
209 | struct lpc_cycle_para iopara; | ||
210 | unsigned long addr; | ||
211 | u32 rd_data = 0; | ||
212 | int ret; | ||
213 | |||
214 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | ||
215 | return ~0; | ||
216 | |||
217 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | ||
218 | |||
219 | iopara.opflags = FG_INCRADDR_LPC; | ||
220 | iopara.csize = dwidth; | ||
221 | |||
222 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, | ||
223 | (unsigned char *)&rd_data, dwidth); | ||
224 | if (ret) | ||
225 | return ~0; | ||
226 | |||
227 | return le32_to_cpu(rd_data); | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * hisi_lpc_comm_out - output the data in a single operation | ||
232 | * @hostdata: pointer to the device information relevant to LPC controller | ||
233 | * @pio: the target I/O port address | ||
234 | * @val: a value to be output from caller, maximum is four bytes | ||
235 | * @dwidth: the data width required writing to the target I/O port | ||
236 | * | ||
237 | * This function corresponds to out(b,w,l) only. | ||
238 | */ | ||
239 | static void hisi_lpc_comm_out(void *hostdata, unsigned long pio, | ||
240 | u32 val, size_t dwidth) | ||
241 | { | ||
242 | struct hisi_lpc_dev *lpcdev = hostdata; | ||
243 | struct lpc_cycle_para iopara; | ||
244 | const unsigned char *buf; | ||
245 | unsigned long addr; | ||
246 | |||
247 | if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH) | ||
248 | return; | ||
249 | |||
250 | val = cpu_to_le32(val); | ||
251 | |||
252 | buf = (const unsigned char *)&val; | ||
253 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | ||
254 | |||
255 | iopara.opflags = FG_INCRADDR_LPC; | ||
256 | iopara.csize = dwidth; | ||
257 | |||
258 | hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth); | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * hisi_lpc_comm_ins - input the data in the buffer in multiple operations | ||
263 | * @hostdata: pointer to the device information relevant to LPC controller | ||
264 | * @pio: the target I/O port address | ||
265 | * @buffer: a buffer where read/input data bytes are stored | ||
266 | * @dwidth: the data width required writing to the target I/O port | ||
267 | * @count: how many data units whose length is dwidth will be read | ||
268 | * | ||
269 | * When success, the data read back is stored in buffer pointed by buffer. | ||
270 | * Returns 0 on success, -errno otherwise. | ||
271 | */ | ||
272 | static u32 hisi_lpc_comm_ins(void *hostdata, unsigned long pio, void *buffer, | ||
273 | size_t dwidth, unsigned int count) | ||
274 | { | ||
275 | struct hisi_lpc_dev *lpcdev = hostdata; | ||
276 | unsigned char *buf = buffer; | ||
277 | struct lpc_cycle_para iopara; | ||
278 | unsigned long addr; | ||
279 | |||
280 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | ||
281 | return -EINVAL; | ||
282 | |||
283 | iopara.opflags = 0; | ||
284 | if (dwidth > 1) | ||
285 | iopara.opflags |= FG_INCRADDR_LPC; | ||
286 | iopara.csize = dwidth; | ||
287 | |||
288 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | ||
289 | |||
290 | do { | ||
291 | int ret; | ||
292 | |||
293 | ret = hisi_lpc_target_in(lpcdev, &iopara, addr, buf, dwidth); | ||
294 | if (ret) | ||
295 | return ret; | ||
296 | buf += dwidth; | ||
297 | } while (--count); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * hisi_lpc_comm_outs - output the data in the buffer in multiple operations | ||
304 | * @hostdata: pointer to the device information relevant to LPC controller | ||
305 | * @pio: the target I/O port address | ||
306 | * @buffer: a buffer where write/output data bytes are stored | ||
307 | * @dwidth: the data width required writing to the target I/O port | ||
308 | * @count: how many data units whose length is dwidth will be written | ||
309 | */ | ||
310 | static void hisi_lpc_comm_outs(void *hostdata, unsigned long pio, | ||
311 | const void *buffer, size_t dwidth, | ||
312 | unsigned int count) | ||
313 | { | ||
314 | struct hisi_lpc_dev *lpcdev = hostdata; | ||
315 | struct lpc_cycle_para iopara; | ||
316 | const unsigned char *buf = buffer; | ||
317 | unsigned long addr; | ||
318 | |||
319 | if (!lpcdev || !buf || !count || !dwidth || dwidth > LPC_MAX_DWIDTH) | ||
320 | return; | ||
321 | |||
322 | iopara.opflags = 0; | ||
323 | if (dwidth > 1) | ||
324 | iopara.opflags |= FG_INCRADDR_LPC; | ||
325 | iopara.csize = dwidth; | ||
326 | |||
327 | addr = hisi_lpc_pio_to_addr(lpcdev, pio); | ||
328 | do { | ||
329 | if (hisi_lpc_target_out(lpcdev, &iopara, addr, buf, dwidth)) | ||
330 | break; | ||
331 | buf += dwidth; | ||
332 | } while (--count); | ||
333 | } | ||
334 | |||
335 | static const struct logic_pio_host_ops hisi_lpc_ops = { | ||
336 | .in = hisi_lpc_comm_in, | ||
337 | .out = hisi_lpc_comm_out, | ||
338 | .ins = hisi_lpc_comm_ins, | ||
339 | .outs = hisi_lpc_comm_outs, | ||
340 | }; | ||
341 | |||
342 | /* | ||
343 | * hisi_lpc_probe - the probe callback function for hisi lpc host, | ||
344 | * will finish all the initialization. | ||
345 | * @pdev: the platform device corresponding to hisi lpc host | ||
346 | * | ||
347 | * Returns 0 on success, non-zero on fail. | ||
348 | */ | ||
349 | static int hisi_lpc_probe(struct platform_device *pdev) | ||
350 | { | ||
351 | struct device *dev = &pdev->dev; | ||
352 | struct acpi_device *acpi_device = ACPI_COMPANION(dev); | ||
353 | struct logic_pio_hwaddr *range; | ||
354 | struct hisi_lpc_dev *lpcdev; | ||
355 | resource_size_t io_end; | ||
356 | struct resource *res; | ||
357 | int ret; | ||
358 | |||
359 | lpcdev = devm_kzalloc(dev, sizeof(*lpcdev), GFP_KERNEL); | ||
360 | if (!lpcdev) | ||
361 | return -ENOMEM; | ||
362 | |||
363 | spin_lock_init(&lpcdev->cycle_lock); | ||
364 | |||
365 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
366 | lpcdev->membase = devm_ioremap_resource(dev, res); | ||
367 | if (IS_ERR(lpcdev->membase)) | ||
368 | return PTR_ERR(lpcdev->membase); | ||
369 | |||
370 | range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); | ||
371 | if (!range) | ||
372 | return -ENOMEM; | ||
373 | |||
374 | range->fwnode = dev->fwnode; | ||
375 | range->flags = LOGIC_PIO_INDIRECT; | ||
376 | range->size = PIO_INDIRECT_SIZE; | ||
377 | |||
378 | ret = logic_pio_register_range(range); | ||
379 | if (ret) { | ||
380 | dev_err(dev, "register IO range failed (%d)!\n", ret); | ||
381 | return ret; | ||
382 | } | ||
383 | lpcdev->io_host = range; | ||
384 | |||
385 | /* register the LPC host PIO resources */ | ||
386 | if (!acpi_device) { | ||
387 | ret = of_platform_populate(dev->of_node, NULL, NULL, dev); | ||
388 | if (ret) | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | lpcdev->io_host->hostdata = lpcdev; | ||
393 | lpcdev->io_host->ops = &hisi_lpc_ops; | ||
394 | |||
395 | io_end = lpcdev->io_host->io_start + lpcdev->io_host->size; | ||
396 | dev_info(dev, "registered range [%pa - %pa]\n", | ||
397 | &lpcdev->io_host->io_start, &io_end); | ||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static const struct of_device_id hisi_lpc_of_match[] = { | ||
403 | { .compatible = "hisilicon,hip06-lpc", }, | ||
404 | { .compatible = "hisilicon,hip07-lpc", }, | ||
405 | {} | ||
406 | }; | ||
407 | |||
408 | static struct platform_driver hisi_lpc_driver = { | ||
409 | .driver = { | ||
410 | .name = DRV_NAME, | ||
411 | .of_match_table = hisi_lpc_of_match, | ||
412 | }, | ||
413 | .probe = hisi_lpc_probe, | ||
414 | }; | ||
415 | builtin_platform_driver(hisi_lpc_driver); | ||