summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2017-06-20 15:07:17 -0500
committerLuiz Souza <luiz@netgate.com>2017-07-20 14:58:40 -0500
commit7901e9183df0f4c6cca2477a33a967d035d94c90 (patch)
tree4792805451fa9a86a70364cc1bf24484eb9568be /sys
parentb7668aa23650dc6c1b806f5b940c73fc885ab793 (diff)
downloadFreeBSD-src-7901e9183df0f4c6cca2477a33a967d035d94c90.zip
FreeBSD-src-7901e9183df0f4c6cca2477a33a967d035d94c90.tar.gz
Add initial GPIO PWM support.
(cherry picked from commit a70ecde4228d0d6f81b0eb8117e102d01a9a36eb)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/gpio/gpio_if.m77
-rw-r--r--sys/dev/gpio/gpioc.c47
-rw-r--r--sys/sys/gpio.h21
3 files changed, 142 insertions, 3 deletions
diff --git a/sys/dev/gpio/gpio_if.m b/sys/dev/gpio/gpio_if.m
index 6306f33..d25a0c7 100644
--- a/sys/dev/gpio/gpio_if.m
+++ b/sys/dev/gpio/gpio_if.m
@@ -56,6 +56,43 @@ CODE {
return (0);
}
+
+ static int
+ gpio_default_pwm_getcaps(device_t dev __unused, int32_t pwm __unused,
+ uint32_t pini __unused, uint32_t *caps)
+ {
+
+ *caps = 0;
+
+ return (0);
+ }
+
+ static int
+ gpio_default_pwm_max(device_t dev __unused, uint32_t *pwmmax)
+ {
+
+ *pwmmax = 0;
+
+ return (0);
+ }
+
+ static int
+ gpio_default_pwm_get(device_t dev __unused, uint32_t pwm __unused,
+ uint32_t pin __unused, uint32_t reg __unused,
+ uint32_t *value __unused)
+ {
+
+ return (EINVAL);
+ }
+
+ static int
+ gpio_default_pwm_set(device_t dev __unused, uint32_t pwm __unused,
+ uint32_t pin __unused, uint32_t reg __unused,
+ uint32_t value __unused)
+ {
+
+ return (EINVAL);
+ }
};
HEADER {
@@ -140,6 +177,46 @@ METHOD int pin_setflags {
};
#
+# Get maximum pwm number
+#
+METHOD int pwm_max {
+ device_t dev;
+ int *maxpwm;
+} DEFAULT gpio_default_pwm_max;
+
+#
+# Get pwm capabilities
+#
+METHOD int pwm_getcaps {
+ device_t dev;
+ int32_t pwm_num;
+ uint32_t pin_num;
+ uint32_t *caps;
+} DEFAULT gpio_default_pwm_getcaps;
+
+#
+# Get pwm settings of pin specifed by pin_num
+#
+METHOD int pwm_get {
+ device_t dev;
+ int32_t pwm_num;
+ uint32_t pin_num;
+ uint32_t pwm_reg;
+ uint32_t *pwm_value;
+} DEFAULT gpio_default_pwm_get;
+
+#
+# Set pwm settings of pin specifed by pin_num
+#
+METHOD int pwm_set {
+ device_t dev;
+ int32_t pwm_num;
+ uint32_t pin_num;
+ uint32_t pwm_reg;
+ uint32_t pwm_value;
+} DEFAULT gpio_default_pwm_set;
+
+#
# Allow the GPIO controller to map the gpio-specifier on its own.
#
METHOD int map_gpios {
diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c
index a5a9d81..2a6895a 100644
--- a/sys/dev/gpio/gpioc.c
+++ b/sys/dev/gpio/gpioc.c
@@ -121,9 +121,10 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
struct thread *td)
{
device_t bus;
- int max_pin, res;
+ int max_pin, max_pwm, res;
struct gpioc_softc *sc = cdev->si_drv1;
struct gpio_pin pin;
+ struct gpio_pwm_req pwmreq;
struct gpio_req req;
uint32_t caps;
@@ -142,9 +143,16 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
&pin.gp_flags);
/* Fail early */
- if (res)
+ if (res != 0)
+ break;
+ res = GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin,
+ &pin.gp_caps);
+ if (res != 0)
+ break;
+ res = GPIO_PWM_GETCAPS(sc->sc_pdev, -1, pin.gp_pin,
+ &pin.gp_pwm_caps);
+ if (res != 0)
break;
- GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name);
bcopy(&pin, arg, sizeof(pin));
break;
@@ -185,6 +193,39 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin,
pin.gp_name);
break;
+ case GPIOMAXPWM:
+ max_pwm = -1;
+ res = GPIO_PWM_MAX(sc->sc_pdev, &max_pwm);
+ bcopy(&max_pwm, arg, sizeof(max_pwm));
+ break;
+ case GPIOPWMGETCONFIG:
+ bcopy(arg, &pwmreq, sizeof(pwmreq));
+ res = GPIO_PWM_GETCAPS(sc->sc_pdev, pwmreq.gp_pwm,
+ pwmreq.gp_pwm_pin, &pwmreq.gp_pwm_caps);
+ dprintf("pwm getcaps pwm %d pin %d -> caps %#x\n",
+ pwmreq.gp_pwm, pwmreq.gp_pwm_pin,
+ pwmreq.gp_pwm_caps);
+ bcopy(&pwmreq, arg, sizeof(pwmreq));
+ break;
+ case GPIOPWMGET:
+ bcopy(arg, &pwmreq, sizeof(pwmreq));
+ res = GPIO_PWM_GET(sc->sc_pdev, pwmreq.gp_pwm,
+ pwmreq.gp_pwm_pin, pwmreq.gp_pwm_reg,
+ &pwmreq.gp_pwm_value);
+ dprintf("pwm get pwm %d pin %d -> reg %#x %d\n",
+ pwmreq.gp_pwm, pwmreq.gp_pwm_pin, pwmreq.gp_pwm_reg,
+ pwmreq.gp_pwm_value);
+ bcopy(&pwmreq, arg, sizeof(pwmreq));
+ break;
+ case GPIOPWMSET:
+ bcopy(arg, &pwmreq, sizeof(pwmreq));
+ res = GPIO_PWM_SET(sc->sc_pdev, pwmreq.gp_pwm,
+ pwmreq.gp_pwm_pin, pwmreq.gp_pwm_reg,
+ pwmreq.gp_pwm_value);
+ dprintf("pwm set pwm %d pin %d -> reg %#x %d\n",
+ pwmreq.gp_pwm, pwmreq.gp_pwm_pin, pwmreq.gp_pwm_reg,
+ pwmreq.gp_pwm_value);
+ break;
default:
return (ENOTTY);
break;
diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h
index 9b0a1b5..4b63baa 100644
--- a/sys/sys/gpio.h
+++ b/sys/sys/gpio.h
@@ -56,6 +56,11 @@
#define GPIO_PIN_LOW 0x00 /* low level (logical 0) */
#define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */
+/* GPIO PWM settings */
+#define GPIO_PWM_DUTY 0x01 /* PWM duty cycle */
+#define GPIO_PWM_FREQ 0x02 /* PWM frequency */
+#define GPIO_PWM_PERIOD 0x04 /* PWM period */
+
/* Max name length of a pin */
#define GPIOMAXNAME 64
@@ -70,6 +75,8 @@
#define GPIO_PIN_INVIN 0x00000080 /* invert input */
#define GPIO_PIN_INVOUT 0x00000100 /* invert output */
#define GPIO_PIN_PULSATE 0x00000200 /* pulsate in hardware */
+#define GPIO_PIN_PWM 0x00000400 /* pwm output */
+#define GPIO_PIN_MUX 0x00000800 /* pin mux */
/* GPIO interrupt capabilities */
#define GPIO_INTR_NONE 0x00000000 /* no interrupt support */
#define GPIO_INTR_LEVEL_LOW 0x00010000 /* level trigger, low */
@@ -86,6 +93,7 @@ struct gpio_pin {
char gp_name[GPIOMAXNAME]; /* human-readable name */
uint32_t gp_caps; /* capabilities */
uint32_t gp_flags; /* current flags */
+ uint32_t gp_pwm_caps; /* pwm capabilities */
};
/* GPIO pin request (read/write/toggle) */
@@ -94,6 +102,15 @@ struct gpio_req {
uint32_t gp_value; /* value */
};
+/* GPIO pwm request (read/write) */
+struct gpio_pwm_req {
+ int32_t gp_pwm; /* pwm number */
+ uint32_t gp_pwm_pin; /* pin number */
+ uint32_t gp_pwm_reg; /* register */
+ uint32_t gp_pwm_value; /* value */
+ uint32_t gp_pwm_caps; /* pwm capabilities */
+};
+
/*
* ioctls
*/
@@ -104,5 +121,9 @@ struct gpio_req {
#define GPIOSET _IOW('G', 4, struct gpio_req)
#define GPIOTOGGLE _IOWR('G', 5, struct gpio_req)
#define GPIOSETNAME _IOW('G', 6, struct gpio_pin)
+#define GPIOMAXPWM _IOR('G', 7, int)
+#define GPIOPWMGETCONFIG _IOWR('G', 8, struct gpio_pwm_req)
+#define GPIOPWMGET _IOWR('G', 9, struct gpio_pwm_req)
+#define GPIOPWMSET _IOW('G', 10, struct gpio_pwm_req)
#endif /* __GPIO_H__ */
OpenPOWER on IntegriCloud