Skip to content

Commit c5860e4

Browse files
committed
pinctrl: intel: Add a generic Intel pin control platform driver
New generations of Intel platforms will provide better description of the pin control devices in the ACPI tables. Hence, we may provide a generic pin control platform driver to cover all of them. Currently the following Intel SoCs / platforms require this to be functional: - Lunar Lake Acked-by: Mika Westerberg <[email protected]> Signed-off-by: Andy Shevchenko <[email protected]>
1 parent 4c51ea9 commit c5860e4

File tree

3 files changed

+236
-0
lines changed

3 files changed

+236
-0
lines changed

drivers/pinctrl/intel/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ config PINCTRL_INTEL
3737
select GPIOLIB
3838
select GPIOLIB_IRQCHIP
3939

40+
config PINCTRL_INTEL_PLATFORM
41+
tristate "Intel pinctrl and GPIO platform driver"
42+
depends on ACPI
43+
select PINCTRL_INTEL
44+
help
45+
This pinctrl driver provides an interface that allows configuring
46+
of Intel PCH pins and using them as GPIOs. Currently the following
47+
Intel SoCs / platforms require this to be functional:
48+
- Lunar Lake
49+
4050
config PINCTRL_ALDERLAKE
4151
tristate "Intel Alder Lake pinctrl and GPIO driver"
4252
select PINCTRL_INTEL

