Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/gpio gpiopwm(4) is a driver to pulse GPIO pins in so...
details: https://anonhg.NetBSD.org/src/rev/0dd049637c83
branches: trunk
changeset: 771162:0dd049637c83
user: mbalmer <mbalmer%NetBSD.org@localhost>
date: Sun Nov 13 12:33:00 2011 +0000
description:
gpiopwm(4) is a driver to pulse GPIO pins in software. This obsoletes
the software pulsing facilities in gpio(4) (and gpioctl(8)) which will
later be removed.
diffstat:
sys/dev/gpio/files.gpio | 7 +-
sys/dev/gpio/gpiopwm.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 252 insertions(+), 1 deletions(-)
diffs (268 lines):
diff -r 3d87f2c56179 -r 0dd049637c83 sys/dev/gpio/files.gpio
--- a/sys/dev/gpio/files.gpio Sun Nov 13 09:46:11 2011 +0000
+++ b/sys/dev/gpio/files.gpio Sun Nov 13 12:33:00 2011 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.gpio,v 1.9 2011/10/02 10:01:25 mbalmer Exp $
+# $NetBSD: files.gpio,v 1.10 2011/11/13 12:33:00 mbalmer Exp $
define gpio {[offset = -1], [mask = 0], [flag = 0]}
@@ -24,3 +24,8 @@
device gpiolock: gpiobus
attach gpiolock at gpio
file dev/gpio/gpiolock.c gpiolock
+
+# PWM
+device gpiopwm: gpiobus
+attach gpiopwm at gpio
+file dev/gpio/gpiopwm.c gpiopwm
diff -r 3d87f2c56179 -r 0dd049637c83 sys/dev/gpio/gpiopwm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/gpio/gpiopwm.c Sun Nov 13 12:33:00 2011 +0000
@@ -0,0 +1,246 @@
+/* $NetBSD: gpiopwm.c,v 1.1 2011/11/13 12:33:01 mbalmer Exp $ */
+
+/*
+ * Copyright (c) 2011 Marc Balmer <marc%msys.ch@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for pulsing GPIO pins in software
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/gpio.h>
+#include <sys/sysctl.h>
+
+#include <dev/gpio/gpiovar.h>
+
+#define GPIOPWM_NPINS 1
+
+struct gpiopwm_softc {
+ device_t sc_dev;
+ void *sc_gpio;
+ struct gpio_pinmap sc_map;
+ int _map[GPIOPWM_NPINS];
+
+ callout_t sc_pulse;
+ int sc_ticks_on;
+ int sc_ticks_off;
+
+ struct sysctllog *sc_log;
+ int sc_dying;
+};
+
+int gpiopwm_match(device_t, cfdata_t, void *);
+void gpiopwm_attach(device_t, device_t, void *);
+int gpiopwm_detach(device_t, int);
+int gpiopwm_activate(device_t, enum devact);
+static int gpiopwm_set_on(SYSCTLFN_ARGS);
+static int gpiopwm_set_off(SYSCTLFN_ARGS);
+static void gpiopwm_pulse(void *);
+
+CFATTACH_DECL_NEW(gpiopwm, sizeof(struct gpiopwm_softc),
+ gpiopwm_match, gpiopwm_attach, gpiopwm_detach, gpiopwm_activate);
+
+extern struct cfdriver gpiopwm_cd;
+
+int
+gpiopwm_match(device_t parent, cfdata_t cf,
+ void *aux)
+{
+ struct gpio_attach_args *ga = aux;
+
+ if (strcmp(ga->ga_dvname, cf->cf_name))
+ return 0;
+
+ if (ga->ga_offset == -1)
+ return 0;
+
+ /* Check number of pins, must be 1 */
+ if (gpio_npins(ga->ga_mask) != GPIOPWM_NPINS) {
+ aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name,
+ ga->ga_mask);
+ return 0;
+ }
+ return 1;
+}
+
+void
+gpiopwm_attach(device_t parent, device_t self, void *aux)
+{
+ struct gpiopwm_softc *sc = device_private(self);
+ struct gpio_attach_args *ga = aux;
+ const struct sysctlnode *node;
+
+ sc->sc_dev = self;
+
+ /* Map pin */
+ sc->sc_gpio = ga->ga_gpio;
+ sc->sc_map.pm_map = sc->_map;
+ if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
+ &sc->sc_map)) {
+ aprint_error(": can't map pin\n");
+ return;
+ }
+ aprint_normal(" [%d]", sc->sc_map.pm_map[0]);
+ pmf_device_register(self, NULL, NULL);
+
+ callout_init(&sc->sc_pulse, CALLOUT_MPSAFE);
+ callout_setfunc(&sc->sc_pulse, gpiopwm_pulse, sc);
+
+ sysctl_createv(NULL, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "hw", NULL,
+ NULL, 0, NULL, 0,
+ CTL_HW, CTL_EOL);
+ sysctl_createv(&sc->sc_log, 0, NULL, &node,
+ 0,
+ CTLTYPE_NODE, device_xname(sc->sc_dev),
+ SYSCTL_DESCR("GPIO software PWM"),
+ NULL, 0, NULL, 0,
+ CTL_HW, CTL_CREATE, CTL_EOL);
+
+ if (node == NULL) {
+ printf(": can't create sysctl node\n");
+ return;
+ }
+
+ sysctl_createv(&sc->sc_log, 0, &node, NULL,
+ CTLFLAG_READWRITE,
+ CTLTYPE_INT, "on",
+ SYSCTL_DESCR("PWM 'on' period in ticks"),
+ gpiopwm_set_on, 0, sc, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(&sc->sc_log, 0, &node, NULL,
+ CTLFLAG_READWRITE,
+ CTLTYPE_INT, "off",
+ SYSCTL_DESCR("PWM 'off' period in ticks"),
+ gpiopwm_set_off, 0, sc, 0,
+ CTL_CREATE, CTL_EOL);
+
+ aprint_normal("\n");
+ return;
+}
+
+int
+gpiopwm_detach(device_t self, int flags)
+{
+ struct gpiopwm_softc *sc = device_private(self);
+
+ callout_halt(&sc->sc_pulse, NULL);
+ callout_destroy(&sc->sc_pulse);
+
+ pmf_device_deregister(self);
+ gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
+
+ if (sc->sc_log != NULL) {
+ sysctl_teardown(&sc->sc_log);
+ sc->sc_log = NULL;
+ }
+ return 0;
+}
+
+static int
+gpiopwm_set_on(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ struct gpiopwm_softc *sc;
+ int val, error;
+
+ node = *rnode;
+ sc = node.sysctl_data;
+
+ callout_halt(&sc->sc_pulse, NULL);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_LOW);
+ node.sysctl_data = &val;
+
+ val = sc->sc_ticks_on;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ return error;
+
+ sc->sc_ticks_on = val;
+ if (sc->sc_ticks_on > 0 && sc->sc_ticks_off > 0) {
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_HIGH);
+ callout_schedule(&sc->sc_pulse, sc->sc_ticks_on);
+ }
+ return 0;
+}
+
+static int
+gpiopwm_set_off(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ struct gpiopwm_softc *sc;
+ int val, error;
+
+ node = *rnode;
+ sc = node.sysctl_data;
+
+ callout_halt(&sc->sc_pulse, NULL);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_LOW);
+ node.sysctl_data = &val;
+
+ val = sc->sc_ticks_off;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ return error;
+
+ sc->sc_ticks_off = val;
+ if (sc->sc_ticks_on > 0 && sc->sc_ticks_off > 0) {
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_HIGH);
+ callout_schedule(&sc->sc_pulse, sc->sc_ticks_on);
+ }
+ return 0;
+}
+
+static void
+gpiopwm_pulse(void *arg)
+{
+ struct gpiopwm_softc *sc;
+
+ sc = arg;
+ if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, 0) == GPIO_PIN_HIGH) {
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_LOW);
+ callout_schedule(&sc->sc_pulse, sc->sc_ticks_off);
+ } else {
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, 0, GPIO_PIN_HIGH);
+ callout_schedule(&sc->sc_pulse, sc->sc_ticks_on);
+ }
+}
+
+int
+gpiopwm_activate(device_t self, enum devact act)
+{
+ struct gpiopwm_softc *sc = device_private(self);
+
+ switch (act) {
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ return 0;
+ default:
+ return EOPNOTSUPP;
+ }
+
+}
Home |
Main Index |
Thread Index |
Old Index