xref: /freebsd/sys/dev/pwm/controller/allwinner/aw_pwm.c (revision b196276c20b577b364372f1aa1a646b9ce34bf5c)
102e91208SEmmanuel Vadot /*-
202e91208SEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
302e91208SEmmanuel Vadot  *
402e91208SEmmanuel Vadot  * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
502e91208SEmmanuel Vadot  *
602e91208SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
702e91208SEmmanuel Vadot  * modification, are permitted provided that the following conditions
802e91208SEmmanuel Vadot  * are met:
902e91208SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
1002e91208SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
1102e91208SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
1202e91208SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
1302e91208SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
1402e91208SEmmanuel Vadot  *
1502e91208SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1602e91208SEmmanuel Vadot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1702e91208SEmmanuel Vadot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1802e91208SEmmanuel Vadot  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1902e91208SEmmanuel Vadot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2002e91208SEmmanuel Vadot  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2102e91208SEmmanuel Vadot  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2202e91208SEmmanuel Vadot  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2302e91208SEmmanuel Vadot  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2402e91208SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2502e91208SEmmanuel Vadot  * SUCH DAMAGE.
2602e91208SEmmanuel Vadot  */
2702e91208SEmmanuel Vadot 
2802e91208SEmmanuel Vadot #include <sys/param.h>
2902e91208SEmmanuel Vadot #include <sys/systm.h>
3002e91208SEmmanuel Vadot #include <sys/bus.h>
3102e91208SEmmanuel Vadot #include <sys/kernel.h>
3202e91208SEmmanuel Vadot #include <sys/module.h>
3302e91208SEmmanuel Vadot #include <sys/rman.h>
3402e91208SEmmanuel Vadot #include <sys/resource.h>
3502e91208SEmmanuel Vadot #include <machine/bus.h>
3602e91208SEmmanuel Vadot 
3702e91208SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
3802e91208SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
3902e91208SEmmanuel Vadot 
40be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
4102e91208SEmmanuel Vadot 
4202e91208SEmmanuel Vadot #include "pwmbus_if.h"
4302e91208SEmmanuel Vadot 
4402e91208SEmmanuel Vadot #define	AW_PWM_CTRL			0x00
4502e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_PRESCALE_MASK	0xF
4602e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_EN			(1 << 4)
4702e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_ACTIVE_LEVEL_HIGH	(1 << 5)
4802e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_GATE		(1 << 6)
4902e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_MODE_MASK		0x80
5002e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_PULSE_MODE		(1 << 7)
5102e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_CYCLE_MODE		(0 << 7)
5202e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_PULSE_START	(1 << 8)
5302e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_CLK_BYPASS		(1 << 9)
5402e91208SEmmanuel Vadot #define	 AW_PWM_CTRL_PERIOD_BUSY	(1 << 28)
5502e91208SEmmanuel Vadot 
5602e91208SEmmanuel Vadot #define	AW_PWM_PERIOD			0x04
5702e91208SEmmanuel Vadot #define	AW_PWM_PERIOD_TOTAL_MASK	0xFFFF
5802e91208SEmmanuel Vadot #define	AW_PWM_PERIOD_TOTAL_SHIFT	16
5902e91208SEmmanuel Vadot #define	AW_PWM_PERIOD_ACTIVE_MASK	0xFFFF
6002e91208SEmmanuel Vadot #define	AW_PWM_PERIOD_ACTIVE_SHIFT	0
6102e91208SEmmanuel Vadot 
6202e91208SEmmanuel Vadot #define	AW_PWM_MAX_FREQ			24000000
6302e91208SEmmanuel Vadot 
6402e91208SEmmanuel Vadot #define	NS_PER_SEC	1000000000
6502e91208SEmmanuel Vadot 
6602e91208SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
6702e91208SEmmanuel Vadot 	{ "allwinner,sun5i-a13-pwm",		1 },
6802e91208SEmmanuel Vadot 	{ "allwinner,sun8i-h3-pwm",		1 },
6902e91208SEmmanuel Vadot 	{ NULL,					0 }
7002e91208SEmmanuel Vadot };
7102e91208SEmmanuel Vadot 
7202e91208SEmmanuel Vadot static struct resource_spec aw_pwm_spec[] = {
7302e91208SEmmanuel Vadot 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
7402e91208SEmmanuel Vadot 	{ -1, 0 }
7502e91208SEmmanuel Vadot };
7602e91208SEmmanuel Vadot 
7702e91208SEmmanuel Vadot struct aw_pwm_softc {
7802e91208SEmmanuel Vadot 	device_t	dev;
7902e91208SEmmanuel Vadot 	device_t	busdev;
8002e91208SEmmanuel Vadot 	clk_t		clk;
8102e91208SEmmanuel Vadot 	struct resource	*res;
8202e91208SEmmanuel Vadot 
8302e91208SEmmanuel Vadot 	uint64_t	clk_freq;
8402e91208SEmmanuel Vadot 	unsigned int	period;
8502e91208SEmmanuel Vadot 	unsigned int	duty;
8602e91208SEmmanuel Vadot 	uint32_t	flags;
8702e91208SEmmanuel Vadot 	bool		enabled;
8802e91208SEmmanuel Vadot };
8902e91208SEmmanuel Vadot 
9002e91208SEmmanuel Vadot static uint32_t aw_pwm_clk_prescaler[] = {
9102e91208SEmmanuel Vadot 	120,
9202e91208SEmmanuel Vadot 	180,
9302e91208SEmmanuel Vadot 	240,
9402e91208SEmmanuel Vadot 	360,
9502e91208SEmmanuel Vadot 	480,
9602e91208SEmmanuel Vadot 	0,
9702e91208SEmmanuel Vadot 	0,
9802e91208SEmmanuel Vadot 	0,
9902e91208SEmmanuel Vadot 	12000,
10002e91208SEmmanuel Vadot 	24000,
10102e91208SEmmanuel Vadot 	36000,
10202e91208SEmmanuel Vadot 	48000,
10302e91208SEmmanuel Vadot 	72000,
10402e91208SEmmanuel Vadot 	0,
10502e91208SEmmanuel Vadot 	0,
10602e91208SEmmanuel Vadot 	1,
10702e91208SEmmanuel Vadot };
10802e91208SEmmanuel Vadot 
10902e91208SEmmanuel Vadot #define	AW_PWM_READ(sc, reg)		bus_read_4((sc)->res, (reg))
11002e91208SEmmanuel Vadot #define	AW_PWM_WRITE(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
11102e91208SEmmanuel Vadot 
11202e91208SEmmanuel Vadot static int aw_pwm_probe(device_t dev);
11302e91208SEmmanuel Vadot static int aw_pwm_attach(device_t dev);
11402e91208SEmmanuel Vadot static int aw_pwm_detach(device_t dev);
11502e91208SEmmanuel Vadot 
11602e91208SEmmanuel Vadot static int
aw_pwm_probe(device_t dev)11702e91208SEmmanuel Vadot aw_pwm_probe(device_t dev)
11802e91208SEmmanuel Vadot {
11902e91208SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
12002e91208SEmmanuel Vadot 		return (ENXIO);
12102e91208SEmmanuel Vadot 
12202e91208SEmmanuel Vadot 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
12302e91208SEmmanuel Vadot 		return (ENXIO);
12402e91208SEmmanuel Vadot 
12502e91208SEmmanuel Vadot 	device_set_desc(dev, "Allwinner PWM");
12602e91208SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
12702e91208SEmmanuel Vadot }
12802e91208SEmmanuel Vadot 
12902e91208SEmmanuel Vadot static int
aw_pwm_attach(device_t dev)13002e91208SEmmanuel Vadot aw_pwm_attach(device_t dev)
13102e91208SEmmanuel Vadot {
13202e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
13302e91208SEmmanuel Vadot 	uint64_t clk_freq;
13402e91208SEmmanuel Vadot 	uint32_t reg;
13502e91208SEmmanuel Vadot 	phandle_t node;
13602e91208SEmmanuel Vadot 	int error;
13702e91208SEmmanuel Vadot 
13802e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
13902e91208SEmmanuel Vadot 	sc->dev = dev;
14002e91208SEmmanuel Vadot 
14102e91208SEmmanuel Vadot 	error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
14202e91208SEmmanuel Vadot 	if (error != 0) {
14302e91208SEmmanuel Vadot 		device_printf(dev, "cannot get clock\n");
14402e91208SEmmanuel Vadot 		goto fail;
14502e91208SEmmanuel Vadot 	}
14602e91208SEmmanuel Vadot 	error = clk_enable(sc->clk);
14702e91208SEmmanuel Vadot 	if (error != 0) {
14802e91208SEmmanuel Vadot 		device_printf(dev, "cannot enable clock\n");
14902e91208SEmmanuel Vadot 		goto fail;
15002e91208SEmmanuel Vadot 	}
15102e91208SEmmanuel Vadot 
15202e91208SEmmanuel Vadot 	error = clk_get_freq(sc->clk, &sc->clk_freq);
15302e91208SEmmanuel Vadot 	if (error != 0) {
15402e91208SEmmanuel Vadot 		device_printf(dev, "cannot get clock frequency\n");
15502e91208SEmmanuel Vadot 		goto fail;
15602e91208SEmmanuel Vadot 	}
15702e91208SEmmanuel Vadot 
15802e91208SEmmanuel Vadot 	if (bus_alloc_resources(dev, aw_pwm_spec, &sc->res) != 0) {
15902e91208SEmmanuel Vadot 		device_printf(dev, "cannot allocate resources for device\n");
16002e91208SEmmanuel Vadot 		error = ENXIO;
16102e91208SEmmanuel Vadot 		goto fail;
16202e91208SEmmanuel Vadot 	}
16302e91208SEmmanuel Vadot 
16402e91208SEmmanuel Vadot 	/* Read the configuration left by U-Boot */
16502e91208SEmmanuel Vadot 	reg = AW_PWM_READ(sc, AW_PWM_CTRL);
16602e91208SEmmanuel Vadot 	if (reg & (AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN))
16702e91208SEmmanuel Vadot 		sc->enabled = true;
16802e91208SEmmanuel Vadot 
16902e91208SEmmanuel Vadot 	reg = AW_PWM_READ(sc, AW_PWM_CTRL);
17002e91208SEmmanuel Vadot 	reg &= AW_PWM_CTRL_PRESCALE_MASK;
17102e91208SEmmanuel Vadot 	if (reg > nitems(aw_pwm_clk_prescaler)) {
17202e91208SEmmanuel Vadot 		device_printf(dev, "Bad prescaler %x, cannot guess current settings\n", reg);
17302e91208SEmmanuel Vadot 		goto skipcfg;
17402e91208SEmmanuel Vadot 	}
17502e91208SEmmanuel Vadot 	clk_freq = sc->clk_freq / aw_pwm_clk_prescaler[reg];
17602e91208SEmmanuel Vadot 
17702e91208SEmmanuel Vadot 	reg = AW_PWM_READ(sc, AW_PWM_PERIOD);
17802e91208SEmmanuel Vadot 	sc->period = NS_PER_SEC /
17902e91208SEmmanuel Vadot 		(clk_freq / ((reg >> AW_PWM_PERIOD_TOTAL_SHIFT) & AW_PWM_PERIOD_TOTAL_MASK));
18002e91208SEmmanuel Vadot 	sc->duty = NS_PER_SEC /
18102e91208SEmmanuel Vadot 		(clk_freq / ((reg >> AW_PWM_PERIOD_ACTIVE_SHIFT) & AW_PWM_PERIOD_ACTIVE_MASK));
18202e91208SEmmanuel Vadot 
18302e91208SEmmanuel Vadot skipcfg:
18402e91208SEmmanuel Vadot 	/*
18502e91208SEmmanuel Vadot 	 * Note that we don't check for failure to attach pwmbus -- even without
18602e91208SEmmanuel Vadot 	 * it we can still service clients who connect via fdt xref data.
18702e91208SEmmanuel Vadot 	 */
18802e91208SEmmanuel Vadot 	node = ofw_bus_get_node(dev);
18902e91208SEmmanuel Vadot 	OF_device_register_xref(OF_xref_from_node(node), dev);
19002e91208SEmmanuel Vadot 
1915b56413dSWarner Losh 	sc->busdev = device_add_child(dev, "pwmbus", DEVICE_UNIT_ANY);
19202e91208SEmmanuel Vadot 
193*18250ec6SJohn Baldwin 	bus_attach_children(dev);
194*18250ec6SJohn Baldwin 	return (0);
19502e91208SEmmanuel Vadot 
19602e91208SEmmanuel Vadot fail:
19702e91208SEmmanuel Vadot 	aw_pwm_detach(dev);
19802e91208SEmmanuel Vadot 	return (error);
19902e91208SEmmanuel Vadot }
20002e91208SEmmanuel Vadot 
20102e91208SEmmanuel Vadot static int
aw_pwm_detach(device_t dev)20202e91208SEmmanuel Vadot aw_pwm_detach(device_t dev)
20302e91208SEmmanuel Vadot {
20402e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
20502e91208SEmmanuel Vadot 	int error;
20602e91208SEmmanuel Vadot 
20702e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
20802e91208SEmmanuel Vadot 
20902e91208SEmmanuel Vadot 	if ((error = bus_generic_detach(sc->dev)) != 0) {
21002e91208SEmmanuel Vadot 		device_printf(sc->dev, "cannot detach child devices\n");
21102e91208SEmmanuel Vadot 		return (error);
21202e91208SEmmanuel Vadot 	}
21302e91208SEmmanuel Vadot 
21402e91208SEmmanuel Vadot 	if (sc->res != NULL)
21502e91208SEmmanuel Vadot 		bus_release_resources(dev, aw_pwm_spec, &sc->res);
21602e91208SEmmanuel Vadot 
21702e91208SEmmanuel Vadot 	return (0);
21802e91208SEmmanuel Vadot }
21902e91208SEmmanuel Vadot 
22002e91208SEmmanuel Vadot static phandle_t
aw_pwm_get_node(device_t bus,device_t dev)22102e91208SEmmanuel Vadot aw_pwm_get_node(device_t bus, device_t dev)
22202e91208SEmmanuel Vadot {
22302e91208SEmmanuel Vadot 
22402e91208SEmmanuel Vadot 	/*
22502e91208SEmmanuel Vadot 	 * Share our controller node with our pwmbus child; it instantiates
22602e91208SEmmanuel Vadot 	 * devices by walking the children contained within our node.
22702e91208SEmmanuel Vadot 	 */
22802e91208SEmmanuel Vadot 	return ofw_bus_get_node(bus);
22902e91208SEmmanuel Vadot }
23002e91208SEmmanuel Vadot 
23102e91208SEmmanuel Vadot static int
aw_pwm_channel_count(device_t dev,u_int * nchannel)23202e91208SEmmanuel Vadot aw_pwm_channel_count(device_t dev, u_int *nchannel)
23302e91208SEmmanuel Vadot {
23402e91208SEmmanuel Vadot 
23502e91208SEmmanuel Vadot 	*nchannel = 1;
23602e91208SEmmanuel Vadot 
23702e91208SEmmanuel Vadot 	return (0);
23802e91208SEmmanuel Vadot }
23902e91208SEmmanuel Vadot 
24002e91208SEmmanuel Vadot static int
aw_pwm_channel_config(device_t dev,u_int channel,u_int period,u_int duty)24102e91208SEmmanuel Vadot aw_pwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty)
24202e91208SEmmanuel Vadot {
24302e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
24402e91208SEmmanuel Vadot 	uint64_t period_freq, duty_freq;
24502e91208SEmmanuel Vadot 	uint64_t clk_rate, div;
24602e91208SEmmanuel Vadot 	uint32_t reg;
24702e91208SEmmanuel Vadot 	int prescaler;
24802e91208SEmmanuel Vadot 	int i;
24902e91208SEmmanuel Vadot 
25002e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
25102e91208SEmmanuel Vadot 
25202e91208SEmmanuel Vadot 	period_freq = NS_PER_SEC / period;
25302e91208SEmmanuel Vadot 	if (period_freq > AW_PWM_MAX_FREQ)
25402e91208SEmmanuel Vadot 		return (EINVAL);
25502e91208SEmmanuel Vadot 
25602e91208SEmmanuel Vadot 	/*
25702e91208SEmmanuel Vadot 	 * FIXME.  The hardware is capable of sub-Hz frequencies, that is,
25802e91208SEmmanuel Vadot 	 * periods longer than a second.  But the current code cannot deal
25902e91208SEmmanuel Vadot 	 * with those properly.
26002e91208SEmmanuel Vadot 	 */
26102e91208SEmmanuel Vadot 	if (period_freq == 0)
26202e91208SEmmanuel Vadot 		return (EINVAL);
26302e91208SEmmanuel Vadot 
26402e91208SEmmanuel Vadot 	/*
26502e91208SEmmanuel Vadot 	 * FIXME.  There is a great loss of precision when the period and the
26602e91208SEmmanuel Vadot 	 * duty are near 1 second.  In some cases period_freq and duty_freq can
26702e91208SEmmanuel Vadot 	 * be equal even if the period and the duty are significantly different.
26802e91208SEmmanuel Vadot 	 */
26902e91208SEmmanuel Vadot 	duty_freq = NS_PER_SEC / duty;
27002e91208SEmmanuel Vadot 	if (duty_freq < period_freq) {
27102e91208SEmmanuel Vadot 		device_printf(sc->dev, "duty < period\n");
27202e91208SEmmanuel Vadot 		return (EINVAL);
27302e91208SEmmanuel Vadot 	}
27402e91208SEmmanuel Vadot 
27502e91208SEmmanuel Vadot 	/* First test without prescaler */
27602e91208SEmmanuel Vadot 	clk_rate = AW_PWM_MAX_FREQ;
27702e91208SEmmanuel Vadot 	prescaler = AW_PWM_CTRL_PRESCALE_MASK;
27802e91208SEmmanuel Vadot 	div = AW_PWM_MAX_FREQ / period_freq;
27902e91208SEmmanuel Vadot 	if ((div - 1) > AW_PWM_PERIOD_TOTAL_MASK) {
28002e91208SEmmanuel Vadot 		/* Test all prescaler */
28102e91208SEmmanuel Vadot 		for (i = 0; i < nitems(aw_pwm_clk_prescaler); i++) {
28202e91208SEmmanuel Vadot 			if (aw_pwm_clk_prescaler[i] == 0)
28302e91208SEmmanuel Vadot 				continue;
28402e91208SEmmanuel Vadot 			div = AW_PWM_MAX_FREQ / aw_pwm_clk_prescaler[i] / period_freq;
28502e91208SEmmanuel Vadot 			if ((div - 1) < AW_PWM_PERIOD_TOTAL_MASK ) {
28602e91208SEmmanuel Vadot 				prescaler = i;
28702e91208SEmmanuel Vadot 				clk_rate = AW_PWM_MAX_FREQ / aw_pwm_clk_prescaler[i];
28802e91208SEmmanuel Vadot 				break;
28902e91208SEmmanuel Vadot 			}
29002e91208SEmmanuel Vadot 		}
29102e91208SEmmanuel Vadot 		if (prescaler == AW_PWM_CTRL_PRESCALE_MASK)
29202e91208SEmmanuel Vadot 			return (EINVAL);
29302e91208SEmmanuel Vadot 	}
29402e91208SEmmanuel Vadot 
29502e91208SEmmanuel Vadot 	reg = AW_PWM_READ(sc, AW_PWM_CTRL);
29602e91208SEmmanuel Vadot 
29702e91208SEmmanuel Vadot 	/* Write the prescalar */
29802e91208SEmmanuel Vadot 	reg &= ~AW_PWM_CTRL_PRESCALE_MASK;
29902e91208SEmmanuel Vadot 	reg |= prescaler;
30002e91208SEmmanuel Vadot 
30102e91208SEmmanuel Vadot 	reg &= ~AW_PWM_CTRL_MODE_MASK;
30202e91208SEmmanuel Vadot 	reg |= AW_PWM_CTRL_CYCLE_MODE;
30302e91208SEmmanuel Vadot 
30402e91208SEmmanuel Vadot 	reg &= ~AW_PWM_CTRL_PULSE_START;
30502e91208SEmmanuel Vadot 	reg &= ~AW_PWM_CTRL_CLK_BYPASS;
30602e91208SEmmanuel Vadot 
30702e91208SEmmanuel Vadot 	AW_PWM_WRITE(sc, AW_PWM_CTRL, reg);
30802e91208SEmmanuel Vadot 
30902e91208SEmmanuel Vadot 	/* Write the total/active cycles */
31002e91208SEmmanuel Vadot 	reg = ((clk_rate / period_freq - 1) << AW_PWM_PERIOD_TOTAL_SHIFT) |
31102e91208SEmmanuel Vadot 	  ((clk_rate / duty_freq) << AW_PWM_PERIOD_ACTIVE_SHIFT);
31202e91208SEmmanuel Vadot 	AW_PWM_WRITE(sc, AW_PWM_PERIOD, reg);
31302e91208SEmmanuel Vadot 
31402e91208SEmmanuel Vadot 	sc->period = period;
31502e91208SEmmanuel Vadot 	sc->duty = duty;
31602e91208SEmmanuel Vadot 
31702e91208SEmmanuel Vadot 	return (0);
31802e91208SEmmanuel Vadot }
31902e91208SEmmanuel Vadot 
32002e91208SEmmanuel Vadot static int
aw_pwm_channel_get_config(device_t dev,u_int channel,u_int * period,u_int * duty)32102e91208SEmmanuel Vadot aw_pwm_channel_get_config(device_t dev, u_int channel, u_int *period, u_int *duty)
32202e91208SEmmanuel Vadot {
32302e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
32402e91208SEmmanuel Vadot 
32502e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
32602e91208SEmmanuel Vadot 
32702e91208SEmmanuel Vadot 	*period = sc->period;
32802e91208SEmmanuel Vadot 	*duty = sc->duty;
32902e91208SEmmanuel Vadot 
33002e91208SEmmanuel Vadot 	return (0);
33102e91208SEmmanuel Vadot }
33202e91208SEmmanuel Vadot 
33302e91208SEmmanuel Vadot static int
aw_pwm_channel_enable(device_t dev,u_int channel,bool enable)33402e91208SEmmanuel Vadot aw_pwm_channel_enable(device_t dev, u_int channel, bool enable)
33502e91208SEmmanuel Vadot {
33602e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
33702e91208SEmmanuel Vadot 	uint32_t reg;
33802e91208SEmmanuel Vadot 
33902e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
34002e91208SEmmanuel Vadot 
34102e91208SEmmanuel Vadot 	if (enable && sc->enabled)
34202e91208SEmmanuel Vadot 		return (0);
34302e91208SEmmanuel Vadot 
34402e91208SEmmanuel Vadot 	reg = AW_PWM_READ(sc, AW_PWM_CTRL);
34502e91208SEmmanuel Vadot 	if (enable)
34602e91208SEmmanuel Vadot 		reg |= AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN;
34702e91208SEmmanuel Vadot 	else
34802e91208SEmmanuel Vadot 		reg &= ~(AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN);
34902e91208SEmmanuel Vadot 
35002e91208SEmmanuel Vadot 	AW_PWM_WRITE(sc, AW_PWM_CTRL, reg);
35102e91208SEmmanuel Vadot 
35202e91208SEmmanuel Vadot 	sc->enabled = enable;
35302e91208SEmmanuel Vadot 
35402e91208SEmmanuel Vadot 	return (0);
35502e91208SEmmanuel Vadot }
35602e91208SEmmanuel Vadot 
35702e91208SEmmanuel Vadot static int
aw_pwm_channel_is_enabled(device_t dev,u_int channel,bool * enabled)35802e91208SEmmanuel Vadot aw_pwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled)
35902e91208SEmmanuel Vadot {
36002e91208SEmmanuel Vadot 	struct aw_pwm_softc *sc;
36102e91208SEmmanuel Vadot 
36202e91208SEmmanuel Vadot 	sc = device_get_softc(dev);
36302e91208SEmmanuel Vadot 
36402e91208SEmmanuel Vadot 	*enabled = sc->enabled;
36502e91208SEmmanuel Vadot 
36602e91208SEmmanuel Vadot 	return (0);
36702e91208SEmmanuel Vadot }
36802e91208SEmmanuel Vadot 
36902e91208SEmmanuel Vadot static device_method_t aw_pwm_methods[] = {
37002e91208SEmmanuel Vadot 	/* Device interface */
37102e91208SEmmanuel Vadot 	DEVMETHOD(device_probe,		aw_pwm_probe),
37202e91208SEmmanuel Vadot 	DEVMETHOD(device_attach,	aw_pwm_attach),
37302e91208SEmmanuel Vadot 	DEVMETHOD(device_detach,	aw_pwm_detach),
37402e91208SEmmanuel Vadot 
37502e91208SEmmanuel Vadot 	/* ofw_bus interface */
37602e91208SEmmanuel Vadot 	DEVMETHOD(ofw_bus_get_node,	aw_pwm_get_node),
37702e91208SEmmanuel Vadot 
37802e91208SEmmanuel Vadot 	/* pwmbus interface */
37902e91208SEmmanuel Vadot 	DEVMETHOD(pwmbus_channel_count,		aw_pwm_channel_count),
38002e91208SEmmanuel Vadot 	DEVMETHOD(pwmbus_channel_config,	aw_pwm_channel_config),
38102e91208SEmmanuel Vadot 	DEVMETHOD(pwmbus_channel_get_config,	aw_pwm_channel_get_config),
38202e91208SEmmanuel Vadot 	DEVMETHOD(pwmbus_channel_enable,	aw_pwm_channel_enable),
38302e91208SEmmanuel Vadot 	DEVMETHOD(pwmbus_channel_is_enabled,	aw_pwm_channel_is_enabled),
38402e91208SEmmanuel Vadot 
38502e91208SEmmanuel Vadot 	DEVMETHOD_END
38602e91208SEmmanuel Vadot };
38702e91208SEmmanuel Vadot 
38802e91208SEmmanuel Vadot static driver_t aw_pwm_driver = {
38902e91208SEmmanuel Vadot 	"pwm",
39002e91208SEmmanuel Vadot 	aw_pwm_methods,
39102e91208SEmmanuel Vadot 	sizeof(struct aw_pwm_softc),
39202e91208SEmmanuel Vadot };
39302e91208SEmmanuel Vadot 
39402e91208SEmmanuel Vadot DRIVER_MODULE(aw_pwm, simplebus, aw_pwm_driver, 0, 0);
39502e91208SEmmanuel Vadot MODULE_VERSION(aw_pwm, 1);
39602e91208SEmmanuel Vadot SIMPLEBUS_PNP_INFO(compat_data);
397