Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c attach LEDs according to info passed as device p...



details:   https://anonhg.NetBSD.org/src/rev/699e336df235
branches:  trunk
changeset: 744464:699e336df235
user:      macallan <macallan%NetBSD.org@localhost>
date:      Sun Feb 02 06:41:27 2020 +0000

description:
attach LEDs according to info passed as device properties

diffstat:

 sys/dev/i2c/files.i2c |    4 +-
 sys/dev/i2c/pcagpio.c |  109 +++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 102 insertions(+), 11 deletions(-)

diffs (216 lines):

diff -r e69241894458 -r 699e336df235 sys/dev/i2c/files.i2c
--- a/sys/dev/i2c/files.i2c     Sun Feb 02 06:38:23 2020 +0000
+++ b/sys/dev/i2c/files.i2c     Sun Feb 02 06:41:27 2020 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.i2c,v 1.109 2020/01/29 05:27:05 macallan Exp $
+#      $NetBSD: files.i2c,v 1.110 2020/02/02 06:41:27 macallan Exp $
 
 obsolete defflag       opt_i2cbus.h            I2C_SCAN
 define i2cbus { }
@@ -387,6 +387,6 @@
 file   dev/i2c/cwfg.c                          cwfg
 
 # Philips PCA955x GPIO
-device pcagpio
+device pcagpio: leds
 attach pcagpio at iic
 file   dev/i2c/pcagpio.c                       pcagpio
diff -r e69241894458 -r 699e336df235 sys/dev/i2c/pcagpio.c
--- a/sys/dev/i2c/pcagpio.c     Sun Feb 02 06:38:23 2020 +0000
+++ b/sys/dev/i2c/pcagpio.c     Sun Feb 02 06:41:27 2020 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: pcagpio.c,v 1.1 2020/01/29 05:27:05 macallan Exp $ */
+/* $NetBSD: pcagpio.c,v 1.2 2020/02/02 06:41:27 macallan Exp $ */
 
 /*-
- * Copyright (c) 2018 Michael Lorenz
+ * Copyright (c) 2020 Michael Lorenz
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pcagpio.c,v 1.1 2020/01/29 05:27:05 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pcagpio.c,v 1.2 2020/02/02 06:41:27 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,6 +40,13 @@
 #include <sys/bus.h>
 
 #include <dev/i2c/i2cvar.h>
+#include <dev/led.h>
+
+#ifdef PCAGPIO_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF if (0) printf
+#endif
 
 /* commands */
 #define PCAGPIO_INPUT  0x00    /* line status */
@@ -50,17 +57,29 @@
 static int     pcagpio_match(device_t, cfdata_t, void *);
 static void    pcagpio_attach(device_t, device_t, void *);
 
+/* we can only pass one cookie to led_attach() but we need several values... */
+struct pcagpio_led {
+       void *cookie;
+       uint32_t mask, v_on, v_off;
+};
+
 struct pcagpio_softc {
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
 
        int             sc_is_16bit;
+       uint32_t        sc_state;
+       struct pcagpio_led sc_leds[16];
+       int             sc_nleds;
 };
 
 
 static void    pcagpio_writereg(struct pcagpio_softc *, int, uint32_t);
 static uint32_t pcagpio_readreg(struct pcagpio_softc *, int);
+static void    pcagpio_attach_led(struct pcagpio_softc *, char *, int, int, int);
+static int     pcagpio_get(void *);
+static void    pcagpio_set(void *, int);
 
 CFATTACH_DECL_NEW(pcagpio, sizeof(struct pcagpio_softc),
     pcagpio_match, pcagpio_attach, NULL, NULL);
@@ -85,6 +104,7 @@
        return 0;
 }
 
+#ifdef PCAGPIO_DEBUG
 static void
 printdir(uint32_t val, uint32_t mask, char letter)
 {
@@ -103,6 +123,7 @@
        printf("dir: %s\n", flags);
        printf("lvl: %s\n", bits);
 }      
+#endif
 
 static void
 pcagpio_attach(device_t parent, device_t self, void *aux)
@@ -110,11 +131,14 @@
        struct pcagpio_softc *sc = device_private(self);
        struct i2c_attach_args *ia = aux;
        const struct device_compatible_entry *dce;
