xref: /openbsd/sys/arch/sparc64/dev/pcfiic_ebus.c (revision eb7eaf8d)
1 /*	$OpenBSD: pcfiic_ebus.c,v 1.15 2021/10/24 17:05:03 mpi 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 const 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
pcfiic_ebus_match(struct device * parent,void * match,void * aux)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
pcfiic_ebus_attach(struct device * parent,struct device * self,void * aux)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
envctrl_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)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 temperature. */
194 	ia.ia_addr = 0x49;
195 	ia.ia_name = "ecadc";
196 	config_found(self, &ia, iic_print);
197 
198 	/* Power supply 3 temperature. */
199 	ia.ia_addr = 0x4a;
200 	ia.ia_name = "ecadc";
201 	config_found(self, &ia, iic_print);
202 
203 	/* Ambient temperature. */
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
envctrltwo_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)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