1 /*
2  * Copyright (c) 2022 Nick Ward <nix.ward@gmail.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_pca9685_pwm
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/pwm.h>
12 #include <zephyr/sys/util_macro.h>
13 #include <zephyr/kernel.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(pwm_pca9685, CONFIG_PWM_LOG_LEVEL);
17 
18 #define OSC_CLOCK_MAX	  50000000
19 #define CHANNEL_CNT	  16
20 
21 #define ADDR_MODE1	  0x00
22 #define SLEEP		  BIT(4)
23 #define AUTO_INC	  BIT(5)
24 #define RESTART		  BIT(7)
25 
26 #define ADDR_MODE2	  0x01
27 #define OUTDRV_TOTEM_POLE BIT(2)
28 #define OCH_ON_ACK	  BIT(3)
29 
30 #define ADDR_LED0_ON_L	  0x06
31 #define ADDR_LED_ON_L(n)  (ADDR_LED0_ON_L + (4 * n))
32 #define LED_FULL_ON	  BIT(4)
33 #define LED_FULL_OFF	  BIT(4)
34 #define BYTE_N(word, n)	  ((word >> (8 * n)) & 0xFF)
35 
36 #define ADDR_PRE_SCALE	  0xFE
37 
38 
39 /* See PCA9585 datasheet Rev. 4 - 16 April 2015 section 7.3.5 */
40 #define OSC_CLOCK_INTERNAL 25000000
41 
42 #define PWM_STEPS 4096
43 
44 #define PRE_SCALE_MIN 0x03
45 #define PRE_SCALE_MAX 0xFF
46 
47 #define PRE_SCALE_DEFAULT 0x1E
48 
49 #define PWM_PERIOD_COUNT_PS(pre_scale) (PWM_STEPS * (pre_scale + 1))
50 
51 /*
52  * When using the internal oscillator this corresponds to an
53  * update rate of 1526 Hz
54  */
55 #define PWM_PERIOD_COUNT_MIN PWM_PERIOD_COUNT_PS(PRE_SCALE_MIN)
56 
57 /*
58  * When using the internal oscillator this corresponds to an
59  * update rate of 24 Hz
60  */
61 #define PWM_PERIOD_COUNT_MAX PWM_PERIOD_COUNT_PS(PRE_SCALE_MAX)
62 
63 /*
64  * When using the internal oscillator this corresponds to an
65  * update rate of 200 Hz
66  */
67 #define PWM_PERIOD_COUNT_DEFAULT PWM_PERIOD_COUNT_PS(PRE_SCALE_DEFAULT)
68 
69 
70 /*
71  * Time allowed for the oscillator to stabilize after the PCA9685's
72  * RESTART mode is used to wake the chip from SLEEP.
73  * See PCA9685 datasheet section 7.3.1.1
74  */
75 #define OSCILLATOR_STABILIZE K_USEC(500)
76 
77 struct pca9685_config {
78 	struct i2c_dt_spec i2c;
79 	bool outdrv_open_drain;
80 	bool och_on_ack;
81 	bool invrt;
82 };
83 
84 struct pca9685_data {
85 	struct k_mutex mutex;
86 	uint8_t pre_scale;
87 };
88 
set_reg(const struct device * dev,uint8_t addr,uint8_t value)89 static int set_reg(const struct device *dev, uint8_t addr, uint8_t value)
90 {
91 	const struct pca9685_config *config = dev->config;
92 	uint8_t buf[] = {addr, value};
93 	int ret;
94 
95 	ret = i2c_write_dt(&config->i2c, buf, sizeof(buf));
96 	if (ret != 0) {
97 		LOG_ERR("I2C write [0x%02X]=0x%02X: %d", addr, value, ret);
98 	} else {
99 		LOG_DBG("[0x%02X]=0x%02X", addr, value);
100 	}
101 	return ret;
102 }
103 
get_reg(const struct device * dev,uint8_t addr,uint8_t * value)104 static int get_reg(const struct device *dev, uint8_t addr, uint8_t *value)
105 {
106 	const struct pca9685_config *config = dev->config;
107 	int ret;
108 
109 	ret = i2c_write_read_dt(&config->i2c, &addr, sizeof(addr), value,
110 				sizeof(*value));
111 	if (ret != 0) {
112 		LOG_ERR("I2C write [0x%02X]=0x%02X: %d", addr, *value, ret);
113 	}
114 	return ret;
115 }
116 
set_pre_scale(const struct device * dev,uint8_t value)117 static int set_pre_scale(const struct device *dev, uint8_t value)
118 {
119 	struct pca9685_data *data = dev->data;
120 	uint8_t mode1;
121 	int ret;
122 	uint8_t restart = RESTART;
123 
124 	k_mutex_lock(&data->mutex, K_FOREVER);
125 
126 	/* Unblock write to PRE_SCALE by setting SLEEP bit to logic 1 */
127 	ret = set_reg(dev, ADDR_MODE1, AUTO_INC | SLEEP);
128 	if (ret != 0) {
129 		goto out;
130 	}
131 
132 	ret = get_reg(dev, ADDR_MODE1, &mode1);
133 	if (ret != 0) {
134 		goto out;
135 	}
136 
137 	if ((mode1 & RESTART) == 0x00) {
138 		restart = 0;
139 	}
140 
141 	ret = set_reg(dev, ADDR_PRE_SCALE, value);
142 	if (ret != 0) {
143 		goto out;
144 	}
145 
146 	/* Clear SLEEP bit - See datasheet section 7.3.1.1 */
147 	ret = set_reg(dev, ADDR_MODE1, AUTO_INC);
148 	if (ret != 0) {
149 		goto out;
150 	}
151 
152 	k_sleep(OSCILLATOR_STABILIZE);
153 
154 	ret = set_reg(dev, ADDR_MODE1, AUTO_INC | restart);
155 	if (ret != 0) {
156 		goto out;
157 	}
158 
159 out:
160 	k_mutex_unlock(&data->mutex);
161 
162 	return ret;
163 }
164 
pca9685_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_count,uint32_t pulse_count,pwm_flags_t flags)165 static int pca9685_set_cycles(const struct device *dev,
166 			      uint32_t channel, uint32_t period_count,
167 			      uint32_t pulse_count, pwm_flags_t flags)
168 {
169 	const struct pca9685_config *config = dev->config;
170 	struct pca9685_data *data = dev->data;
171 	uint8_t buf[5] = { 0 };
172 	uint32_t led_off_count;
173 	int32_t pre_scale;
174 	int ret;
175 
176 	ARG_UNUSED(flags);
177 
178 	if (channel >= CHANNEL_CNT) {
179 		LOG_WRN("channel out of range: %u", channel);
180 		return -EINVAL;
181 	}
182 
183 	pre_scale = DIV_ROUND_UP((int64_t)period_count, PWM_STEPS) - 1;
184 
185 	if (pre_scale < PRE_SCALE_MIN) {
186 		LOG_ERR("period_count %u < %u (min)", period_count,
187 			PWM_PERIOD_COUNT_MIN);
188 		return -ENOTSUP;
189 	} else if (pre_scale > PRE_SCALE_MAX) {
190 		LOG_ERR("period_count %u > %u (max)", period_count,
191 			PWM_PERIOD_COUNT_MAX);
192 		return -ENOTSUP;
193 	}
194 
195 	/* Only one output frequency - simple conversion to equivalent PWM */
196 	if (pre_scale != data->pre_scale) {
197 		data->pre_scale = pre_scale;
198 		ret = set_pre_scale(dev, pre_scale);
199 		if (ret != 0) {
200 			return ret;
201 		}
202 	}
203 
204 	/* Adjust PWM output for the resolution of the PCA9685 */
205 	led_off_count = DIV_ROUND_UP(pulse_count * PWM_STEPS, period_count);
206 
207 	buf[0] = ADDR_LED_ON_L(channel);
208 	if (led_off_count == 0) {
209 		buf[4] = LED_FULL_OFF;
210 	} else if (led_off_count < PWM_STEPS) {
211 		/* LED turns on at count 0 */
212 		buf[3] = BYTE_N(led_off_count, 0);
213 		buf[4] = BYTE_N(led_off_count, 1);
214 	} else {
215 		buf[2] = LED_FULL_ON;
216 	}
217 
218 	return i2c_write_dt(&config->i2c, buf, sizeof(buf));
219 }
220 
pca9685_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)221 static int pca9685_get_cycles_per_sec(const struct device *dev,
222 				      uint32_t channel, uint64_t *cycles)
223 {
224 	ARG_UNUSED(dev);
225 	ARG_UNUSED(channel);
226 
227 	*cycles = OSC_CLOCK_INTERNAL;
228 
229 	return 0;
230 }
231 
232 static DEVICE_API(pwm, pca9685_api) = {
233 	.set_cycles = pca9685_set_cycles,
234 	.get_cycles_per_sec = pca9685_get_cycles_per_sec,
235 };
236 
pca9685_init(const struct device * dev)237 static int pca9685_init(const struct device *dev)
238 {
239 	const struct pca9685_config *config = dev->config;
240 	struct pca9685_data *data = dev->data;
241 	uint8_t value;
242 	int ret;
243 
244 	(void)k_mutex_init(&data->mutex);
245 
246 	if (!i2c_is_ready_dt(&config->i2c)) {
247 		LOG_ERR("I2C device not ready");
248 		return -ENODEV;
249 	}
250 
251 	ret = set_reg(dev, ADDR_MODE1, AUTO_INC);
252 	if (ret != 0) {
253 		LOG_ERR("set_reg MODE1: %d", ret);
254 		return ret;
255 	}
256 
257 	value = 0x00;
258 	if (!config->outdrv_open_drain) {
259 		value |= OUTDRV_TOTEM_POLE;
260 	}
261 	if (config->och_on_ack) {
262 		value |= OCH_ON_ACK;
263 	}
264 	ret = set_reg(dev, ADDR_MODE2, value);
265 	if (ret != 0) {
266 		LOG_ERR("set_reg MODE2: %d", ret);
267 		return ret;
268 	}
269 
270 	return 0;
271 }
272 
273 #define PCA9685_INIT(inst)                                              \
274 	static const struct pca9685_config pca9685_##inst##_config = {  \
275 		.i2c = I2C_DT_SPEC_INST_GET(inst),                      \
276 		.outdrv_open_drain = DT_INST_PROP(inst, open_drain),    \
277 		.och_on_ack = DT_INST_PROP(inst, och_on_ack),           \
278 		.invrt = DT_INST_PROP(inst, invert),                    \
279 	};                                                              \
280                                                                         \
281 	static struct pca9685_data pca9685_##inst##_data;               \
282                                                                         \
283 	DEVICE_DT_INST_DEFINE(inst, pca9685_init, NULL,                 \
284 			      &pca9685_##inst##_data,                   \
285 			      &pca9685_##inst##_config, POST_KERNEL,    \
286 			      CONFIG_PWM_INIT_PRIORITY,                 \
287 			      &pca9685_api);
288 
289 DT_INST_FOREACH_STATUS_OKAY(PCA9685_INIT);
290