Annotation of src/sys/dev/isa/smsc.c, Revision 1.7
1.7 ! xtraeme 1: /* $NetBSD: smsc.c,v 1.6 2007/11/17 08:30:35 kefren Exp $ */
1.1 blymn 2:
3: /*-
4: * Copyright (c) 2007 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Brett Lymn.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*
40: * This is a driver for the Standard Microsystems Corp (SMSC)
41: * LPC47B397 "super i/o" chip. This driver only handles the environment
42: * monitoring capabilities of the chip, the other functions will be
43: * probed/matched as "normal" PC hardware devices (serial ports, fdc, so on).
44: * SMSC has not deigned to release a datasheet for this particular chip
45: * (though they do for others they make) so this driver was written from
46: * information contained in the comment block for the Linux driver.
47: */
48:
49: #include <sys/cdefs.h>
1.7 ! xtraeme 50: __KERNEL_RCSID(0, "$NetBSD: smsc.c,v 1.6 2007/11/17 08:30:35 kefren Exp $");
1.1 blymn 51:
52: #include <sys/param.h>
53: #include <sys/systm.h>
54: #include <sys/device.h>
1.4 ad 55: #include <sys/bus.h>
1.1 blymn 56:
57: #include <dev/isa/isareg.h>
58: #include <dev/isa/isavar.h>
59:
60: #include <dev/sysmon/sysmonvar.h>
61: #include <dev/isa/smscvar.h>
62:
63: #if defined(LMDEBUG)
64: #define DPRINTF(x) do { printf x; } while (0)
65: #else
66: #define DPRINTF(x)
67: #endif
68:
1.7 ! xtraeme 69: static int smsc_match(device_t, cfdata_t, void *);
! 70: static void smsc_attach(device_t, device_t, void *);
! 71: static int smsc_detach(device_t, int);
! 72:
! 73: static uint8_t smsc_readreg(bus_space_tag_t, bus_space_handle_t, int);
! 74: static void smsc_writereg(bus_space_tag_t, bus_space_handle_t, int, int);
1.1 blymn 75:
1.5 xtraeme 76: static void smsc_refresh(struct sysmon_envsys *, envsys_data_t *);
1.1 blymn 77:
1.7 ! xtraeme 78: CFATTACH_DECL_NEW(smsc, sizeof(struct smsc_softc),
1.5 xtraeme 79: smsc_match, smsc_attach, smsc_detach, NULL);
1.1 blymn 80:
81: /*
82: * Probe for the SMSC Super I/O chip
83: */
1.5 xtraeme 84: static int
1.7 ! xtraeme 85: smsc_match(device_t parent, cfdata_t match, void *aux)
1.1 blymn 86: {
87: bus_space_handle_t ioh;
88: struct isa_attach_args *ia = aux;
89: int rv;
90: uint8_t cr;
91:
92: /* Must supply an address */
93: if (ia->ia_nio < 1)
94: return 0;
95:
96: if (ISA_DIRECT_CONFIG(ia))
97: return 0;
98:
99: if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
100: return 0;
101:
102: if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh))
103: return 0;
104:
105: /* To get the device ID we must enter config mode... */
106: bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START);
107:
108: /* Then select the device id register */
1.7 ! xtraeme 109: cr = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID);
1.1 blymn 110:
111: /* Exit config mode, apparently this is important to do */
112: bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END);
113:
1.7 ! xtraeme 114: switch (cr) {
! 115: case SMSC_ID_47B397:
! 116: case SMSC_ID_SCH5307NS:
! 117: case SMSC_ID_SCH5317:
1.1 blymn 118: rv = 1;
1.7 ! xtraeme 119: break;
! 120: default:
1.1 blymn 121: rv = 0;
1.7 ! xtraeme 122: break;
! 123: }
1.1 blymn 124:
125: DPRINTF(("smsc: rv = %d, cr = %x\n", rv, cr));
126:
127: bus_space_unmap(ia->ia_iot, ioh, 2);
128:
129: if (rv) {
130: ia->ia_nio = 1;
131: ia->ia_io[0].ir_size = 2;
132:
133: ia->ia_niomem = 0;
134: ia->ia_nirq = 0;
135: ia->ia_ndrq = 0;
136: }
137:
138: return rv;
139: }
140:
141: /*
142: * Get the base address for the monitoring registers and set up the
1.7 ! xtraeme 143: * sysmon_envsys(9) framework.
1.1 blymn 144: */
1.5 xtraeme 145: static void
1.7 ! xtraeme 146: smsc_attach(device_t parent, device_t self, void *aux)
1.1 blymn 147: {
1.5 xtraeme 148: struct smsc_softc *sc = device_private(self);
1.1 blymn 149: struct isa_attach_args *ia = aux;
150: bus_space_handle_t ioh;
1.7 ! xtraeme 151: uint8_t rev, msb, lsb, chipid;
1.1 blymn 152: unsigned address;
1.5 xtraeme 153: int i;
1.1 blymn 154:
1.5 xtraeme 155: sc->sc_iot = ia->ia_iot;
1.1 blymn 156:
1.7 ! xtraeme 157: aprint_naive("\n");
! 158:
! 159: /*
! 160: * To attach we need to find the actual Hardware Monitor
! 161: * I/O address space.
! 162: */
1.1 blymn 163: if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0,
164: &ioh)) {
165: aprint_error(": can't map base i/o space\n");
166: return;
167: }
168:
1.7 ! xtraeme 169: /* Enter config mode */
1.1 blymn 170: bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START);
171:
1.7 ! xtraeme 172: /*
! 173: * While we have the base registers mapped, grab the chip
! 174: * revision and device ID.
! 175: */
! 176: rev = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_REVISION);
! 177: chipid = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID);
! 178:
! 179: /* Select the Hardware Monitor LDN */
! 180: smsc_writereg(ia->ia_iot, ioh, SMSC_LOGICAL_DEV_SEL,
! 181: SMSC_LOGICAL_DEVICE);
1.1 blymn 182:
183: /* Read the base address for the registers. */
1.7 ! xtraeme 184: msb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_MSB);
! 185: lsb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_LSB);
1.1 blymn 186: address = (msb << 8) | lsb;
187:
188: /* Exit config mode */
189: bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END);
190: bus_space_unmap(ia->ia_iot, ioh, 2);
191:
1.7 ! xtraeme 192: /* Map the Hardware Monitor I/O space. */
1.5 xtraeme 193: if (bus_space_map(ia->ia_iot, address, 2, 0, &sc->sc_ioh)) {
1.1 blymn 194: aprint_error(": can't map register i/o space\n");
195: return;
196: }
197:
1.5 xtraeme 198: sc->sc_sme = sysmon_envsys_create();
199:
1.7 ! xtraeme 200: #define INITSENSOR(index, string, reg, type) \
! 201: do { \
! 202: strlcpy(sc->sc_sensor[index].desc, string, \
! 203: sizeof(sc->sc_sensor[index].desc)); \
! 204: sc->sc_sensor[index].units = type; \
! 205: sc->sc_regs[index] = reg; \
! 206: sc->sc_sensor[index].state = ENVSYS_SVALID; \
! 207: } while (/* CONSTCOND */ 0)
! 208:
! 209: /* Temperature sensors */
! 210: INITSENSOR(0, "Temp0", SMSC_TEMP1, ENVSYS_STEMP);
! 211: INITSENSOR(1, "Temp1", SMSC_TEMP2, ENVSYS_STEMP);
! 212: INITSENSOR(2, "Temp2", SMSC_TEMP3, ENVSYS_STEMP);
! 213: INITSENSOR(3, "Temp3", SMSC_TEMP4, ENVSYS_STEMP);
! 214:
! 215: /* Fan sensors */
! 216: INITSENSOR(4, "Fan0", SMSC_FAN1_LSB, ENVSYS_SFANRPM);
! 217: INITSENSOR(5, "Fan1", SMSC_FAN2_LSB, ENVSYS_SFANRPM);
! 218: INITSENSOR(6, "Fan2", SMSC_FAN3_LSB, ENVSYS_SFANRPM);
! 219: INITSENSOR(7, "Fan3", SMSC_FAN4_LSB, ENVSYS_SFANRPM);
1.5 xtraeme 220:
1.7 ! xtraeme 221: for (i = 0; i < SMSC_MAX_SENSORS; i++) {
1.5 xtraeme 222: if (sysmon_envsys_sensor_attach(sc->sc_sme,
223: &sc->sc_sensor[i])) {
224: sysmon_envsys_destroy(sc->sc_sme);
1.7 ! xtraeme 225: bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
1.5 xtraeme 226: return;
227: }
228: }
229:
1.7 ! xtraeme 230: sc->sc_sme->sme_name = device_xname(self);
1.5 xtraeme 231: sc->sc_sme->sme_cookie = sc;
232: sc->sc_sme->sme_refresh = smsc_refresh;
233:
234: if ((i = sysmon_envsys_register(sc->sc_sme)) != 0) {
1.7 ! xtraeme 235: aprint_error(": unable to register with sysmon (%d)\n", i);
1.5 xtraeme 236: sysmon_envsys_destroy(sc->sc_sme);
1.7 ! xtraeme 237: bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
! 238: return;
! 239: }
! 240:
! 241: switch (chipid) {
! 242: case SMSC_ID_47B397:
! 243: aprint_normal(": SMSC LPC47B397 Super I/O");
! 244: break;
! 245: case SMSC_ID_SCH5307NS:
! 246: aprint_normal(": SMSC SCH5307-NS Super I/O");
! 247: break;
! 248: case SMSC_ID_SCH5317:
! 249: aprint_normal(": SMSC SCH5317 Super I/O");
! 250: break;
1.5 xtraeme 251: }
252:
1.7 ! xtraeme 253: aprint_normal(" (rev %u)\n", rev);
! 254: aprint_normal_dev(self, "Hardware Monitor registers at 0x%04x\n",
! 255: address);
1.1 blymn 256: }
257:
1.5 xtraeme 258: static int
1.3 xtraeme 259: smsc_detach(struct device *self, int flags)
260: {
261: struct smsc_softc *sc = device_private(self);
262:
1.5 xtraeme 263: sysmon_envsys_unregister(sc->sc_sme);
264: bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2);
1.3 xtraeme 265: return 0;
266: }
1.1 blymn 267:
268: /*
269: * Read the value of the given register
270: */
271: static uint8_t
1.7 ! xtraeme 272: smsc_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
1.1 blymn 273: {
1.7 ! xtraeme 274: bus_space_write_1(iot, ioh, SMSC_ADDR, reg);
! 275: return bus_space_read_1(iot, ioh, SMSC_DATA);
1.1 blymn 276: }
277:
278: /*
1.7 ! xtraeme 279: * Write the given value to the given register.
! 280: */
1.1 blymn 281: static void
1.7 ! xtraeme 282: smsc_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, int val)
1.1 blymn 283: {
1.7 ! xtraeme 284: bus_space_write_1(iot, ioh, SMSC_ADDR, reg);
! 285: bus_space_write_1(iot, ioh, SMSC_DATA, val);
1.5 xtraeme 286: }
1.1 blymn 287:
288: /* convert temperature read from the chip to micro kelvin */
289: static inline int
290: smsc_temp2muk(uint8_t t)
291: {
292: int temp=t;
293:
294: return temp * 1000000 + 273150000U;
295: }
296:
297: /*
298: * convert register value read from chip into rpm using:
299: *
300: * RPM = 60/(Count * 11.111us)
301: *
302: * 1/1.1111us = 90kHz
303: *
304: */
305: static inline int
306: smsc_reg2rpm(unsigned int r)
307: {
308: unsigned long rpm;
309:
310: if (r == 0x0)
311: return 0;
312:
313: rpm = (90000 * 60) / ((unsigned long) r);
314: return (int) rpm;
315: }
316:
317: /* min and max temperatures in uK */
318: #define SMSC_MIN_TEMP_UK ((-127 * 1000000) + 273150000)
319: #define SMSC_MAX_TEMP_UK ((127 * 1000000) + 273150000)
320:
321: /*
322: * Get the data for the requested sensor, update the sysmon structure
323: * with the retrieved value.
324: */
1.5 xtraeme 325: static void
326: smsc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1.1 blymn 327: {
328: struct smsc_softc *sc = sme->sme_cookie;
1.5 xtraeme 329: int reg;
1.1 blymn 330: unsigned int rpm;
331: uint8_t msb, lsb;
332:
1.5 xtraeme 333: reg = sc->sc_regs[edata->sensor];
1.1 blymn 334:
1.2 xtraeme 335: switch (edata->units) {
1.1 blymn 336: case ENVSYS_STEMP:
1.7 ! xtraeme 337: edata->value_cur =
! 338: smsc_temp2muk(smsc_readreg(sc->sc_iot, sc->sc_ioh, reg));
1.1 blymn 339: break;
340:
341: case ENVSYS_SFANRPM:
342: /* reading lsb first locks msb... */
1.7 ! xtraeme 343: lsb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg);
! 344: msb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg + 1);
1.1 blymn 345: rpm = (msb << 8) | lsb;
1.2 xtraeme 346: edata->value_cur = smsc_reg2rpm(rpm);
1.1 blymn 347: break;
348: }
349: }
CVSweb <webmaster@jp.NetBSD.org>