| @@ -23,46 +23,47 @@ | | | @@ -23,46 +23,47 @@ |
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * POSSIBILITY OF SUCH DAMAGE. | | 27 | * POSSIBILITY OF SUCH DAMAGE. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | /* | | 30 | /* |
31 | * A driver for Philips Semiconductor (NXP) PCF8574/PCF857A GPIO's. | | 31 | * A driver for Philips Semiconductor (NXP) PCF8574/PCF857A GPIO's. |
32 | * Uses device properties to connect pins to the appropriate subsystem. | | 32 | * Uses device properties to connect pins to the appropriate subsystem. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: pcf8574.c,v 1.1 2020/10/29 06:55:51 jdc Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: pcf8574.c,v 1.2 2020/10/31 14:39:31 jdc Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/systm.h> | | 39 | #include <sys/systm.h> |
40 | #include <sys/device.h> | | 40 | #include <sys/device.h> |
41 | #include <sys/kernel.h> | | 41 | #include <sys/kernel.h> |
42 | | | 42 | |
43 | #include <dev/sysmon/sysmonvar.h> | | 43 | #include <dev/sysmon/sysmonvar.h> |
44 | | | 44 | |
45 | #include <dev/i2c/i2cvar.h> | | 45 | #include <dev/i2c/i2cvar.h> |
46 | #include <dev/led.h> | | 46 | #include <dev/led.h> |
47 | | | 47 | |
48 | #ifdef PCF8574_DEBUG | | 48 | #ifdef PCF8574_DEBUG |
49 | #define DPRINTF printf | | 49 | #define DPRINTF printf |
50 | #else | | 50 | #else |
51 | #define DPRINTF if (0) printf | | 51 | #define DPRINTF if (0) printf |
52 | #endif | | 52 | #endif |
53 | | | 53 | |
54 | struct pcf8574_led { | | 54 | struct pcf8574_led { |
55 | void *cookie; | | 55 | void *cookie; |
| | | 56 | struct led_device *led; |
56 | uint8_t mask, v_on, v_off; | | 57 | uint8_t mask, v_on, v_off; |
57 | }; | | 58 | }; |
58 | | | 59 | |
59 | #define PCF8574_NPINS 8 | | 60 | #define PCF8574_NPINS 8 |
60 | struct pcf8574_softc { | | 61 | struct pcf8574_softc { |
61 | device_t sc_dev; | | 62 | device_t sc_dev; |
62 | i2c_tag_t sc_tag; | | 63 | i2c_tag_t sc_tag; |
63 | i2c_addr_t sc_addr; | | 64 | i2c_addr_t sc_addr; |
64 | uint8_t sc_state; | | 65 | uint8_t sc_state; |
65 | uint8_t sc_mask; | | 66 | uint8_t sc_mask; |
66 | | | 67 | |
67 | int sc_nleds; | | 68 | int sc_nleds; |
68 | struct pcf8574_led sc_leds[PCF8574_NPINS]; | | 69 | struct pcf8574_led sc_leds[PCF8574_NPINS]; |
| @@ -205,33 +206,39 @@ pcf8574_attach(device_t parent, device_t | | | @@ -205,33 +206,39 @@ pcf8574_attach(device_t parent, device_t |
205 | sc->sc_sme->sme_refresh = pcf8574_refresh; | | 206 | sc->sc_sme->sme_refresh = pcf8574_refresh; |
206 | if (sysmon_envsys_register(sc->sc_sme)) { | | 207 | if (sysmon_envsys_register(sc->sc_sme)) { |
207 | aprint_error_dev(self, | | 208 | aprint_error_dev(self, |
208 | "unable to register with sysmon\n"); | | 209 | "unable to register with sysmon\n"); |
209 | sysmon_envsys_destroy(sc->sc_sme); | | 210 | sysmon_envsys_destroy(sc->sc_sme); |
210 | return; | | 211 | return; |
211 | } | | 212 | } |
212 | } | | 213 | } |
213 | } | | 214 | } |
214 | | | 215 | |
215 | static int | | 216 | static int |
216 | pcf8574_detach(device_t self, int flags) | | 217 | pcf8574_detach(device_t self, int flags) |
217 | { | | 218 | { |
218 | #ifdef PCF8574_DEBUG | | | |
219 | struct pcf8574_softc *sc = device_private(self); | | 219 | struct pcf8574_softc *sc = device_private(self); |
| | | 220 | int i; |
| | | 221 | |
| | | 222 | if (sc->sc_sme != NULL) |
| | | 223 | sysmon_envsys_unregister(sc->sc_sme); |
| | | 224 | |
| | | 225 | for (i = 0; i < sc->sc_nleds; i++) |
| | | 226 | led_detach(sc->sc_leds[i].led); |
220 | | | 227 | |
| | | 228 | #ifdef PCF8574_DEBUG |
221 | callout_halt(&sc->sc_timer, NULL); | | 229 | callout_halt(&sc->sc_timer, NULL); |
222 | callout_destroy(&sc->sc_timer); | | 230 | callout_destroy(&sc->sc_timer); |
223 | #endif | | 231 | #endif |
224 | | | | |
225 | return 0; | | 232 | return 0; |
226 | } | | 233 | } |
227 | | | 234 | |
228 | static int | | 235 | static int |
229 | pcf8574_read(struct pcf8574_softc *sc, uint8_t *val) | | 236 | pcf8574_read(struct pcf8574_softc *sc, uint8_t *val) |
230 | { | | 237 | { |
231 | int err = 0; | | 238 | int err = 0; |
232 | | | 239 | |
233 | if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) | | 240 | if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) |
234 | return err; | | 241 | return err; |
235 | err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 242 | err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, |
236 | sc->sc_addr, NULL, 0, val, 1, 0); | | 243 | sc->sc_addr, NULL, 0, val, 1, 0); |
237 | iic_release_bus(sc->sc_tag, 0); | | 244 | iic_release_bus(sc->sc_tag, 0); |