mips: mtmips: spl/Kconfig: Set CONFIG_SPL_PAD_TO to 0x0 for ARCH_MTMIPS
[platform/kernel/u-boot.git] / drivers / led / led_pwm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2022 VK
4  * Author: Ivan Vozvakhov <i.vozvakhov@vk.team>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <led.h>
11 #include <malloc.h>
12 #include <dm/lists.h>
13 #include <pwm.h>
14
15 #define LEDS_PWM_DRIVER_NAME    "led_pwm"
16
17 struct led_pwm_priv {
18         struct udevice *pwm;
19         uint period;    /* period in ns */
20         uint duty;      /* duty cycle in ns */
21         uint channel;   /* pwm channel number */
22         bool active_low;        /* pwm polarity */
23         bool enabled;
24 };
25
26 static int led_pwm_enable(struct udevice *dev)
27 {
28         struct led_pwm_priv *priv = dev_get_priv(dev);
29         int ret;
30
31         ret = pwm_set_invert(priv->pwm, priv->channel, priv->active_low);
32         if (ret)
33                 return ret;
34
35         ret = pwm_set_config(priv->pwm, priv->channel, priv->period, priv->duty);
36         if (ret)
37                 return ret;
38
39         ret = pwm_set_enable(priv->pwm, priv->channel, true);
40         if (ret)
41                 return ret;
42
43         priv->enabled = true;
44
45         return 0;
46 }
47
48 static int led_pwm_disable(struct udevice *dev)
49 {
50         struct led_pwm_priv *priv = dev_get_priv(dev);
51         int ret;
52
53         ret = pwm_set_config(priv->pwm, priv->channel, priv->period, 0);
54         if (ret)
55                 return ret;
56
57         ret = pwm_set_enable(priv->pwm, priv->channel, false);
58         if (ret)
59                 return ret;
60
61         priv->enabled = false;
62
63         return 0;
64 }
65
66 static int led_pwm_set_state(struct udevice *dev, enum led_state_t state)
67 {
68         struct led_pwm_priv *priv = dev_get_priv(dev);
69         int ret;
70
71         switch (state) {
72         case LEDST_OFF:
73                 ret = led_pwm_disable(dev);
74                 break;
75         case LEDST_ON:
76                 ret = led_pwm_enable(dev);
77                 break;
78         case LEDST_TOGGLE:
79                 ret = (priv->enabled) ? led_pwm_disable(dev) : led_pwm_enable(dev);
80                 break;
81         default:
82                 ret = -ENOSYS;
83         }
84
85         return ret;
86 }
87
88 static enum led_state_t led_pwm_get_state(struct udevice *dev)
89 {
90         struct led_pwm_priv *priv = dev_get_priv(dev);
91
92         return (priv->enabled) ? LEDST_ON : LEDST_OFF;
93 }
94
95 static int led_pwm_probe(struct udevice *dev)
96 {
97         struct led_pwm_priv *priv = dev_get_priv(dev);
98
99         return led_pwm_set_state(dev, (priv->enabled) ? LEDST_ON : LEDST_OFF);
100 }
101
102 static int led_pwm_of_to_plat(struct udevice *dev)
103 {
104         struct led_pwm_priv *priv = dev_get_priv(dev);
105         struct ofnode_phandle_args args;
106         uint def_brightness, max_brightness;
107         int ret;
108
109         ret = dev_read_phandle_with_args(dev, "pwms", "#pwm-cells", 0, 0, &args);
110         if (ret)
111                 return ret;
112
113         ret = uclass_get_device_by_ofnode(UCLASS_PWM, args.node, &priv->pwm);
114         if (ret)
115                 return ret;
116
117         priv->channel = args.args[0];
118         priv->period = args.args[1];
119         priv->active_low = dev_read_bool(dev, "active-low");
120
121         def_brightness = dev_read_u32_default(dev, "u-boot,default-brightness", 0);
122         max_brightness = dev_read_u32_default(dev, "max-brightness", 255);
123         priv->enabled =  !!def_brightness;
124
125         /*
126          * No need to handle pwm iverted case (active_low)
127          * because of pwm_set_invert function
128          */
129         if (def_brightness < max_brightness)
130                 priv->duty = priv->period * def_brightness / max_brightness;
131         else
132                 priv->duty = priv->period;
133
134         return 0;
135 }
136
137 static int led_pwm_bind(struct udevice *parent)
138 {
139         struct udevice *dev;
140         ofnode node;
141         int ret;
142
143         dev_for_each_subnode(node, parent) {
144                 ret = device_bind_driver_to_node(parent, LEDS_PWM_DRIVER_NAME,
145                                                  ofnode_get_name(node),
146                                                  node, &dev);
147                 if (ret)
148                         return ret;
149         }
150         return 0;
151 }
152
153 static const struct led_ops led_pwm_ops = {
154         .set_state = led_pwm_set_state,
155         .get_state = led_pwm_get_state,
156 };
157
158 static const struct udevice_id led_pwm_ids[] = {
159         { .compatible = "pwm-leds" },
160         { }
161 };
162
163 U_BOOT_DRIVER(led_pwm) = {
164         .name = LEDS_PWM_DRIVER_NAME,
165         .id = UCLASS_LED,
166         .ops = &led_pwm_ops,
167         .priv_auto = sizeof(struct led_pwm_priv),
168         .probe = led_pwm_probe,
169         .of_to_plat = led_pwm_of_to_plat,
170 };
171
172 U_BOOT_DRIVER(led_pwm_wrap) = {
173         .name = LEDS_PWM_DRIVER_NAME "_wrap",
174         .id = UCLASS_NOP,
175         .of_match = led_pwm_ids,
176         .bind = led_pwm_bind,
177 };