1 /* $OpenBSD: pcfiic_ebus.c,v 1.13 2008/06/08 03:07:40 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> 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 /* 20 * Device specific driver for the EBus i2c devices found on some sun4u 21 * systems. On systems not having a boot-bus controller the i2c devices 22 * are PCF8584. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/device.h> 28 #include <sys/kernel.h> 29 #include <sys/rwlock.h> 30 31 #include <machine/bus.h> 32 #include <machine/openfirm.h> 33 #include <machine/autoconf.h> 34 35 #include <sparc64/dev/ebusreg.h> 36 #include <sparc64/dev/ebusvar.h> 37 38 #include <dev/i2c/i2cvar.h> 39 #include <sparc64/dev/ofwi2cvar.h> 40 41 #include <dev/ic/pcf8584var.h> 42 43 int pcfiic_ebus_match(struct device *, void *, void *); 44 void pcfiic_ebus_attach(struct device *, struct device *, void *); 45 46 struct pcfiic_ebus_softc { 47 struct pcfiic_softc esc_sc; 48 49 int esc_node; 50 void *esc_ih; 51 }; 52 53 struct cfattach pcfiic_ebus_ca = { 54 sizeof(struct pcfiic_ebus_softc), pcfiic_ebus_match, pcfiic_ebus_attach 55 }; 56 57 void envctrl_scan(struct device *, struct i2cbus_attach_args *, void *); 58 void envctrltwo_scan(struct device *, struct i2cbus_attach_args *, void *); 59 60 int 61 pcfiic_ebus_match(struct device *parent, void *match, void *aux) 62 { 63 struct ebus_attach_args *ea = aux; 64 char compat[32]; 65 66 if (strcmp(ea->ea_name, "SUNW,envctrl") == 0 || 67 strcmp(ea->ea_name, "SUNW,envctrltwo") == 0) 68 return (1); 69 70 if (strcmp(ea->ea_name, "i2c") != 0) 71 return (0); 72 73 if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1) 74 return (0); 75 76 if (strcmp(compat, "pcf8584") == 0 || 77 strcmp(compat, "i2cpcf,8584") == 0 || 78 strcmp(compat, "SUNW,i2c-pic16f747") == 0 || 79 strcmp(compat, "SUNW,bbc-i2c") == 0) 80 return (1); 81 82 return (0); 83 } 84 85 void 86 pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct pcfiic_ebus_softc *esc = (struct pcfiic_ebus_softc *)self; 89 struct pcfiic_softc *sc = &esc->esc_sc; 90 struct ebus_attach_args *ea = aux; 91 char compat[32]; 92 u_int64_t addr; 93 u_int8_t clock = PCF_CLOCK_12 | PCF_FREQ_90; 94 int swapregs = 0; 95 96 if (ea->ea_nregs < 1 || ea->ea_nregs > 2) { 97 printf(": expected 1 or 2 registers, got %d\n", ea->ea_nregs); 98 return; 99 } 100 101 if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) > 0 && 102 strcmp(compat, "SUNW,bbc-i2c") == 0) { 103 /* 104 * On BBC-based machines, Sun swapped the order of 105 * the registers on their clone pcf, plus they feed 106 * it a non-standard clock. 107 */ 108 int clk = getpropint(findroot(), "clock-frequency", 0); 109 110 if (clk < 105000000) 111 clock = PCF_CLOCK_3 | PCF_FREQ_90; 112 else if (clk < 160000000) 113 clock = PCF_CLOCK_4_43 | PCF_FREQ_90; 114 swapregs = 1; 115 } 116 117 if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) { 118 addr = 0xaa; 119 } else if (addr == 0x00 || addr > 0xff) { 120 printf(": invalid address on I2C bus"); 121 return; 122 } 123 124 /* Prefer prom mapping, then memory mapping, then io mapping */ 125 if (ea->ea_nvaddrs) { 126 if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0, 127 BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) != 0) 128 goto fail; 129 sc->sc_iot = ea->ea_memtag; 130 } else if (ebus_bus_map(ea->ea_memtag, 0, 131 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 132 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 133 sc->sc_iot = ea->ea_memtag; 134 } else if (ebus_bus_map(ea->ea_iotag, 0, 135 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), 136 ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) { 137 sc->sc_iot = ea->ea_iotag; 138 } else { 139 fail: 140 printf(": can't map register space\n"); 141 return; 142 } 143 144 if (ea->ea_nregs == 2) { 145 /* 146 * Second register only occurs on BBC-based machines, 147 * and is likely not prom mapped 148 */ 149 if (ebus_bus_map(sc->sc_iot, 0, EBUS_PADDR_FROM_REG(&ea->ea_regs[1]), 150 ea->ea_regs[1].size, 0, 0, &sc->sc_ioh2) != 0) { 151 printf(": can't map 2nd register space\n"); 152 return; 153 } 154 sc->sc_master = 1; 155 } 156 157 if (ea->ea_nintrs >= 1) 158 esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0], 159 IPL_BIO, 0, pcfiic_intr, sc, self->dv_xname); 160 else 161 esc->esc_ih = NULL; 162 163 164 if (esc->esc_ih == NULL) 165 sc->sc_poll = 1; 166 167 if (strcmp(ea->ea_name, "SUNW,envctrl") == 0) 168 pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0, 169 envctrl_scan, &ea->ea_node); 170 else if (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0) 171 pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0, 172 envctrltwo_scan, &ea->ea_node); 173 else 174 pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs, 175 ofwiic_scan, &ea->ea_node); 176 } 177 178 void 179 envctrl_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux) 180 { 181 extern int iic_print(void *, const char *); 182 struct i2c_attach_args ia; 183 184 memset(&ia, 0, sizeof(ia)); 185 ia.ia_tag = iba->iba_tag; 186 ia.ia_cookie = aux; 187 188 /* Power supply 1 temperature. */ 189 ia.ia_addr = 0x48; 190 ia.ia_name = "ecadc"; 191 config_found(self, &ia, iic_print); 192 193 /* Power supply 2 termperature. */ 194 ia.ia_addr = 0x49; 195 ia.ia_name = "ecadc"; 196 config_found(self, &ia, iic_print); 197 198 /* Power supply 3 tempterature. */ 199 ia.ia_addr = 0x4a; 200 ia.ia_name = "ecadc"; 201 config_found(self, &ia, iic_print); 202 203 /* Ambient tempterature. */ 204 ia.ia_addr = 0x4d; 205 ia.ia_name = "lm75"; 206 config_found(self, &ia, iic_print); 207 208 /* CPU temperatures. */ 209 ia.ia_addr = 0x4f; 210 ia.ia_name = "ecadc"; 211 config_found(self, &ia, iic_print); 212 } 213 214 void 215 envctrltwo_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux) 216 { 217 extern int iic_print(void *, const char *); 218 struct i2c_attach_args ia; 219 220 memset(&ia, 0, sizeof(ia)); 221 ia.ia_tag = iba->iba_tag; 222 ia.ia_cookie = aux; 223 224 ia.ia_addr = 0x4a; 225 ia.ia_name = "ecadc"; 226 config_found(self, &ia, iic_print); 227 228 ia.ia_addr = 0x4f; 229 ia.ia_name = "ecadc"; 230 config_found(self, &ia, iic_print); 231 } 232