-       uint32_t dir, in, out;
+       prop_dictionary_t dict = device_properties(self);
+       prop_array_t pins;
+       prop_dictionary_t pin;
 
        sc->sc_dev = self;
        sc->sc_i2c = ia->ia_tag;
        sc->sc_addr = ia->ia_addr;
+       sc->sc_nleds = 0;
 
        aprint_naive("\n");
        sc->sc_is_16bit = 0;
@@ -123,17 +147,43 @@
 
        aprint_normal(": %s\n", sc->sc_is_16bit ? "PCA9555" : "PCA9556");
 
-       if (sc->sc_addr == 0x38) pcagpio_writereg(sc, 1, 0xff & ~0x10);
-       
-       dir = pcagpio_readreg(sc, 3);
-       in = pcagpio_readreg(sc, 0);
-       out = pcagpio_readreg(sc, 1);
+       sc->sc_state = pcagpio_readreg(sc, PCAGPIO_OUTPUT);
+
+#ifdef PCAGPIO_DEBUG
+       uint32_t dir, in, out;
+       dir = pcagpio_readreg(sc, PCAGPIO_CONFIG);
+       in = pcagpio_readreg(sc, PCAGPIO_INPUT);
+       out = sc->sc_state;
 
        out &= ~dir;
        in &= dir;
        
        printdir(in, dir, 'I');
        printdir(out, ~dir, 'O');
+#endif
+
+       pins = prop_dictionary_get(dict, "pins");
+       if (pins != NULL) {
+               int i, num, def;
+               char name[32];
+               const char *nptr;
+               bool ok = TRUE, act;
+
+               for (i = 0; i < prop_array_count(pins); i++) {
+                       nptr = NULL;
+                       pin = prop_array_get(pins, i);
+                       ok &= prop_dictionary_get_cstring_nocopy(pin, "name", &nptr);
+                       strncpy(name, nptr, 31);
+                       ok &= prop_dictionary_get_uint32(pin, "pin", &num);
+                       ok &= prop_dictionary_get_bool(pin, "active_high", &act);
+                       /* optional default state */
+                       def = -1;
+                       prop_dictionary_get_int32(pin, "default_state", &def);
+                       if (ok) {               
+                               pcagpio_attach_led(sc, name, num, act, def);
+                       }
+               }
+       }
 }
 
 static void
@@ -155,6 +205,7 @@
                iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP,
                    sc->sc_addr, &cmd, 1, &creg, 1, 0);
        }
+       if (reg == PCAGPIO_OUTPUT) sc->sc_state = val;
        iic_release_bus(sc->sc_i2c, 0);
 }              
 
@@ -180,3 +231,43 @@
        iic_release_bus(sc->sc_i2c, 0);
        return ret;
 }
+
+static void
+pcagpio_attach_led(struct pcagpio_softc *sc, char *n, int pin, int act, int def)
+{
+       struct pcagpio_led *l;
+
+       l = &sc->sc_leds[sc->sc_nleds];
+       l->cookie = sc;
+       l->mask = 1 << pin;
+       l->v_on = act ? l->mask : 0;
+       l->v_off = act ? 0 : l->mask;
+       led_attach(n, l, pcagpio_get, pcagpio_set);
+       if (def != -1) pcagpio_set(l, def);
+       DPRINTF("%s: %04x %04x %04x def %d\n", __func__, l->mask, l->v_on, l->v_off, def);
+       sc->sc_nleds++;
+}
+
+static int
+pcagpio_get(void *cookie)
+{
+       struct pcagpio_led *l = cookie;
+       struct pcagpio_softc *sc = l->cookie;
+
+       return ((sc->sc_state & l->mask) == l->v_on);
+}
+
+static void
+pcagpio_set(void *cookie, int val)
+{
+       struct pcagpio_led *l = cookie;
+       struct pcagpio_softc *sc = l->cookie;
+       uint32_t newstate;      
+
+       newstate = sc->sc_state & ~l->mask;
+       newstate |= val ? l->v_on : l->v_off;
+       DPRINTF("%s: %04x -> %04x, %04x %04x %04x\n", __func__,
+           sc->sc_state, newstate, l->mask, l->v_on, l->v_off);
+       if (newstate != sc->sc_state)
+               pcagpio_writereg(sc, PCAGPIO_OUTPUT, newstate);
+}



Home | Main Index | Thread Index | Old Index