drivers/pinctrl/intel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_TANGIER) += pinctrl-tangier.o
88
obj-$(CONFIG_PINCTRL_MERRIFIELD) += pinctrl-merrifield.o
99
obj-$(CONFIG_PINCTRL_MOOREFIELD) += pinctrl-moorefield.o
1010
obj-$(CONFIG_PINCTRL_INTEL) += pinctrl-intel.o
11+
obj-$(CONFIG_PINCTRL_INTEL_PLATFORM) += pinctrl-intel-platform.o
1112
obj-$(CONFIG_PINCTRL_ALDERLAKE) += pinctrl-alderlake.o
1213
obj-$(CONFIG_PINCTRL_BROXTON) += pinctrl-broxton.o
1314
obj-$(CONFIG_PINCTRL_CANNONLAKE) += pinctrl-cannonlake.o
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Intel PCH pinctrl/GPIO driver
4+
*
5+
* Copyright (C) 2021-2023, Intel Corporation
6+
* Author: Andy Shevchenko <[email protected]>
7+
*/
8+
9+
#include <linux/mod_devicetable.h>
10+
#include <linux/module.h>
11+
#include <linux/platform_device.h>
12+
#include <linux/pm.h>
13+
#include <linux/property.h>
14+
#include <linux/string_helpers.h>
15+
16+
#include <linux/pinctrl/pinctrl.h>
17+
18+
#include "pinctrl-intel.h"
19+
20+
struct intel_platform_pins {
21+
struct pinctrl_pin_desc *pins;
22+
size_t npins;
23+
};
24+
25+
static int intel_platform_pinctrl_prepare_pins(struct device *dev, size_t base,
26+
const char *name, u32 size,
27+
struct intel_platform_pins *pins)
28+
{
29+
struct pinctrl_pin_desc *descs;
30+
char **pin_names;
31+
unsigned int i;
32+
33+
pin_names = devm_kasprintf_strarray(dev, name, size);
34+
if (IS_ERR(pin_names))
35+
return PTR_ERR(pin_names);
36+
37+
descs = devm_krealloc_array(dev, pins->pins, base + size, sizeof(*descs), GFP_KERNEL);
38+
if (!descs)
39+
return -ENOMEM;
40+
41+
for (i = 0; i < size; i++) {
42+
unsigned int pin_number = base + i;
43+
char *pin_name = pin_names[i];
44+
struct pinctrl_pin_desc *desc;
45+
46+
/* Unify delimiter for pin name */
47+
strreplace(pin_name, '-', '_');
48+
49+
desc = &descs[pin_number];
50+
desc->number = pin_number;
51+
desc->name = pin_name;
52+
}
53+
54+
pins->pins = descs;
55+
pins->npins = base + size;
56+
57+
return 0;
58+
}
59+
60+
static int intel_platform_pinctrl_prepare_group(struct device *dev,
61+
struct fwnode_handle *child,
62+
struct intel_padgroup *gpp,
63+
struct intel_platform_pins *pins)
64+
{
65+
size_t base = pins->npins;
66+
const char *name;
67+
u32 size;
68+
int ret;
69+
70+
ret = fwnode_property_read_string(child, "intc-gpio-group-name", &name);
71+
if (ret)
72+
return ret;
73+
74+
ret = fwnode_property_read_u32(child, "intc-gpio-pad-count", &size);
75+
if (ret)
76+
return ret;
77+
78+
ret = intel_platform_pinctrl_prepare_pins(dev, base, name, size, pins);
79+
if (ret)
80+
return ret;
81+
82+
gpp->base = base;
83+
gpp->size = size;
84+
gpp->gpio_base = INTEL_GPIO_BASE_MATCH;
85+
86+
return 0;
87+
}
88+
89+
static int intel_platform_pinctrl_prepare_community(struct device *dev,
90+
struct intel_community *community,
91+
struct intel_platform_pins *pins)
92+
{
93+
struct fwnode_handle *child;
94+
struct intel_padgroup *gpps;
95+
unsigned int group;
96+
size_t ngpps;
97+
u32 offset;
98+
int ret;
99+
100+
ret = device_property_read_u32(dev, "intc-gpio-pad-ownership-offset", &offset);
101+
if (ret)
102+
return ret;
103+
community->padown_offset = offset;
104+
105+
ret = device_property_read_u32(dev, "intc-gpio-pad-configuration-lock-offset", &offset);
106+
if (ret)
107+
return ret;
108+
community->padcfglock_offset = offset;
109+
110+
ret = device_property_read_u32(dev, "intc-gpio-host-software-pad-ownership-offset", &offset);
111+
if (ret)
112+
return ret;
113+
community->hostown_offset = offset;
114+
115+
ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-status-offset", &offset);
116+
if (ret)
117+
return ret;
118+
community->is_offset = offset;
119+
120+
ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-enable-offset", &offset);
121+
if (ret)
122+
return ret;
123+
community->ie_offset = offset;
124+
125+
ngpps = device_get_child_node_count(dev);
126+
if (!ngpps)
127+
return -ENODEV;
128+
129+
gpps = devm_kcalloc(dev, ngpps, sizeof(*gpps), GFP_KERNEL);
130+
if (!gpps)
131+
return -ENOMEM;
132+
133+
group = 0;
134+
device_for_each_child_node(dev, child) {
135+
struct intel_padgroup *gpp = &gpps[group];
136+
137+
gpp->reg_num = group;
138+
139+
ret = intel_platform_pinctrl_prepare_group(dev, child, gpp, pins);
140+
if (ret)
141+
return ret;
142+
143+
group++;
144+
}
145+
146+
community->ngpps = ngpps;
147+
community->gpps = gpps;
148+
149+
return 0;
150+
}
151+
152+
static int intel_platform_pinctrl_prepare_soc_data(struct device *dev,
153+
struct intel_pinctrl_soc_data *data)
154+
{
155+
struct intel_platform_pins pins = {};
156+
struct intel_community *communities;
157+
size_t ncommunities;
158+
unsigned int i;
159+
int ret;
160+
161+
/* Version 1.0 of the specification assumes only a single community per device node */
162+
ncommunities = 1,
163+
communities = devm_kcalloc(dev, ncommunities, sizeof(*communities), GFP_KERNEL);
164+
if (!communities)
165+
return -ENOMEM;
166+
167+
for (i = 0; i < ncommunities; i++) {
168+
struct intel_community *community = &communities[i];
169+
170+
community->barno = i;
171+
community->pin_base = pins.npins;
172+
173+
ret = intel_platform_pinctrl_prepare_community(dev, community, &pins);
174+
if (ret)
175+
return ret;
176+
177+
community->npins = pins.npins - community->pin_base;
178+
}
179+
180+
data->ncommunities = ncommunities;
181+
data->communities = communities;
182+
183+
data->npins = pins.npins;
184+
data->pins = pins.pins;
185+
186+
return 0;
187+
}
188+
189+
static int intel_platform_pinctrl_probe(struct platform_device *pdev)
190+
{
191+
struct intel_pinctrl_soc_data *data;
192+
struct device *dev = &pdev->dev;
193+
int ret;
194+
195+
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
196+
if (!data)
197+
return -ENOMEM;
198+
199+
ret = intel_platform_pinctrl_prepare_soc_data(dev, data);
200+
if (ret)
201+
return ret;
202+
203+
return intel_pinctrl_probe(pdev, data);
204+
}
205+
206+
static const struct acpi_device_id intel_platform_pinctrl_acpi_match[] = {
207+
{ "INTC105F" },
208+
{ }
209+
};
210+
MODULE_DEVICE_TABLE(acpi, intel_platform_pinctrl_acpi_match);
211+
212+
static struct platform_driver intel_platform_pinctrl_driver = {
213+
.probe = intel_platform_pinctrl_probe,
214+
.driver = {
215+
.name = "intel-pinctrl",
216+
.acpi_match_table = intel_platform_pinctrl_acpi_match,
217+
.pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
218+
},
219+
};
220+
module_platform_driver(intel_platform_pinctrl_driver);
221+
222+
MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
223+
MODULE_DESCRIPTION("Intel PCH pinctrl/GPIO driver");
224+
MODULE_LICENSE("GPL v2");
225+
MODULE_IMPORT_NS(PINCTRL_INTEL);

0 commit comments

Comments
 (0)