Skip to content

Commit 357c9b7

Browse files
GuEe-GUIRbb666
authored andcommitted
[dm][pin][pinctrl] add new driver
1. ARM PL061 GPIO 2. Single Pinctrl Signed-off-by: GuEe-GUI <[email protected]>
1 parent b5ea922 commit 357c9b7

File tree

6 files changed

+759
-8
lines changed

6 files changed

+759
-8
lines changed

components/drivers/pin/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ menuconfig RT_USING_PIN
22
bool "Using Generic GPIO device drivers"
33
default y
44

5+
config RT_PIN_PL061
6+
bool "ARM PL061"
7+
depends on RT_USING_DM
8+
depends on RT_USING_PIN
9+
default n
10+
511
if RT_USING_DM && RT_USING_PIN
612
osource "$(SOC_DM_PIN_DIR)/Kconfig"
713
endif

components/drivers/pin/SConscript

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ if GetDepend(['RT_USING_DM']):
1616
if GetDepend(['RT_USING_OFW']):
1717
src += ['dev_pin_ofw.c']
1818

19+
if GetDepend(['RT_PIN_PL061']):
20+
src += ['pin-pl061.c']
21+
1922
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
2023

2124
Return('group')

components/drivers/pin/pin-pl061.c

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
/*
2+
* Copyright (c) 2006-2022, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2022-11-26 GuEe-GUI first version
9+
*/
10+
11+
#include <rthw.h>
12+
#include <rtthread.h>
13+
#include <rtdevice.h>
14+
15+
#include "dev_pin_dm.h"
16+
17+
#define PL061_DIR 0x400
18+
#define PL061_IS 0x404
19+
#define PL061_IBE 0x408
20+
#define PL061_IEV 0x40c
21+
#define PL061_IE 0x410
22+
#define PL061_RIS 0x414
23+
#define PL061_MIS 0x418
24+
#define PL061_IC 0x41c
25+
26+
#define PL061_GPIO_NR 8
27+
28+
struct pl061
29+
{
30+
struct rt_device_pin parent;
31+
32+
int irq;
33+
void *base;
34+
35+
struct rt_clk *pclk;
36+
struct rt_spinlock spinlock;
37+
};
38+
39+
#define raw_to_pl061(raw) rt_container_of(raw, struct pl061, parent)
40+
41+
rt_inline rt_uint8_t pl061_read(struct pl061 *pl061, int offset)
42+
{
43+
return HWREG8(pl061->base + offset);
44+
}
45+
46+
rt_inline void pl061_write(struct pl061 *pl061, int offset, rt_uint8_t value)
47+
{
48+
HWREG8(pl061->base + offset) = value;
49+
}
50+
51+
static void pl061_isr(int irqno, void *param)
52+
{
53+
rt_uint8_t mask = 0;
54+
rt_ubase_t pending, level;
55+
struct pl061 *pl061 = (struct pl061 *)param;
56+
57+
level = rt_spin_lock_irqsave(&pl061->spinlock);
58+
59+
pending = pl061_read(pl061, PL061_MIS);
60+
61+
rt_spin_unlock_irqrestore(&pl061->spinlock, level);
62+
63+
if (pending)
64+
{
65+
for (int pin = 0; pin < PL061_GPIO_NR; ++pin)
66+
{
67+
if (pending & RT_BIT(pin))
68+
{
69+
mask |= RT_BIT(pin);
70+
71+
pin_pic_handle_isr(&pl061->parent, pin);
72+
}
73+
}
74+
75+
level = rt_spin_lock_irqsave(&pl061->spinlock);
76+
77+
pl061_write(pl061, PL061_IC, mask);
78+
79+
rt_spin_unlock_irqrestore(&pl061->spinlock, level);
80+
}
81+
}
82+
83+
static void pl061_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
84+
{
85+
struct pl061 *pl061 = raw_to_pl061(device);
86+
87+
if (pin >= 0 && pin < PL061_GPIO_NR)
88+
{
89+
rt_base_t level = rt_spin_lock_irqsave(&pl061->spinlock);
90+
91+
switch (mode)
92+
{
93+
case PIN_MODE_OUTPUT:
94+
95+
pl061_write(pl061, RT_BIT(pin + 2), 1 << pin);
96+
pl061_write(pl061, PL061_DIR, pl061_read(pl061, PL061_DIR) | RT_BIT(pin));
97+
98+
/*
99+
* gpio value is set again, because pl061 doesn't allow to set value
100+
* of a gpio pin before configuring it in OUT mode.
101+
*/
102+
pl061_write(pl061, RT_BIT(pin + 2), 1 << pin);
103+
104+
break;
105+
106+
case PIN_MODE_INPUT:
107+
108+
pl061_write(pl061, PL061_DIR, pl061_read(pl061, PL061_DIR) & ~RT_BIT(pin));
109+
110+
break;
111+
112+
default:
113+
break;
114+
}
115+
116+
rt_spin_unlock_irqrestore(&pl061->spinlock, level);
117+
}
118+
}
119+
120+
static void pl061_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
121+
{
122+
struct pl061 *pl061 = raw_to_pl061(device);
123+
124+
if (pin >= 0 && pin < PL061_GPIO_NR)
125+
{
126+
pl061_write(pl061, RT_BIT(pin + 2), !!value << pin);
127+
}
128+
}
129+
130+
static rt_ssize_t pl061_pin_read(struct rt_device *device, rt_base_t pin)
131+
{
132+
rt_int8_t value = -RT_EINVAL;
133+
struct pl061 *pl061 = raw_to_pl061(device);
134+
135+
if (pin >= 0 && pin < PL061_GPIO_NR)
136+
{
137+
value = !!pl061_read(pl061, RT_BIT(pin + 2));
138+
}
139+
140+
return value;
141+
}
142+
143+
static rt_err_t pl061_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
144+
{
145+
rt_err_t err = RT_EOK;
146+
struct pl061 *pl061 = raw_to_pl061(device);
147+
148+
if (pin >= 0 && pin < PL061_GPIO_NR)
149+
{
150+
rt_uint8_t gpioie, mask = RT_BIT(pin);
151+
rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock);
152+
153+
if (enabled)
154+
{
155+
gpioie = pl061_read(pl061, PL061_IE) | mask;
156+
}
157+
else
158+
{
159+
gpioie = pl061_read(pl061, PL061_IE) & ~mask;
160+
}
161+
162+
pl061_write(pl061, PL061_IE, gpioie);
163+
164+
rt_spin_unlock_irqrestore(&pl061->spinlock, level);
165+
}
166+
else
167+
{
168+
err = -RT_EINVAL;
169+
}
170+
171+
return err;
172+
}
173+
174+
static rt_err_t pl061_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
175+
{
176+
rt_err_t err = RT_EOK;
177+
struct pl061 *pl061 = raw_to_pl061(device);
178+
179+
if (pin >= 0 && pin < PL061_GPIO_NR)
180+
{
181+
rt_uint8_t gpiois, gpioibe, gpioiev, bit = RT_BIT(pin);
182+
rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock);
183+
184+
gpioiev = pl061_read(pl061, PL061_IEV);
185+
gpiois = pl061_read(pl061, PL061_IS);
186+
gpioibe = pl061_read(pl061, PL061_IBE);
187+
188+
if (mode == PIN_IRQ_MODE_HIGH_LEVEL || mode == PIN_IRQ_MODE_LOW_LEVEL)
189+
{
190+
rt_bool_t polarity = (mode == PIN_IRQ_MODE_HIGH_LEVEL);
191+
192+
/* Disable edge detection */
193+
gpioibe &= ~bit;
194+
/* Enable level detection */
195+
gpiois |= bit;
196+
197+
/* Select polarity */
198+
if (polarity)
199+
{
200+
gpioiev |= bit;
201+
}
202+
else
203+
{
204+
gpioiev &= ~bit;
205+
}
206+
}
207+
else if (mode == PIN_IRQ_MODE_RISING_FALLING)
208+
{
209+
/* Disable level detection */
210+
gpiois &= ~bit;
211+
/* Select both edges, setting this makes PL061_EV be ignored */
212+
gpioibe |= bit;
213+
}
214+
else if (mode == PIN_IRQ_MODE_RISING || mode == PIN_IRQ_MODE_FALLING)
215+
{
216+
rt_bool_t rising = (mode == PIN_IRQ_MODE_RISING);
217+
218+
/* Disable level detection */
219+
gpiois &= ~bit;
220+
/* Clear detection on both edges */
221+
gpioibe &= ~bit;
222+
223+
/* Select edge */
224+
if (rising)
225+
{
226+
gpioiev |= bit;
227+
}
228+
else
229+
{
230+
gpioiev &= ~bit;
231+
}
232+
}
233+
else
234+
{
235+
/* No trigger: disable everything */
236+
gpiois &= ~bit;
237+
gpioibe &= ~bit;
238+
gpioiev &= ~bit;
239+
}
240+
241+
pl061_write(pl061, PL061_IS, gpiois);
242+
pl061_write(pl061, PL061_IBE, gpioibe);
243+
pl061_write(pl061, PL061_IEV, gpioiev);
244+
245+
rt_spin_unlock_irqrestore(&pl061->spinlock, level);
246+
}
247+
else
248+
{
249+
err = -RT_EINVAL;
250+
}
251+
252+
return err;
253+
}
254+
255+
static const struct rt_pin_ops pl061_pin_ops =
256+
{
257+
.pin_mode = pl061_pin_mode,
258+
.pin_write = pl061_pin_write,
259+
.pin_read = pl061_pin_read,
260+
.pin_irq_enable = pl061_pin_irq_enable,
261+
.pin_irq_mode = pl061_pin_irq_mode,
262+
};
263+
264+
static rt_err_t pl061_probe(struct rt_platform_device *pdev)
265+
{
266+
rt_err_t err;
267+
struct rt_device *dev = &pdev->parent;
268+
struct pl061 *pl061 = rt_calloc(1, sizeof(*pl061));
269+
270+
if (!pl061)
271+
{
272+
return -RT_ENOMEM;
273+
}
274+
275+
pl061->base = rt_dm_dev_iomap(dev, 0);
276+
277+
if (!pl061->base)
278+
{
279+
err = -RT_EIO;
280+
281+
goto _fail;
282+
}
283+
284+
pl061->irq = rt_dm_dev_get_irq(dev, 0);
285+
286+
if (pl061->irq < 0)
287+
{
288+
err = pl061->irq;
289+
290+
goto _fail;
291+
}
292+
293+
pl061->pclk = rt_clk_get_by_name(dev, "apb_pclk");
294+
295+
if (rt_is_err(pl061->pclk))
296+
{
297+
err = rt_ptr_err(pl061->pclk);
298+
299+
goto _fail;
300+
}
301+
302+
if ((err = rt_clk_prepare_enable(pl061->pclk)))
303+
{
304+
goto _fail;
305+
}
306+
307+
rt_dm_dev_bind_fwdata(dev, RT_NULL, &pl061->parent);
308+
309+
rt_spin_lock_init(&pl061->spinlock);
310+
311+
pl061->parent.ops = &pl061_pin_ops;
312+
pin_api_init(&pl061->parent, PL061_GPIO_NR);
313+
pin_pic_init(&pl061->parent, pl061->irq);
314+
315+
rt_hw_interrupt_install(pl061->irq, pl061_isr, pl061, "gpio-pl061");
316+
rt_hw_interrupt_umask(pl061->irq);
317+
318+
return RT_EOK;
319+
320+
_fail:
321+
if (pl061->base)
322+
{
323+
rt_iounmap(pl061->base);
324+
}
325+
326+
if (!rt_is_err_or_null(pl061->pclk))
327+
{
328+
rt_clk_disable_unprepare(pl061->pclk);
329+
rt_clk_put(pl061->pclk);
330+
}
331+
332+
rt_free(pl061);
333+
334+
return err;
335+
}
336+
337+
static const struct rt_ofw_node_id pl061_ofw_ids[] =
338+
{
339+
{ .compatible = "arm,pl061" },
340+
{ /* sentinel */ }
341+
};
342+
343+
static struct rt_platform_driver pl061_driver =
344+
{
345+
.name = "pin-pl061",
346+
.ids = pl061_ofw_ids,
347+
348+
.probe = pl061_probe,
349+
};
350+
351+
static int pl061_drv_register(void)
352+
{
353+
rt_platform_driver_register(&pl061_driver);
354+
355+
return 0;
356+
}
357+
INIT_SUBSYS_EXPORT(pl061_drv_register);

components/drivers/pinctrl/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ menuconfig RT_USING_PINCTRL
44
depends on RT_USING_PIN
55
default n
66

7+
config RT_PINCTRL_SINGLE
8+
bool "Single Pinctrl driver"
9+
depends on RT_USING_PINCTRL
10+
default n
11+
712
if RT_USING_PINCTRL
813
osource "$(SOC_DM_PINCTRL_DIR)/Kconfig"
914
endif

0 commit comments

Comments
 (0)