1/*	$OpenBSD: lm78_i2c.c,v 1.5 2022/04/06 18:59:28 naddy Exp $	*/
2
3/*
4 * Copyright (c) 2005 Mark Kettenis
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/device.h>
22#include <sys/sensors.h>
23
24#include <dev/i2c/i2cvar.h>
25#include <dev/ic/lm78var.h>
26
27struct lm_i2c_softc {
28	struct lm_softc sc_lmsc;
29	i2c_tag_t	sc_tag;
30	i2c_addr_t	sc_addr;
31};
32
33int lm_i2c_match(struct device *, void *, void *);
34void lm_i2c_attach(struct device *, struct device *, void *);
35u_int8_t lm_i2c_readreg(struct lm_softc *, int);
36void lm_i2c_writereg(struct lm_softc *, int, int);
37
38const struct cfattach lm_i2c_ca = {
39	sizeof(struct lm_i2c_softc), lm_i2c_match, lm_i2c_attach
40};
41
42int
43lm_i2c_match(struct device *parent, void *match, void *aux)
44{
45	struct i2c_attach_args *ia = aux;
46
47	if (strcmp(ia->ia_name, "as99127f") == 0 ||
48	    strcmp(ia->ia_name, "w83627dhg") == 0 ||
49	    strcmp(ia->ia_name, "w83627hf") == 0 ||
50	    strcmp(ia->ia_name, "w83781d") == 0 ||
51	    strcmp(ia->ia_name, "w83782d") == 0 ||
52	    strcmp(ia->ia_name, "w83783s") == 0 ||
53	    strcmp(ia->ia_name, "w83791d") == 0 ||
54	    strcmp(ia->ia_name, "w83792d") == 0) {
55		return (1);
56	}
57	/*
58	 * XXX This chip doesn't have any real sensors, but we match
59	 * it for now, just to knock out its satellites.
60	 */
61	if (strcmp(ia->ia_name, "w83791sd") == 0) {
62		return (1);
63	}
64	return (0);
65}
66
67void
68lm_i2c_attach(struct device *parent, struct device *self, void *aux)
69{
70	struct lm_i2c_softc *sc = (struct lm_i2c_softc *)self;
71	struct i2c_attach_args *ia = aux;
72	u_int8_t cmd, data;
73
74	sc->sc_tag = ia->ia_tag;
75	sc->sc_addr = ia->ia_addr;
76
77	/* Bus-independent attachment. */
78	sc->sc_lmsc.lm_writereg = lm_i2c_writereg;
79	sc->sc_lmsc.lm_readreg = lm_i2c_readreg;
80	lm_attach(&sc->sc_lmsc);
81
82	/* Remember we attached to iic(4). */
83	sc->sc_lmsc.sbusaddr = ia->ia_addr;
84
85	iic_acquire_bus(sc->sc_tag, 0);
86
87	cmd = 0x4a;
88	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
89	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
90
91	iic_release_bus(sc->sc_tag, 0);
92
93	/* Make the bus scan ignore the satellites. */
94	iic_ignore_addr(0x48 + (data & 0x7));
95	iic_ignore_addr(0x48 + ((data >> 4) & 0x7));
96}
97
98u_int8_t
99lm_i2c_readreg(struct lm_softc *lmsc, int reg)
100{
101	struct lm_i2c_softc *sc = (struct lm_i2c_softc *)lmsc;
102	u_int8_t cmd, data;
103
104	iic_acquire_bus(sc->sc_tag, 0);
105
106	cmd = reg;
107	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
108	     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
109
110	iic_release_bus(sc->sc_tag, 0);
111
112	return data;
113}
114
115void
116lm_i2c_writereg(struct lm_softc *lmsc, int reg, int val)
117{
118	struct lm_i2c_softc *sc = (struct lm_i2c_softc *)lmsc;
119	u_int8_t cmd, data;
120
121	iic_acquire_bus(sc->sc_tag, 0);
122
123	cmd = reg;
124	data = val;
125	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
126	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
127
128	iic_release_bus(sc->sc_tag, 0);
129}
130