xref: /freebsd/sys/arm/ti/am335x/am335x_ehrpwm.c (revision 10ff414c)
1 /*-
2  * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/limits.h>
35 #include <sys/lock.h>
36 #include <sys/module.h>
37 #include <sys/mutex.h>
38 #include <sys/resource.h>
39 #include <sys/rman.h>
40 
41 #include <machine/bus.h>
42 
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/ofw_bus.h>
45 #include <dev/ofw/ofw_bus_subr.h>
46 
47 #include <dev/pwm/pwmc.h>
48 
49 #include "pwmbus_if.h"
50 
51 #include "am335x_pwm.h"
52 
53 /*******************************************************************************
54  * Enhanced resolution PWM driver.  Many of the advanced featues of the hardware
55  * are not supported by this driver.  What is implemented here is simple
56  * variable-duty-cycle PWM output.
57  ******************************************************************************/
58 
59 /* In ticks */
60 #define	DEFAULT_PWM_PERIOD	1000
61 #define	PWM_CLOCK		100000000UL
62 
63 #define	NS_PER_SEC		1000000000
64 
65 #define	PWM_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
66 #define	PWM_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
67 #define	PWM_LOCK_ASSERT(_sc)    mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
68 #define	PWM_LOCK_INIT(_sc)	mtx_init(&(_sc)->sc_mtx, \
69     device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF)
70 #define	PWM_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_mtx)
71 
72 #define	EPWM_READ2(_sc, reg)	bus_read_2((_sc)->sc_mem_res, reg)
73 #define	EPWM_WRITE2(_sc, reg, value)	\
74     bus_write_2((_sc)->sc_mem_res, reg, value)
75 
76 #define	EPWM_TBCTL		0x00
77 /* see 15.2.2.11 for the first two, used in debug situations */
78 #define		TBCTL_FREERUN_STOP_NEXT_TBC_INCREMENT	(0 << 14)
79 #define		TBCTL_FREERUN_STOP_COMPLETE_CYCLE	(1 << 14)
80 /* ignore suspend control signal */
81 #define		TBCTL_FREERUN				(2 << 14)
82 
83 #define		TBCTL_PHDIR_UP		(1 << 13)
84 #define		TBCTL_PHDIR_DOWN	(0 << 13)
85 #define		TBCTL_CLKDIV(x)		((x) << 10)
86 #define		TBCTL_CLKDIV_MASK	(7 << 10)
87 #define		TBCTL_HSPCLKDIV(x)	((x) << 7)
88 #define		TBCTL_HSPCLKDIV_MASK	(7 << 7)
89 #define		TBCTL_SYNCOSEL_DISABLED	(3 << 4)
90 #define		TBCTL_PRDLD_SHADOW	(0 << 3)
91 #define		TBCTL_PRDLD_IMMEDIATE	(1 << 3)
92 #define		TBCTL_PHSEN_DISABLED	(0 << 2)
93 #define		TBCTL_PHSEN_ENABLED	(1 << 2)
94 #define		TBCTL_CTRMODE_MASK	(3)
95 #define		TBCTL_CTRMODE_UP	(0 << 0)
96 #define		TBCTL_CTRMODE_DOWN	(1 << 0)
97 #define		TBCTL_CTRMODE_UPDOWN	(2 << 0)
98 #define		TBCTL_CTRMODE_FREEZE	(3 << 0)
99 
100 #define	EPWM_TBSTS		0x02
101 #define	EPWM_TBPHSHR		0x04
102 #define	EPWM_TBPHS		0x06
103 #define	EPWM_TBCNT		0x08
104 #define	EPWM_TBPRD		0x0a
105 /* Counter-compare */
106 #define	EPWM_CMPCTL		0x0e
107 #define		CMPCTL_SHDWBMODE_SHADOW		(1 << 6)
108 #define		CMPCTL_SHDWBMODE_IMMEDIATE	(0 << 6)
109 #define		CMPCTL_SHDWAMODE_SHADOW		(1 << 4)
110 #define		CMPCTL_SHDWAMODE_IMMEDIATE	(0 << 4)
111 #define		CMPCTL_LOADBMODE_ZERO		(0 << 2)
112 #define		CMPCTL_LOADBMODE_PRD		(1 << 2)
113 #define		CMPCTL_LOADBMODE_EITHER		(2 << 2)
114 #define		CMPCTL_LOADBMODE_FREEZE		(3 << 2)
115 #define		CMPCTL_LOADAMODE_ZERO		(0 << 0)
116 #define		CMPCTL_LOADAMODE_PRD		(1 << 0)
117 #define		CMPCTL_LOADAMODE_EITHER		(2 << 0)
118 #define		CMPCTL_LOADAMODE_FREEZE		(3 << 0)
119 #define	EPWM_CMPAHR		0x10
120 #define	EPWM_CMPA		0x12
121 #define	EPWM_CMPB		0x14
122 /* CMPCTL_LOADAMODE_ZERO */
123 #define	EPWM_AQCTLA		0x16
124 #define	EPWM_AQCTLB		0x18
125 #define		AQCTL_CBU_NONE		(0 << 8)
126 #define		AQCTL_CBU_CLEAR		(1 << 8)
127 #define		AQCTL_CBU_SET		(2 << 8)
128 #define		AQCTL_CBU_TOGGLE	(3 << 8)
129 #define		AQCTL_CAU_NONE		(0 << 4)
130 #define		AQCTL_CAU_CLEAR		(1 << 4)
131 #define		AQCTL_CAU_SET		(2 << 4)
132 #define		AQCTL_CAU_TOGGLE	(3 << 4)
133 #define		AQCTL_ZRO_NONE		(0 << 0)
134 #define		AQCTL_ZRO_CLEAR		(1 << 0)
135 #define		AQCTL_ZRO_SET		(2 << 0)
136 #define		AQCTL_ZRO_TOGGLE	(3 << 0)
137 #define	EPWM_AQSFRC		0x1a
138 #define	EPWM_AQCSFRC		0x1c
139 #define		AQCSFRC_OFF		0
140 #define		AQCSFRC_LO		1
141 #define		AQCSFRC_HI		2
142 #define		AQCSFRC_MASK		3
143 #define		AQCSFRC(chan, hilo)	((hilo) << (2 * chan))
144 
145 /* Trip-Zone module */
146 #define	EPWM_TZSEL		0x24
147 #define	EPWM_TZCTL		0x28
148 #define	EPWM_TZFLG		0x2C
149 
150 /* Dead band */
151 #define EPWM_DBCTL		0x1E
152 #define		DBCTL_MASK		(3 << 0)
153 #define		DBCTL_BYPASS		0
154 #define		DBCTL_RISING_EDGE	1
155 #define		DBCTL_FALLING_EDGE	2
156 #define		DBCTL_BOTH_EDGE		3
157 
158 /* PWM-chopper */
159 #define EPWM_PCCTL		0x3C
160 #define		PCCTL_CHPEN_MASK	(1 << 0)
161 #define		PCCTL_CHPEN_DISABLE	0
162 #define		PCCTL_CHPEN_ENABLE	1
163 
164 /* High-Resolution PWM */
165 #define	EPWM_HRCTL		0x40
166 #define		HRCTL_DELMODE_BOTH	3
167 #define		HRCTL_DELMODE_FALL	2
168 #define		HRCTL_DELMODE_RISE	1
169 
170 static device_probe_t am335x_ehrpwm_probe;
171 static device_attach_t am335x_ehrpwm_attach;
172 static device_detach_t am335x_ehrpwm_detach;
173 
174 struct ehrpwm_channel {
175 	u_int	duty;		/* on duration, in ns */
176 	bool	enabled;	/* channel enabled? */
177 	bool	inverted;	/* signal inverted? */
178 };
179 #define	NUM_CHANNELS	2
180 
181 struct am335x_ehrpwm_softc {
182 	device_t		sc_dev;
183 	device_t		sc_busdev;
184 	struct mtx		sc_mtx;
185 	struct resource		*sc_mem_res;
186 	int			sc_mem_rid;
187 
188 	/* Things used for configuration via pwm(9) api. */
189 	u_int			sc_clkfreq; /* frequency in Hz */
190 	u_int			sc_clktick; /* duration in ns */
191 	u_int			sc_period;  /* duration in ns */
192 	struct ehrpwm_channel	sc_channels[NUM_CHANNELS];
193 };
194 
195 static struct ofw_compat_data compat_data[] = {
196 	{"ti,am33xx-ehrpwm",    true},
197 	{NULL,                  false},
198 };
199 SIMPLEBUS_PNP_INFO(compat_data);
200 
201 static void
202 am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty)
203 {
204 	u_int tbcmp;
205 
206 	if (duty == 0)
207 		tbcmp = 0;
208 	else
209 		tbcmp = max(1, duty / sc->sc_clktick);
210 
211 	sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick;
212 
213 	PWM_LOCK_ASSERT(sc);
214 	EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp);
215 }
216 
217 static void
218 am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable)
219 {
220 	uint16_t regval;
221 
222 	sc->sc_channels[chan].enabled = enable;
223 
224 	/*
225 	 * Turn off any existing software-force of the channel, then force
226 	 * it in the right direction (high or low) if it's not being enabled.
227 	 */
228 	PWM_LOCK_ASSERT(sc);
229 	regval = EPWM_READ2(sc, EPWM_AQCSFRC);
230 	regval &= ~AQCSFRC(chan, AQCSFRC_MASK);
231 	if (!sc->sc_channels[chan].enabled) {
232 		if (sc->sc_channels[chan].inverted)
233 			regval |= AQCSFRC(chan, AQCSFRC_HI);
234 		else
235 			regval |= AQCSFRC(chan, AQCSFRC_LO);
236 	}
237 	EPWM_WRITE2(sc, EPWM_AQCSFRC, regval);
238 }
239 
240 static bool
241 am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period)
242 {
243 	uint16_t regval;
244 	u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd;
245 
246 	/* Can't do a period shorter than 2 clock ticks. */
247 	if (period < 2 * NS_PER_SEC / PWM_CLOCK) {
248 		sc->sc_clkfreq = 0;
249 		sc->sc_clktick = 0;
250 		sc->sc_period  = 0;
251 		return (false);
252 	}
253 
254 	/*
255 	 * Figure out how much we have to divide down the base 100MHz clock so
256 	 * that we can express the requested period as a 16-bit tick count.
257 	 */
258 	tbprd = 0;
259 	for (clkdiv = 0; clkdiv < 8; ++clkdiv) {
260 		const u_int cd = 1 << clkdiv;
261 		for (hspclkdiv = 0; hspclkdiv < 8; ++hspclkdiv) {
262 			const u_int cdhs = max(1, hspclkdiv * 2);
263 			pwmclk = PWM_CLOCK / (cd * cdhs);
264 			pwmtick = NS_PER_SEC / pwmclk;
265 			if (period / pwmtick < 65536) {
266 				tbprd = period / pwmtick;
267 				break;
268 			}
269 		}
270 		if (tbprd != 0)
271 			break;
272 	}
273 
274 	/* Handle requested period too long for available clock divisors. */
275 	if (tbprd == 0)
276 		return (false);
277 
278 	/*
279 	 * If anything has changed from the current settings, reprogram the
280 	 * clock divisors and period register.
281 	 */
282 	if (sc->sc_clkfreq != pwmclk || sc->sc_clktick != pwmtick ||
283 	    sc->sc_period != tbprd * pwmtick) {
284 		sc->sc_clkfreq = pwmclk;
285 		sc->sc_clktick = pwmtick;
286 		sc->sc_period  = tbprd * pwmtick;
287 
288 		PWM_LOCK_ASSERT(sc);
289 		regval = EPWM_READ2(sc, EPWM_TBCTL);
290 		regval &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK);
291 		regval |= TBCTL_CLKDIV(clkdiv) | TBCTL_HSPCLKDIV(hspclkdiv);
292 		EPWM_WRITE2(sc, EPWM_TBCTL, regval);
293 		EPWM_WRITE2(sc, EPWM_TBPRD, tbprd - 1);
294 #if 0
295 		device_printf(sc->sc_dev, "clkdiv %u hspclkdiv %u tbprd %u "
296 		    "clkfreq %u Hz clktick %u ns period got %u requested %u\n",
297 		    clkdiv, hspclkdiv, tbprd - 1,
298 		    sc->sc_clkfreq, sc->sc_clktick, sc->sc_period, period);
299 #endif
300 		/*
301 		 * If the period changed, that invalidates the current CMP
302 		 * registers (duty values), just zero them out.
303 		 */
304 		am335x_ehrpwm_cfg_duty(sc, 0, 0);
305 		am335x_ehrpwm_cfg_duty(sc, 1, 0);
306 	}
307 
308 	return (true);
309 }
310 
311 static int
312 am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel)
313 {
314 
315 	*nchannel = NUM_CHANNELS;
316 
317 	return (0);
318 }
319 
320 static int
321 am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty)
322 {
323 	struct am335x_ehrpwm_softc *sc;
324 	bool status;
325 
326 	if (channel >= NUM_CHANNELS)
327 		return (EINVAL);
328 
329 	sc = device_get_softc(dev);
330 
331 	PWM_LOCK(sc);
332 	status = am335x_ehrpwm_cfg_period(sc, period);
333 	if (status)
334 		am335x_ehrpwm_cfg_duty(sc, channel, duty);
335 	PWM_UNLOCK(sc);
336 
337 	return (status ? 0 : EINVAL);
338 }
339 
340 static int
341 am335x_ehrpwm_channel_get_config(device_t dev, u_int channel,
342     u_int *period, u_int *duty)
343 {
344 	struct am335x_ehrpwm_softc *sc;
345 
346 	if (channel >= NUM_CHANNELS)
347 		return (EINVAL);
348 
349 	sc = device_get_softc(dev);
350 	*period = sc->sc_period;
351 	*duty = sc->sc_channels[channel].duty;
352 	return (0);
353 }
354 
355 static int
356 am335x_ehrpwm_channel_set_flags(device_t dev, u_int channel,
357        uint32_t flags)
358 {
359 	struct am335x_ehrpwm_softc *sc;
360 
361 	if (channel >= NUM_CHANNELS)
362 		return (EINVAL);
363 
364 	sc = device_get_softc(dev);
365 
366 	PWM_LOCK(sc);
367 	if (flags & PWM_POLARITY_INVERTED) {
368 		sc->sc_channels[channel].inverted = true;
369 		/* Action-Qualifier 15.2.2.5 */
370 		if (channel == 0)
371 			EPWM_WRITE2(sc, EPWM_AQCTLA,
372 			    (AQCTL_ZRO_CLEAR | AQCTL_CAU_SET));
373 		else
374 			EPWM_WRITE2(sc, EPWM_AQCTLB,
375 			    (AQCTL_ZRO_CLEAR | AQCTL_CBU_SET));
376 	} else {
377 		sc->sc_channels[channel].inverted = false;
378 		if (channel == 0)
379 			EPWM_WRITE2(sc, EPWM_AQCTLA,
380 			    (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR));
381 		else
382 			EPWM_WRITE2(sc, EPWM_AQCTLB,
383 			    (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR));
384 	}
385 	PWM_UNLOCK(sc);
386 
387 	return (0);
388 }
389 
390 static int
391 am335x_ehrpwm_channel_get_flags(device_t dev, u_int channel,
392     uint32_t *flags)
393 {
394 	struct am335x_ehrpwm_softc *sc;
395 	if (channel >= NUM_CHANNELS)
396 		return (EINVAL);
397 
398 	sc = device_get_softc(dev);
399 
400 	if (sc->sc_channels[channel].inverted == true)
401 		*flags = PWM_POLARITY_INVERTED;
402 	else
403 		*flags = 0;
404 
405 	return (0);
406 }
407 
408 
409 static int
410 am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable)
411 {
412 	struct am335x_ehrpwm_softc *sc;
413 
414 	if (channel >= NUM_CHANNELS)
415 		return (EINVAL);
416 
417 	sc = device_get_softc(dev);
418 
419 	PWM_LOCK(sc);
420 	am335x_ehrpwm_cfg_enable(sc, channel, enable);
421 	PWM_UNLOCK(sc);
422 
423 	return (0);
424 }
425 
426 static int
427 am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled)
428 {
429 	struct am335x_ehrpwm_softc *sc;
430 
431 	if (channel >= NUM_CHANNELS)
432 		return (EINVAL);
433 
434 	sc = device_get_softc(dev);
435 
436 	*enabled = sc->sc_channels[channel].enabled;
437 
438 	return (0);
439 }
440 
441 static int
442 am335x_ehrpwm_probe(device_t dev)
443 {
444 
445 	if (!ofw_bus_status_okay(dev))
446 		return (ENXIO);
447 
448 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
449 		return (ENXIO);
450 
451 	device_set_desc(dev, "AM335x EHRPWM");
452 
453 	return (BUS_PROBE_DEFAULT);
454 }
455 
456 static int
457 am335x_ehrpwm_attach(device_t dev)
458 {
459 	struct am335x_ehrpwm_softc *sc;
460 	uint16_t reg;
461 
462 	sc = device_get_softc(dev);
463 	sc->sc_dev = dev;
464 
465 	PWM_LOCK_INIT(sc);
466 
467 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
468 	    &sc->sc_mem_rid, RF_ACTIVE);
469 	if (sc->sc_mem_res == NULL) {
470 		device_printf(dev, "cannot allocate memory resources\n");
471 		goto fail;
472 	}
473 
474 	/* CONFIGURE EPWM */
475 	reg = EPWM_READ2(sc, EPWM_TBCTL);
476 	reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK);
477 	EPWM_WRITE2(sc, EPWM_TBCTL, reg);
478 
479 	EPWM_WRITE2(sc, EPWM_TBPRD, DEFAULT_PWM_PERIOD - 1);
480 	EPWM_WRITE2(sc, EPWM_CMPA, 0);
481 	EPWM_WRITE2(sc, EPWM_CMPB, 0);
482 
483 	/* Action-Qualifier 15.2.2.5 */
484 	EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR));
485 	EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR));
486 
487 	/* Dead band 15.2.2.6 */
488 	reg = EPWM_READ2(sc, EPWM_DBCTL);
489 	reg &= ~DBCTL_MASK;
490 	reg |= DBCTL_BYPASS;
491 	EPWM_WRITE2(sc, EPWM_DBCTL, reg);
492 
493 	/* PWM-chopper described in 15.2.2.7 */
494 	/* Acc. TRM used in pulse transformerbased gate drivers
495 	 * to control the power switching-elements
496 	 */
497 	reg = EPWM_READ2(sc, EPWM_PCCTL);
498 	reg &= ~PCCTL_CHPEN_MASK;
499 	reg |= PCCTL_CHPEN_DISABLE;
500 	EPWM_WRITE2(sc, EPWM_PCCTL, PCCTL_CHPEN_DISABLE);
501 
502 	/* Trip zone are described in 15.2.2.8.
503 	 * Essential its used to detect faults and can be configured
504 	 * to react on such faults..
505 	 */
506 	/* disable TZn as one-shot / CVC trip source 15.2.4.18 */
507 	EPWM_WRITE2(sc, EPWM_TZSEL, 0x0);
508 	/* reg described in 15.2.4.19 */
509 	EPWM_WRITE2(sc, EPWM_TZCTL, 0xf);
510 	reg = EPWM_READ2(sc, EPWM_TZFLG);
511 
512 	/* START EPWM */
513 	reg &= ~TBCTL_CTRMODE_MASK;
514 	reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN;
515 	EPWM_WRITE2(sc, EPWM_TBCTL, reg);
516 
517 	if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) {
518 		device_printf(dev, "Cannot add child pwmbus\n");
519 		// This driver can still do things even without the bus child.
520 	}
521 
522 	bus_generic_probe(dev);
523 	return (bus_generic_attach(dev));
524 fail:
525 	PWM_LOCK_DESTROY(sc);
526 	if (sc->sc_mem_res)
527 		bus_release_resource(dev, SYS_RES_MEMORY,
528 		    sc->sc_mem_rid, sc->sc_mem_res);
529 
530 	return(ENXIO);
531 }
532 
533 static int
534 am335x_ehrpwm_detach(device_t dev)
535 {
536 	struct am335x_ehrpwm_softc *sc;
537 	int error;
538 
539 	sc = device_get_softc(dev);
540 
541 	if ((error = bus_generic_detach(sc->sc_dev)) != 0)
542 		return (error);
543 
544 	PWM_LOCK(sc);
545 
546 	if (sc->sc_busdev != NULL)
547 		device_delete_child(dev, sc->sc_busdev);
548 
549 	if (sc->sc_mem_res)
550 		bus_release_resource(dev, SYS_RES_MEMORY,
551 		    sc->sc_mem_rid, sc->sc_mem_res);
552 
553 	PWM_UNLOCK(sc);
554 
555 	PWM_LOCK_DESTROY(sc);
556 
557 	return (0);
558 }
559 
560 static phandle_t
561 am335x_ehrpwm_get_node(device_t bus, device_t dev)
562 {
563 
564 	/*
565 	 * Share our controller node with our pwmbus child; it instantiates
566 	 * devices by walking the children contained within our node.
567 	 */
568 	return ofw_bus_get_node(bus);
569 }
570 
571 static device_method_t am335x_ehrpwm_methods[] = {
572 	DEVMETHOD(device_probe,		am335x_ehrpwm_probe),
573 	DEVMETHOD(device_attach,	am335x_ehrpwm_attach),
574 	DEVMETHOD(device_detach,	am335x_ehrpwm_detach),
575 
576 	/* ofw_bus_if */
577 	DEVMETHOD(ofw_bus_get_node,	am335x_ehrpwm_get_node),
578 
579 	/* pwm interface */
580 	DEVMETHOD(pwmbus_channel_count,		am335x_ehrpwm_channel_count),
581 	DEVMETHOD(pwmbus_channel_config,	am335x_ehrpwm_channel_config),
582 	DEVMETHOD(pwmbus_channel_get_config,	am335x_ehrpwm_channel_get_config),
583 	DEVMETHOD(pwmbus_channel_set_flags,	am335x_ehrpwm_channel_set_flags),
584 	DEVMETHOD(pwmbus_channel_get_flags,	am335x_ehrpwm_channel_get_flags),
585 	DEVMETHOD(pwmbus_channel_enable,	am335x_ehrpwm_channel_enable),
586 	DEVMETHOD(pwmbus_channel_is_enabled,	am335x_ehrpwm_channel_is_enabled),
587 
588 	DEVMETHOD_END
589 };
590 
591 static driver_t am335x_ehrpwm_driver = {
592 	"pwm",
593 	am335x_ehrpwm_methods,
594 	sizeof(struct am335x_ehrpwm_softc),
595 };
596 
597 static devclass_t am335x_ehrpwm_devclass;
598 
599 DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0);
600 MODULE_VERSION(am335x_ehrpwm, 1);
601 MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1);
602 MODULE_DEPEND(am335x_ehrpwm, pwmbus, 1, 1, 1);
603