xref: /linux/drivers/gpio/gpiolib-kunit.c (revision 88b8c6ae2ccb3ef9dbb04c8e13a4d1a98c42e922)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
4  */
5 
6 #include <linux/fwnode.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/gpio/driver.h>
9 #include <linux/gpio/machine.h>
10 #include <linux/gpio/property.h>
11 #include <linux/notifier.h>
12 #include <linux/platform_device.h>
13 #include <linux/property.h>
14 
15 #include <kunit/platform_device.h>
16 #include <kunit/test.h>
17 
18 #define GPIO_TEST_PROVIDER		"gpio-test-provider"
19 #define GPIO_SWNODE_TEST_CONSUMER	"gpio-swnode-test-consumer"
20 #define GPIO_UNBIND_TEST_CONSUMER	"gpio-unbind-test-consumer"
21 
22 static int gpio_test_provider_get_direction(struct gpio_chip *gc, unsigned int offset)
23 {
24 	return GPIO_LINE_DIRECTION_OUT;
25 }
26 
27 static int gpio_test_provider_set(struct gpio_chip *gc, unsigned int offset, int value)
28 {
29 	return 0;
30 }
31 
32 static int gpio_test_provider_probe(struct platform_device *pdev)
33 {
34 	struct device *dev = &pdev->dev;
35 	struct gpio_chip *gc;
36 
37 	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
38 	if (!gc)
39 		return -ENOMEM;
40 
41 	gc->base = -1;
42 	gc->ngpio = 4;
43 	gc->label = "gpio-swnode-consumer-test-device";
44 	gc->parent = dev;
45 	gc->owner = THIS_MODULE;
46 
47 	gc->get_direction = gpio_test_provider_get_direction;
48 	gc->set = gpio_test_provider_set;
49 
50 	return devm_gpiochip_add_data(dev, gc, NULL);
51 }
52 
53 static struct platform_driver gpio_test_provider_driver = {
54 	.probe = gpio_test_provider_probe,
55 	.driver = {
56 		.name = GPIO_TEST_PROVIDER,
57 	},
58 };
59 
60 static const struct software_node gpio_test_provider_swnode = {
61 	.name = "gpio-test-provider-primary",
62 };
63 
64 struct gpio_swnode_consumer_pdata {
65 	bool gpio_ok;
66 };
67 
68 static const struct gpio_swnode_consumer_pdata gpio_swnode_pdata_template = {
69 	.gpio_ok = false,
70 };
71 
72 static int gpio_swnode_consumer_probe(struct platform_device *pdev)
73 {
74 	struct device *dev = &pdev->dev;
75 	struct gpio_swnode_consumer_pdata *pdata = dev_get_platdata(dev);
76 	struct gpio_desc *desc;
77 
78 	desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
79 	if (IS_ERR(desc))
80 		return PTR_ERR(desc);
81 
82 	pdata->gpio_ok = true;
83 
84 	return 0;
85 }
86 
87 static struct platform_driver gpio_swnode_consumer_driver = {
88 	.probe = gpio_swnode_consumer_probe,
89 	.driver = {
90 		.name = GPIO_SWNODE_TEST_CONSUMER,
91 	},
92 };
93 
94 static void gpio_swnode_lookup_by_primary(struct kunit *test)
95 {
96 	struct gpio_swnode_consumer_pdata *pdata;
97 	struct platform_device_info pdevinfo;
98 	struct property_entry properties[2];
99 	struct platform_device *pdev;
100 	bool bound = false;
101 	int ret;
102 
103 	ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
104 	KUNIT_ASSERT_EQ(test, ret, 0);
105 
106 	ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
107 	KUNIT_ASSERT_EQ(test, ret, 0);
108 
109 	pdevinfo = (struct platform_device_info){
110 		.name = GPIO_TEST_PROVIDER,
111 		.id = PLATFORM_DEVID_NONE,
112 		.swnode = &gpio_test_provider_swnode,
113 	};
114 
115 	pdev = kunit_platform_device_register_full(test, &pdevinfo);
116 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
117 
118 	properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
119 					    &gpio_test_provider_swnode,
120 					    0, GPIO_ACTIVE_HIGH);
121 	properties[1] = (struct property_entry){ };
122 
123 	pdevinfo = (struct platform_device_info){
124 		.name = GPIO_SWNODE_TEST_CONSUMER,
125 		.id = PLATFORM_DEVID_NONE,
126 		.data = &gpio_swnode_pdata_template,
127 		.size_data = sizeof(gpio_swnode_pdata_template),
128 		.properties = properties,
129 	};
130 
131 	pdev = kunit_platform_device_register_full(test, &pdevinfo);
132 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
133 
134 	wait_for_device_probe();
135 	scoped_guard(device, &pdev->dev)
136 		bound = device_is_bound(&pdev->dev);
137 
138 	KUNIT_ASSERT_TRUE(test, bound);
139 
140 	pdata = dev_get_platdata(&pdev->dev);
141 	KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
142 }
143 
144 static void gpio_swnode_lookup_by_secondary(struct kunit *test)
145 {
146 	struct gpio_swnode_consumer_pdata *pdata;
147 	struct platform_device_info pdevinfo;
148 	struct property_entry properties[2];
149 	struct fwnode_handle *primary;
150 	struct platform_device *pdev;
151 	bool bound = false;
152 	int ret;
153 
154 	/*
155 	 * Can't live on the stack as it will still get referenced in cleanup
156 	 * path after this function returns.
157 	 */
158 	primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
159 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
160 
161 	ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
162 	KUNIT_ASSERT_EQ(test, ret, 0);
163 
164 	ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
165 	KUNIT_ASSERT_EQ(test, ret, 0);
166 
167 	fwnode_init(primary, NULL);
168 
169 	pdevinfo = (struct platform_device_info){
170 		.name = GPIO_TEST_PROVIDER,
171 		.id = PLATFORM_DEVID_NONE,
172 		.fwnode = primary,
173 		.swnode = &gpio_test_provider_swnode,
174 	};
175 
176 	pdev = kunit_platform_device_register_full(test, &pdevinfo);
177 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
178 
179 	properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
180 					    &gpio_test_provider_swnode,
181 					    0, GPIO_ACTIVE_HIGH);
182 	properties[1] = (struct property_entry){ };
183 
184 	pdevinfo = (struct platform_device_info){
185 		.name = GPIO_SWNODE_TEST_CONSUMER,
186 		.id = PLATFORM_DEVID_NONE,
187 		.data = &gpio_swnode_pdata_template,
188 		.size_data = sizeof(gpio_swnode_pdata_template),
189 		.properties = properties,
190 	};
191 
192 	pdev = kunit_platform_device_register_full(test, &pdevinfo);
193 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
194 
195 	wait_for_device_probe();
196 	scoped_guard(device, &pdev->dev)
197 		bound = device_is_bound(&pdev->dev);
198 
199 	KUNIT_ASSERT_TRUE(test, bound);
200 
201 	pdata = dev_get_platdata(&pdev->dev);
202 	KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
203 }
204 
205 static struct kunit_case gpio_swnode_lookup_tests[] = {
206 	KUNIT_CASE(gpio_swnode_lookup_by_primary),
207 	KUNIT_CASE(gpio_swnode_lookup_by_secondary),
208 	{ }
209 };
210 
211 static struct kunit_suite gpio_swnode_lookup_test_suite = {
212 	.name = "gpio-swnode-lookup",
213 	.test_cases = gpio_swnode_lookup_tests,
214 };
215 
216 static BLOCKING_NOTIFIER_HEAD(gpio_unbind_notifier);
217 
218 struct gpio_unbind_consumer_drvdata {
219 	struct device *dev;
220 	struct gpio_desc *desc;
221 	struct notifier_block nb;
222 	int set_retval;
223 };
224 
225 static int gpio_unbind_notify(struct notifier_block *nb, unsigned long action,
226 			      void *data)
227 {
228 	struct gpio_unbind_consumer_drvdata *drvdata =
229 		container_of(nb, struct gpio_unbind_consumer_drvdata, nb);
230 	struct device *dev = data;
231 
232 	if (dev != drvdata->dev)
233 		return NOTIFY_DONE;
234 
235 	drvdata->set_retval = gpiod_set_value_cansleep(drvdata->desc, 0);
236 
237 	return NOTIFY_OK;
238 }
239 
240 static void gpio_unbind_unregister_notifier(void *data)
241 {
242 	struct notifier_block *nb = data;
243 
244 	blocking_notifier_chain_unregister(&gpio_unbind_notifier, nb);
245 }
246 
247 static int gpio_unbind_consumer_probe(struct platform_device *pdev)
248 {
249 	struct gpio_unbind_consumer_drvdata *data;
250 	struct device *dev = &pdev->dev;
251 	int ret;
252 
253 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
254 	if (!data)
255 		return -ENOMEM;
256 
257 	data->dev = dev;
258 
259 	data->desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
260 	if (IS_ERR(data->desc))
261 		return PTR_ERR(data->desc);
262 
263 	data->nb.notifier_call = gpio_unbind_notify;
264 	ret = blocking_notifier_chain_register(&gpio_unbind_notifier, &data->nb);
265 	if (ret)
266 		return ret;
267 
268 	ret = devm_add_action_or_reset(dev, gpio_unbind_unregister_notifier, &data->nb);
269 	if (ret)
270 		return ret;
271 
272 	platform_set_drvdata(pdev, data);
273 
274 	return 0;
275 }
276 
277 static struct platform_driver gpio_unbind_consumer_driver = {
278 	.probe = gpio_unbind_consumer_probe,
279 	.driver = {
280 		.name = GPIO_UNBIND_TEST_CONSUMER,
281 	},
282 };
283 
284 static void gpio_unbind_with_consumers(struct kunit *test)
285 {
286 	struct gpio_unbind_consumer_drvdata *cons_data;
287 	struct platform_device_info pdevinfo;
288 	struct property_entry properties[2];
289 	struct platform_device *prvd, *cons;
290 	bool bound = false;
291 	int ret;
292 
293 	ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
294 	KUNIT_ASSERT_EQ(test, ret, 0);
295 
296 	ret = kunit_platform_driver_register(test, &gpio_unbind_consumer_driver);
297 	KUNIT_ASSERT_EQ(test, ret, 0);
298 
299 	pdevinfo = (struct platform_device_info){
300 		.name = GPIO_TEST_PROVIDER,
301 		.id = PLATFORM_DEVID_NONE,
302 		.swnode = &gpio_test_provider_swnode,
303 	};
304 
305 	prvd = kunit_platform_device_register_full(test, &pdevinfo);
306 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, prvd);
307 
308 	properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
309 					    &gpio_test_provider_swnode,
310 					    0, GPIO_ACTIVE_HIGH);
311 	properties[1] = (struct property_entry){ };
312 
313 	pdevinfo = (struct platform_device_info){
314 		.name = GPIO_UNBIND_TEST_CONSUMER,
315 		.id = PLATFORM_DEVID_NONE,
316 		.properties = properties,
317 	};
318 
319 	cons = kunit_platform_device_register_full(test, &pdevinfo);
320 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons);
321 
322 	wait_for_device_probe();
323 	scoped_guard(device, &cons->dev)
324 		bound = device_is_bound(&cons->dev);
325 
326 	KUNIT_ASSERT_TRUE(test, bound);
327 
328 	kunit_platform_device_unregister(test, prvd);
329 
330 	ret = blocking_notifier_call_chain(&gpio_unbind_notifier, 0, &cons->dev);
331 	KUNIT_ASSERT_EQ(test, ret, NOTIFY_OK);
332 
333 	scoped_guard(device, &cons->dev) {
334 		cons_data = platform_get_drvdata(cons);
335 		ret = cons_data->set_retval;
336 	}
337 
338 	KUNIT_ASSERT_EQ(test, ret, -ENODEV);
339 }
340 
341 static struct kunit_case gpio_unbind_with_consumers_tests[] = {
342 	KUNIT_CASE(gpio_unbind_with_consumers),
343 	{ }
344 };
345 
346 static struct kunit_suite gpio_unbind_with_consumers_test_suite = {
347 	.name = "gpio-unbind-with-consumers",
348 	.test_cases = gpio_unbind_with_consumers_tests,
349 };
350 
351 kunit_test_suites(
352 	&gpio_swnode_lookup_test_suite,
353 	&gpio_unbind_with_consumers_test_suite,
354 );
355 
356 MODULE_DESCRIPTION("Test module for the GPIO subsystem");
357 MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>");
358 MODULE_LICENSE("GPL");
359