g760a.c revision 1.2 1 1.2 pgoyette /* $NetBSD: g760a.c,v 1.2 2011/06/20 20:16:19 pgoyette Exp $ */
2 1.1 kiyohara
3 1.1 kiyohara /*-
4 1.1 kiyohara * Copyright (C) 2008 A.Leo.
5 1.1 kiyohara *
6 1.1 kiyohara * Redistribution and use in source and binary forms, with or without
7 1.1 kiyohara * modification, are permitted provided that the following conditions
8 1.1 kiyohara * are met:
9 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright
10 1.1 kiyohara * notice, this list of conditions and the following disclaimer.
11 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the
13 1.1 kiyohara * documentation and/or other materials provided with the distribution.
14 1.1 kiyohara * 3. The name of the author may not be used to endorse or promote products
15 1.1 kiyohara * derived from this software without specific prior written permission.
16 1.1 kiyohara *
17 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.1 kiyohara * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.1 kiyohara * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.1 kiyohara * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1.1 kiyohara * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.1 kiyohara * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.1 kiyohara * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.1 kiyohara * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 1.1 kiyohara * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.1 kiyohara */
28 1.1 kiyohara
29 1.1 kiyohara /*
30 1.1 kiyohara * The driver for the G760A FAN Speed PWM controller.
31 1.1 kiyohara */
32 1.1 kiyohara
33 1.1 kiyohara #include <sys/cdefs.h>
34 1.1 kiyohara
35 1.2 pgoyette __KERNEL_RCSID(0, "$NetBSD: g760a.c,v 1.2 2011/06/20 20:16:19 pgoyette Exp $");
36 1.1 kiyohara
37 1.1 kiyohara #include <sys/param.h>
38 1.1 kiyohara #include <sys/systm.h>
39 1.1 kiyohara #include <sys/device.h>
40 1.1 kiyohara #include <sys/kernel.h>
41 1.1 kiyohara #include <sys/conf.h>
42 1.1 kiyohara #include <sys/sysctl.h>
43 1.1 kiyohara
44 1.1 kiyohara #include <dev/sysmon/sysmonvar.h>
45 1.1 kiyohara
46 1.1 kiyohara #include <dev/i2c/i2cvar.h>
47 1.1 kiyohara #include <dev/i2c/g760areg.h>
48 1.1 kiyohara
49 1.1 kiyohara
50 1.1 kiyohara struct g760a_softc {
51 1.1 kiyohara device_t sc_dev;
52 1.1 kiyohara struct sysmon_envsys *sc_sme;
53 1.1 kiyohara
54 1.1 kiyohara envsys_data_t sc_sensor;
55 1.1 kiyohara i2c_tag_t sc_tag;
56 1.1 kiyohara int sc_addr;
57 1.1 kiyohara };
58 1.1 kiyohara
59 1.1 kiyohara static int g760a_match(device_t, struct cfdata*, void*);
60 1.1 kiyohara static void g760a_attach(device_t, device_t, void*);
61 1.1 kiyohara static void g760a_setup(struct g760a_softc*);
62 1.1 kiyohara static uint8_t g760a_readreg(struct g760a_softc*, uint8_t);
63 1.1 kiyohara static void g760a_writereg(struct g760a_softc*, uint8_t, uint8_t);
64 1.1 kiyohara
65 1.1 kiyohara static int g760a_reg2rpm(int);
66 1.1 kiyohara
67 1.1 kiyohara static void g760a_refresh(struct sysmon_envsys*, envsys_data_t*);
68 1.1 kiyohara static int sysctl_g760a_rpm(SYSCTLFN_PROTO);
69 1.1 kiyohara
70 1.1 kiyohara CFATTACH_DECL_NEW(g760a, sizeof(struct g760a_softc),
71 1.1 kiyohara g760a_match, g760a_attach, NULL, NULL);
72 1.1 kiyohara
73 1.1 kiyohara static int
74 1.1 kiyohara g760a_match(device_t parent, struct cfdata* cf, void* arg)
75 1.1 kiyohara {
76 1.1 kiyohara struct i2c_attach_args* ia = arg;
77 1.1 kiyohara
78 1.1 kiyohara if (ia->ia_addr == G760A_ADDR) {
79 1.1 kiyohara /*
80 1.1 kiyohara * TODO: set up minimal speed?
81 1.1 kiyohara */
82 1.1 kiyohara return 1;
83 1.1 kiyohara }
84 1.1 kiyohara
85 1.1 kiyohara return 0;
86 1.1 kiyohara }
87 1.1 kiyohara
88 1.1 kiyohara
89 1.1 kiyohara static void
90 1.1 kiyohara g760a_attach(device_t parent, device_t self, void* arg)
91 1.1 kiyohara {
92 1.1 kiyohara struct i2c_attach_args* ia = arg;
93 1.1 kiyohara struct g760a_softc* sc = device_private(self);
94 1.1 kiyohara
95 1.1 kiyohara aprint_normal(": G760A Fan Controller\n");
96 1.1 kiyohara
97 1.1 kiyohara sc->sc_dev = self;
98 1.1 kiyohara sc->sc_tag = ia->ia_tag;
99 1.1 kiyohara sc->sc_addr = ia->ia_addr;
100 1.1 kiyohara
101 1.1 kiyohara g760a_setup(sc);
102 1.1 kiyohara }
103 1.1 kiyohara
104 1.1 kiyohara
105 1.1 kiyohara static int
106 1.1 kiyohara g760a_reg2rpm(int n)
107 1.1 kiyohara {
108 1.1 kiyohara if(n == 255)
109 1.1 kiyohara return 0;
110 1.1 kiyohara
111 1.1 kiyohara if(n == 0)
112 1.1 kiyohara return 255;
113 1.1 kiyohara
114 1.1 kiyohara return G760A_N2RPM(n);
115 1.1 kiyohara }
116 1.1 kiyohara
117 1.1 kiyohara
118 1.1 kiyohara static uint8_t
119 1.1 kiyohara g760a_readreg(struct g760a_softc* sc, uint8_t reg)
120 1.1 kiyohara {
121 1.1 kiyohara uint8_t data;
122 1.1 kiyohara
123 1.1 kiyohara if (iic_acquire_bus(sc->sc_tag, 0)) {
124 1.1 kiyohara aprint_error_dev(sc->sc_dev, "unable to acquire the iic bus\n");
125 1.1 kiyohara return 0;
126 1.1 kiyohara }
127 1.1 kiyohara
128 1.1 kiyohara iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, ®, 1,
129 1.1 kiyohara &data, 1, 0);
130 1.1 kiyohara iic_release_bus(sc->sc_tag, 0);
131 1.1 kiyohara
132 1.1 kiyohara return data;
133 1.1 kiyohara }
134 1.1 kiyohara
135 1.1 kiyohara
136 1.1 kiyohara static void
137 1.1 kiyohara g760a_writereg(struct g760a_softc* sc, uint8_t reg, uint8_t data)
138 1.1 kiyohara {
139 1.1 kiyohara
140 1.1 kiyohara if (iic_acquire_bus(sc->sc_tag, 0)) {
141 1.1 kiyohara aprint_error_dev(sc->sc_dev, "unable to acquire the iic bus\n");
142 1.1 kiyohara return;
143 1.1 kiyohara }
144 1.1 kiyohara
145 1.1 kiyohara iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, ®, 1,
146 1.1 kiyohara &data, 1, 0);
147 1.1 kiyohara iic_release_bus(sc->sc_tag, 0);
148 1.1 kiyohara }
149 1.1 kiyohara
150 1.1 kiyohara
151 1.1 kiyohara SYSCTL_SETUP(sysctl_g760a_setup, "sysctl g760a subtree setup")
152 1.1 kiyohara {
153 1.1 kiyohara
154 1.1 kiyohara sysctl_createv(NULL, 0, NULL, NULL,
155 1.1 kiyohara CTLFLAG_PERMANENT,
156 1.1 kiyohara CTLTYPE_NODE, "machdep", NULL,
157 1.1 kiyohara NULL, 0, NULL, 0,
158 1.1 kiyohara CTL_MACHDEP, CTL_EOL);
159 1.1 kiyohara }
160 1.1 kiyohara
161 1.1 kiyohara
162 1.1 kiyohara /*ARGUSED*/
163 1.1 kiyohara static int
164 1.1 kiyohara sysctl_g760a_rpm(SYSCTLFN_ARGS)
165 1.1 kiyohara {
166 1.1 kiyohara int error, t;
167 1.1 kiyohara struct sysctlnode node;
168 1.1 kiyohara struct g760a_softc* sc;
169 1.1 kiyohara
170 1.1 kiyohara node = *rnode;
171 1.1 kiyohara sc = node.sysctl_data;
172 1.1 kiyohara
173 1.1 kiyohara t = g760a_readreg(sc, G760A_REG_SET_CNT);
174 1.1 kiyohara t = g760a_reg2rpm(t);
175 1.1 kiyohara
176 1.1 kiyohara node.sysctl_data = &t;
177 1.1 kiyohara
178 1.1 kiyohara error = sysctl_lookup(SYSCTLFN_CALL(&node));
179 1.1 kiyohara
180 1.1 kiyohara if (error || newp == NULL)
181 1.1 kiyohara return error;
182 1.1 kiyohara
183 1.1 kiyohara if (t > 20000 || t < G760A_N2RPM(254))
184 1.1 kiyohara return EINVAL;
185 1.1 kiyohara
186 1.1 kiyohara t = g760a_reg2rpm(t);
187 1.1 kiyohara
188 1.1 kiyohara g760a_writereg(sc, G760A_REG_SET_CNT, t);
189 1.1 kiyohara
190 1.1 kiyohara return 0;
191 1.1 kiyohara }
192 1.1 kiyohara
193 1.1 kiyohara
194 1.1 kiyohara static void
195 1.1 kiyohara g760a_refresh(struct sysmon_envsys* sme, envsys_data_t* edata)
196 1.1 kiyohara {
197 1.1 kiyohara struct g760a_softc* sc = sme->sme_cookie;
198 1.1 kiyohara
199 1.1 kiyohara switch (edata->units) {
200 1.1 kiyohara case ENVSYS_SFANRPM:
201 1.1 kiyohara {
202 1.1 kiyohara uint8_t n;
203 1.1 kiyohara
204 1.1 kiyohara n = g760a_readreg(sc, G760A_REG_ACT_CNT);
205 1.1 kiyohara edata->value_cur = g760a_reg2rpm(n);
206 1.1 kiyohara }
207 1.1 kiyohara break;
208 1.1 kiyohara default:
209 1.1 kiyohara aprint_error_dev(sc->sc_dev, "oops\n");
210 1.1 kiyohara }
211 1.1 kiyohara
212 1.1 kiyohara edata->state = ENVSYS_SVALID;
213 1.1 kiyohara }
214 1.1 kiyohara
215 1.1 kiyohara
216 1.1 kiyohara static void
217 1.1 kiyohara g760a_setup(struct g760a_softc* sc)
218 1.1 kiyohara {
219 1.1 kiyohara int error;
220 1.1 kiyohara int ret;
221 1.1 kiyohara struct sysctlnode* me = NULL, * node = NULL;
222 1.1 kiyohara
223 1.1 kiyohara sc->sc_sme = sysmon_envsys_create();
224 1.1 kiyohara
225 1.1 kiyohara ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode**)&me,
226 1.1 kiyohara CTLFLAG_READWRITE,
227 1.1 kiyohara CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
228 1.1 kiyohara NULL, 0, NULL, 0,
229 1.1 kiyohara CTL_MACHDEP, CTL_CREATE, CTL_EOL);
230 1.1 kiyohara
231 1.1 kiyohara (void)strlcpy(sc->sc_sensor.desc, "sysfan rpm",
232 1.1 kiyohara sizeof(sc->sc_sensor.desc));
233 1.1 kiyohara sc->sc_sensor.units = ENVSYS_SFANRPM;
234 1.2 pgoyette sc->sc_sensor.state = ENVSYS_SINVALID;
235 1.1 kiyohara
236 1.1 kiyohara if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor))
237 1.1 kiyohara goto out;
238 1.1 kiyohara
239 1.1 kiyohara ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode**)&node,
240 1.1 kiyohara CTLFLAG_READWRITE,
241 1.1 kiyohara CTLTYPE_INT, "rpm", sc->sc_sensor.desc,
242 1.1 kiyohara sysctl_g760a_rpm, 0x42, NULL, 0,
243 1.1 kiyohara CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
244 1.1 kiyohara if (node != NULL)
245 1.1 kiyohara node->sysctl_data = sc;
246 1.1 kiyohara
247 1.1 kiyohara sc->sc_sme->sme_name = device_xname(sc->sc_dev);
248 1.1 kiyohara sc->sc_sme->sme_cookie = sc;
249 1.1 kiyohara sc->sc_sme->sme_refresh = g760a_refresh;
250 1.1 kiyohara
251 1.1 kiyohara error = sysmon_envsys_register(sc->sc_sme);
252 1.1 kiyohara
253 1.1 kiyohara if (error) {
254 1.1 kiyohara aprint_error_dev(sc->sc_dev,
255 1.1 kiyohara "unable to register with sysmon. errorcode %i\n", error);
256 1.1 kiyohara goto out;
257 1.1 kiyohara }
258 1.1 kiyohara
259 1.1 kiyohara return;
260 1.1 kiyohara out:
261 1.1 kiyohara sysmon_envsys_destroy(sc->sc_sme);
262 1.1 kiyohara }
263