1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
4 | * |
5 | * GPIO and pin control functions on this SOC are handled by the "TLMM" |
6 | * device. The driver which controls this device is pinctrl-msm.c. Each |
7 | * SOC with a TLMM is expected to create a client driver that registers |
8 | * with pinctrl-msm.c. This means that all TLMM drivers are pin control |
9 | * drivers. |
10 | * |
11 | * This pin control driver is intended to be used only an ACPI-enabled |
12 | * system. As such, UEFI will handle all pin control configuration, so |
13 | * this driver does not provide pin control functions. It is effectively |
14 | * a GPIO-only driver. The alternative is to duplicate the GPIO code of |
15 | * pinctrl-msm.c into another driver. |
16 | */ |
17 | |
18 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/pinctrl/pinctrl.h> |
21 | #include <linux/acpi.h> |
22 | |
23 | #include "pinctrl-msm.h" |
24 | |
25 | /* A maximum of 256 allows us to use a u8 array to hold the GPIO numbers */ |
26 | #define MAX_GPIOS 256 |
27 | |
28 | /* maximum size of each gpio name (enough room for "gpioXXX" + null) */ |
29 | #define NAME_SIZE 8 |
30 | |
31 | static int qdf2xxx_pinctrl_probe(struct platform_device *pdev) |
32 | { |
33 | struct msm_pinctrl_soc_data *pinctrl; |
34 | struct pinctrl_pin_desc *pins; |
35 | struct msm_pingroup *groups; |
36 | char (*names)[NAME_SIZE]; |
37 | unsigned int i; |
38 | u32 num_gpios; |
39 | unsigned int avail_gpios; /* The number of GPIOs we support */ |
40 | u8 gpios[MAX_GPIOS]; /* An array of supported GPIOs */ |
41 | int ret; |
42 | |
43 | /* Query the number of GPIOs from ACPI */ |
44 | ret = device_property_read_u32(dev: &pdev->dev, propname: "num-gpios" , val: &num_gpios); |
45 | if (ret < 0) { |
46 | dev_err(&pdev->dev, "missing 'num-gpios' property\n" ); |
47 | return ret; |
48 | } |
49 | if (!num_gpios || num_gpios > MAX_GPIOS) { |
50 | dev_err(&pdev->dev, "invalid 'num-gpios' property\n" ); |
51 | return -ENODEV; |
52 | } |
53 | |
54 | /* The number of GPIOs in the approved list */ |
55 | ret = device_property_count_u8(dev: &pdev->dev, propname: "gpios" ); |
56 | if (ret < 0) { |
57 | dev_err(&pdev->dev, "missing 'gpios' property\n" ); |
58 | return ret; |
59 | } |
60 | /* |
61 | * The number of available GPIOs should be non-zero, and no |
62 | * more than the total number of GPIOS. |
63 | */ |
64 | if (!ret || ret > num_gpios) { |
65 | dev_err(&pdev->dev, "invalid 'gpios' property\n" ); |
66 | return -ENODEV; |
67 | } |
68 | avail_gpios = ret; |
69 | |
70 | ret = device_property_read_u8_array(dev: &pdev->dev, propname: "gpios" , val: gpios, |
71 | nval: avail_gpios); |
72 | if (ret < 0) { |
73 | dev_err(&pdev->dev, "could not read list of GPIOs\n" ); |
74 | return ret; |
75 | } |
76 | |
77 | pinctrl = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pinctrl), GFP_KERNEL); |
78 | pins = devm_kcalloc(dev: &pdev->dev, n: num_gpios, |
79 | size: sizeof(struct pinctrl_pin_desc), GFP_KERNEL); |
80 | groups = devm_kcalloc(dev: &pdev->dev, n: num_gpios, |
81 | size: sizeof(struct msm_pingroup), GFP_KERNEL); |
82 | names = devm_kcalloc(dev: &pdev->dev, n: avail_gpios, NAME_SIZE, GFP_KERNEL); |
83 | |
84 | if (!pinctrl || !pins || !groups || !names) |
85 | return -ENOMEM; |
86 | |
87 | /* |
88 | * Initialize the array. GPIOs not listed in the 'gpios' array |
89 | * still need a number, but nothing else. |
90 | */ |
91 | for (i = 0; i < num_gpios; i++) { |
92 | pins[i].number = i; |
93 | groups[i].grp.pins = &pins[i].number; |
94 | } |
95 | |
96 | /* Populate the entries that are meant to be exposed as GPIOs. */ |
97 | for (i = 0; i < avail_gpios; i++) { |
98 | unsigned int gpio = gpios[i]; |
99 | |
100 | groups[gpio].grp.npins = 1; |
101 | snprintf(buf: names[i], NAME_SIZE, fmt: "gpio%u" , gpio); |
102 | pins[gpio].name = names[i]; |
103 | groups[gpio].grp.name = names[i]; |
104 | |
105 | groups[gpio].ctl_reg = 0x10000 * gpio; |
106 | groups[gpio].io_reg = 0x04 + 0x10000 * gpio; |
107 | groups[gpio].intr_cfg_reg = 0x08 + 0x10000 * gpio; |
108 | groups[gpio].intr_status_reg = 0x0c + 0x10000 * gpio; |
109 | groups[gpio].intr_target_reg = 0x08 + 0x10000 * gpio; |
110 | |
111 | groups[gpio].mux_bit = 2; |
112 | groups[gpio].pull_bit = 0; |
113 | groups[gpio].drv_bit = 6; |
114 | groups[gpio].oe_bit = 9; |
115 | groups[gpio].in_bit = 0; |
116 | groups[gpio].out_bit = 1; |
117 | groups[gpio].intr_enable_bit = 0; |
118 | groups[gpio].intr_status_bit = 0; |
119 | groups[gpio].intr_target_bit = 5; |
120 | groups[gpio].intr_target_kpss_val = 1; |
121 | groups[gpio].intr_raw_status_bit = 4; |
122 | groups[gpio].intr_polarity_bit = 1; |
123 | groups[gpio].intr_detection_bit = 2; |
124 | groups[gpio].intr_detection_width = 2; |
125 | } |
126 | |
127 | pinctrl->pins = pins; |
128 | pinctrl->groups = groups; |
129 | pinctrl->npins = num_gpios; |
130 | pinctrl->ngroups = num_gpios; |
131 | pinctrl->ngpios = num_gpios; |
132 | |
133 | return msm_pinctrl_probe(pdev, soc_data: pinctrl); |
134 | } |
135 | |
136 | static const struct acpi_device_id qdf2xxx_acpi_ids[] = { |
137 | {"QCOM8002" }, |
138 | {}, |
139 | }; |
140 | MODULE_DEVICE_TABLE(acpi, qdf2xxx_acpi_ids); |
141 | |
142 | static struct platform_driver qdf2xxx_pinctrl_driver = { |
143 | .driver = { |
144 | .name = "qdf2xxx-pinctrl" , |
145 | .acpi_match_table = qdf2xxx_acpi_ids, |
146 | }, |
147 | .probe = qdf2xxx_pinctrl_probe, |
148 | .remove_new = msm_pinctrl_remove, |
149 | }; |
150 | |
151 | static int __init qdf2xxx_pinctrl_init(void) |
152 | { |
153 | return platform_driver_register(&qdf2xxx_pinctrl_driver); |
154 | } |
155 | arch_initcall(qdf2xxx_pinctrl_init); |
156 | |
157 | static void __exit qdf2xxx_pinctrl_exit(void) |
158 | { |
159 | platform_driver_unregister(&qdf2xxx_pinctrl_driver); |
160 | } |
161 | module_exit(qdf2xxx_pinctrl_exit); |
162 | |
163 | MODULE_DESCRIPTION("Qualcomm Technologies QDF2xxx pin control driver" ); |
164 | MODULE_LICENSE("GPL v2" ); |
165 | |