patches-5.15.92-rt57
[platform/kernel/linux-rpi.git] / drivers / gpio / gpio-pwm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * GPIO driver wrapping PWM API
4  *
5  * PWM 0% and PWM 100% are equivalent to digital GPIO
6  * outputs, and there are times where it is useful to use
7  * PWM outputs as straight GPIOs (eg outputs of NXP PCA9685
8  * I2C PWM chip). This driver wraps the PWM API as a GPIO
9  * controller.
10  *
11  * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
12  */
13
14 #include <linux/err.h>
15 #include <linux/gpio/driver.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/pwm.h>
19
20 struct pwm_gpio {
21         struct gpio_chip gc;
22         struct pwm_device **pwm;
23 };
24
25 static int pwm_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
26 {
27         return GPIO_LINE_DIRECTION_OUT;
28 }
29
30 static void pwm_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
31 {
32         struct pwm_gpio *pwm_gpio = gpiochip_get_data(gc);
33         struct pwm_state state;
34
35         pwm_get_state(pwm_gpio->pwm[off], &state);
36         state.duty_cycle = val ? state.period : 0;
37         pwm_apply_state(pwm_gpio->pwm[off], &state);
38 }
39
40 static int pwm_gpio_parse_dt(struct pwm_gpio *pwm_gpio,
41                              struct device *dev)
42 {
43         struct device_node *node = dev->of_node;
44         struct pwm_state state;
45         int ret = 0, i, num_gpios;
46         const char *pwm_name;
47
48         if (!node)
49                 return -ENODEV;
50
51         num_gpios = of_property_count_strings(node, "pwm-names");
52         if (num_gpios <= 0)
53                 return 0;
54
55         pwm_gpio->pwm = devm_kzalloc(dev,
56                                      sizeof(*pwm_gpio->pwm) * num_gpios,
57                                      GFP_KERNEL);
58         if (!pwm_gpio->pwm)
59                 return -ENOMEM;
60
61         for (i = 0; i < num_gpios; i++) {
62                 ret = of_property_read_string_index(node, "pwm-names", i,
63                                                     &pwm_name);
64                 if (ret) {
65                         dev_err(dev, "unable to get pwm device index %d, name %s",
66                                 i, pwm_name);
67                         goto error;
68                 }
69
70                 pwm_gpio->pwm[i] = devm_pwm_get(dev, pwm_name);
71                 if (IS_ERR(pwm_gpio->pwm[i])) {
72                         ret = PTR_ERR(pwm_gpio->pwm[i]);
73                         if (ret != -EPROBE_DEFER)
74                                 dev_err(dev, "unable to request PWM\n");
75                         goto error;
76                 }
77
78                 /* Sync up PWM state. */
79                 pwm_init_state(pwm_gpio->pwm[i], &state);
80
81                 state.duty_cycle = 0;
82                 pwm_apply_state(pwm_gpio->pwm[i], &state);
83         }
84
85         pwm_gpio->gc.ngpio = num_gpios;
86
87 error:
88         return ret;
89 }
90
91 static int pwm_gpio_probe(struct platform_device *pdev)
92 {
93         struct device *dev = &pdev->dev;
94         struct pwm_gpio *pwm_gpio;
95         int ret;
96
97         pwm_gpio = devm_kzalloc(dev, sizeof(*pwm_gpio), GFP_KERNEL);
98         if (!pwm_gpio)
99                 return -ENOMEM;
100
101         pwm_gpio->gc.parent = dev;
102         pwm_gpio->gc.label = "pwm-gpio";
103         pwm_gpio->gc.owner = THIS_MODULE;
104         pwm_gpio->gc.of_node = dev->of_node;
105         pwm_gpio->gc.base = -1;
106
107         pwm_gpio->gc.get_direction = pwm_gpio_get_direction;
108         pwm_gpio->gc.set = pwm_gpio_set;
109         pwm_gpio->gc.can_sleep = true;
110
111         ret = pwm_gpio_parse_dt(pwm_gpio, dev);
112         if (ret)
113                 return ret;
114
115         if (!pwm_gpio->gc.ngpio)
116                 return 0;
117
118         return devm_gpiochip_add_data(dev, &pwm_gpio->gc, pwm_gpio);
119 }
120
121 static int pwm_gpio_remove(struct platform_device *pdev)
122 {
123         return 0;
124 }
125
126 static const struct of_device_id pwm_gpio_of_match[] = {
127         { .compatible = "pwm-gpio" },
128         { }
129 };
130 MODULE_DEVICE_TABLE(of, pwm_gpio_of_match);
131
132 static struct platform_driver pwm_gpio_driver = {
133         .driver = {
134                 .name           = "pwm-gpio",
135                 .of_match_table = of_match_ptr(pwm_gpio_of_match),
136         },
137         .probe  = pwm_gpio_probe,
138         .remove = pwm_gpio_remove,
139 };
140 module_platform_driver(pwm_gpio_driver);
141
142 MODULE_LICENSE("GPL");
143 MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>");
144 MODULE_DESCRIPTION("PWM GPIO driver");