xref: /openbsd/sys/arch/sparc64/dev/pcfiic_ebus.c (revision 6c4a4b0d)
1*6c4a4b0dSderaadt /*	$OpenBSD: pcfiic_ebus.c,v 1.13 2008/06/08 03:07:40 deraadt Exp $ */
2c74283e0Sdlg 
3c74283e0Sdlg /*
4c74283e0Sdlg  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
5c74283e0Sdlg  *
6c74283e0Sdlg  * Permission to use, copy, modify, and distribute this software for any
7c74283e0Sdlg  * purpose with or without fee is hereby granted, provided that the above
8c74283e0Sdlg  * copyright notice and this permission notice appear in all copies.
9c74283e0Sdlg  *
10c74283e0Sdlg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11c74283e0Sdlg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12c74283e0Sdlg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13c74283e0Sdlg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14c74283e0Sdlg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15c74283e0Sdlg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16c74283e0Sdlg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17c74283e0Sdlg  */
18c74283e0Sdlg 
19c74283e0Sdlg /*
20c74283e0Sdlg  * Device specific driver for the EBus i2c devices found on some sun4u
21c74283e0Sdlg  * systems. On systems not having a boot-bus controller the i2c devices
22c74283e0Sdlg  * are PCF8584.
23c74283e0Sdlg  */
24c74283e0Sdlg 
25c74283e0Sdlg #include <sys/param.h>
26c74283e0Sdlg #include <sys/systm.h>
27c74283e0Sdlg #include <sys/device.h>
28c74283e0Sdlg #include <sys/kernel.h>
29ee945c99Sjsg #include <sys/rwlock.h>
30c74283e0Sdlg 
31c74283e0Sdlg #include <machine/bus.h>
32c74283e0Sdlg #include <machine/openfirm.h>
333e5c8021Sderaadt #include <machine/autoconf.h>
34c74283e0Sdlg 
35c74283e0Sdlg #include <sparc64/dev/ebusreg.h>
36c74283e0Sdlg #include <sparc64/dev/ebusvar.h>
37c74283e0Sdlg 
38c74283e0Sdlg #include <dev/i2c/i2cvar.h>
39c74283e0Sdlg #include <sparc64/dev/ofwi2cvar.h>
40c74283e0Sdlg 
41c74283e0Sdlg #include <dev/ic/pcf8584var.h>
42c74283e0Sdlg 
43c74283e0Sdlg int	pcfiic_ebus_match(struct device *, void *, void *);
44c74283e0Sdlg void	pcfiic_ebus_attach(struct device *, struct device *, void *);
45c74283e0Sdlg 
46c74283e0Sdlg struct pcfiic_ebus_softc {
47c74283e0Sdlg 	struct pcfiic_softc	esc_sc;
48c74283e0Sdlg 
49c74283e0Sdlg 	int			esc_node;
50c74283e0Sdlg 	void			*esc_ih;
51c74283e0Sdlg };
52c74283e0Sdlg 
53c74283e0Sdlg struct cfattach pcfiic_ebus_ca = {
54c74283e0Sdlg 	sizeof(struct pcfiic_ebus_softc), pcfiic_ebus_match, pcfiic_ebus_attach
55c74283e0Sdlg };
56c74283e0Sdlg 
57d7f1f1d8Skettenis void	envctrl_scan(struct device *, struct i2cbus_attach_args *, void *);
58f620116fSkettenis void	envctrltwo_scan(struct device *, struct i2cbus_attach_args *, void *);
59f620116fSkettenis 
60c74283e0Sdlg int
61c74283e0Sdlg pcfiic_ebus_match(struct device *parent, void *match, void *aux)
62c74283e0Sdlg {
63c74283e0Sdlg 	struct ebus_attach_args		*ea = aux;
64c74283e0Sdlg 	char				compat[32];
65c74283e0Sdlg 
66d7f1f1d8Skettenis 	if (strcmp(ea->ea_name, "SUNW,envctrl") == 0 ||
67d7f1f1d8Skettenis 	    strcmp(ea->ea_name, "SUNW,envctrltwo") == 0)
68f620116fSkettenis 		return (1);
69f620116fSkettenis 
70c74283e0Sdlg 	if (strcmp(ea->ea_name, "i2c") != 0)
71c74283e0Sdlg 		return (0);
72c74283e0Sdlg 
73c74283e0Sdlg 	if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
74c74283e0Sdlg 		return (0);
75c74283e0Sdlg 
764cda44c6Skettenis 	if (strcmp(compat, "pcf8584") == 0 ||
774cda44c6Skettenis 	    strcmp(compat, "i2cpcf,8584") == 0 ||
78d8858115Skettenis 	    strcmp(compat, "SUNW,i2c-pic16f747") == 0 ||
79f620116fSkettenis 	    strcmp(compat, "SUNW,bbc-i2c") == 0)
80c74283e0Sdlg 		return (1);
819c6a5656Sderaadt 
829c6a5656Sderaadt 	return (0);
83c74283e0Sdlg }
84c74283e0Sdlg 
85c74283e0Sdlg void
86c74283e0Sdlg pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
87c74283e0Sdlg {
88c74283e0Sdlg 	struct pcfiic_ebus_softc	*esc = (struct pcfiic_ebus_softc *)self;
89c74283e0Sdlg 	struct pcfiic_softc		*sc = &esc->esc_sc;
90c74283e0Sdlg 	struct ebus_attach_args		*ea = aux;
913e5c8021Sderaadt 	char				compat[32];
92c74283e0Sdlg 	u_int64_t			addr;
93*6c4a4b0dSderaadt 	u_int8_t			clock = PCF_CLOCK_12 | PCF_FREQ_90;
943e5c8021Sderaadt 	int				swapregs = 0;
95c74283e0Sdlg 
969c6a5656Sderaadt 	if (ea->ea_nregs < 1 || ea->ea_nregs > 2) {
979c6a5656Sderaadt 		printf(": expected 1 or 2 registers, got %d\n", ea->ea_nregs);
98c74283e0Sdlg 		return;
99c74283e0Sdlg 	}
100c74283e0Sdlg 
101d7f1f1d8Skettenis 	if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) > 0 &&
102d7f1f1d8Skettenis 	    strcmp(compat, "SUNW,bbc-i2c") == 0) {
1033e5c8021Sderaadt 		/*
1043e5c8021Sderaadt 		 * On BBC-based machines, Sun swapped the order of
1053e5c8021Sderaadt 		 * the registers on their clone pcf, plus they feed
1063e5c8021Sderaadt 		 * it a non-standard clock.
1073e5c8021Sderaadt 		 */
1083e5c8021Sderaadt 		int clk = getpropint(findroot(), "clock-frequency", 0);
1093e5c8021Sderaadt 
1103e5c8021Sderaadt 		if (clk < 105000000)
111*6c4a4b0dSderaadt 			clock = PCF_CLOCK_3 | PCF_FREQ_90;
1123e5c8021Sderaadt 		else if (clk < 160000000)
113*6c4a4b0dSderaadt 			clock = PCF_CLOCK_4_43 | PCF_FREQ_90;
1143e5c8021Sderaadt 		swapregs = 1;
1153e5c8021Sderaadt 	}
1163e5c8021Sderaadt 
117c74283e0Sdlg 	if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
1189c6a5656Sderaadt 		addr = 0xaa;
1199c6a5656Sderaadt 	} else if (addr == 0x00 || addr > 0xff) {
1209c6a5656Sderaadt 		printf(": invalid address on I2C bus");
121c74283e0Sdlg 		return;
122c74283e0Sdlg 	}
123c74283e0Sdlg 
124392880e3Sderaadt 	/* Prefer prom mapping, then memory mapping, then io mapping */
125392880e3Sderaadt 	if (ea->ea_nvaddrs) {
126392880e3Sderaadt 		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
127392880e3Sderaadt 		    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) != 0)
128392880e3Sderaadt 			goto fail;
129392880e3Sderaadt 		sc->sc_iot = ea->ea_memtag;
130392880e3Sderaadt 	} else if (ebus_bus_map(ea->ea_memtag, 0,
131392880e3Sderaadt 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
132392880e3Sderaadt 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
133392880e3Sderaadt 		sc->sc_iot = ea->ea_memtag;
134392880e3Sderaadt 	} else if (ebus_bus_map(ea->ea_iotag, 0,
135392880e3Sderaadt 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
136392880e3Sderaadt 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
137392880e3Sderaadt 		sc->sc_iot = ea->ea_iotag;
138392880e3Sderaadt 	} else {
139392880e3Sderaadt fail:
140c74283e0Sdlg 		printf(": can't map register space\n");
141c74283e0Sdlg                	return;
142c74283e0Sdlg 	}
143c74283e0Sdlg 
1449c6a5656Sderaadt 	if (ea->ea_nregs == 2) {
145392880e3Sderaadt 		/*
146392880e3Sderaadt 		 * Second register only occurs on BBC-based machines,
147392880e3Sderaadt 		 * and is likely not prom mapped
148392880e3Sderaadt 		*/
1499c6a5656Sderaadt 		if (ebus_bus_map(sc->sc_iot, 0, EBUS_PADDR_FROM_REG(&ea->ea_regs[1]),
1509c6a5656Sderaadt 		    ea->ea_regs[1].size, 0, 0, &sc->sc_ioh2) != 0) {
1519c6a5656Sderaadt 			printf(": can't map 2nd register space\n");
1529c6a5656Sderaadt 			return;
1539c6a5656Sderaadt 		}
1549c6a5656Sderaadt 		sc->sc_master = 1;
1559c6a5656Sderaadt 	}
1569c6a5656Sderaadt 
157c74283e0Sdlg 	if (ea->ea_nintrs >= 1)
158c74283e0Sdlg 		esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
159c74283e0Sdlg 		    IPL_BIO, 0, pcfiic_intr, sc, self->dv_xname);
160c74283e0Sdlg 	else
161c74283e0Sdlg 		esc->esc_ih = NULL;
162c74283e0Sdlg 
163c74283e0Sdlg 
164c74283e0Sdlg 	if (esc->esc_ih == NULL)
165c74283e0Sdlg 		sc->sc_poll = 1;
166c74283e0Sdlg 
167d7f1f1d8Skettenis 	if (strcmp(ea->ea_name, "SUNW,envctrl") == 0)
168d7f1f1d8Skettenis 		pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0,
169d7f1f1d8Skettenis 		    envctrl_scan, &ea->ea_node);
170d7f1f1d8Skettenis 	else if (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0)
171f620116fSkettenis 		pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0,
172f620116fSkettenis 		    envctrltwo_scan, &ea->ea_node);
173f620116fSkettenis 	else
1743e5c8021Sderaadt 		pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs,
1753e5c8021Sderaadt 		    ofwiic_scan, &ea->ea_node);
176c74283e0Sdlg }
177f620116fSkettenis 
178f620116fSkettenis void
179d7f1f1d8Skettenis envctrl_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
180d7f1f1d8Skettenis {
181d7f1f1d8Skettenis 	extern int iic_print(void *, const char *);
182d7f1f1d8Skettenis 	struct i2c_attach_args ia;
183d7f1f1d8Skettenis 
184d7f1f1d8Skettenis 	memset(&ia, 0, sizeof(ia));
185d7f1f1d8Skettenis 	ia.ia_tag = iba->iba_tag;
186d7f1f1d8Skettenis 	ia.ia_cookie = aux;
187d7f1f1d8Skettenis 
188d7f1f1d8Skettenis 	/* Power supply 1 temperature. */
189d7f1f1d8Skettenis 	ia.ia_addr = 0x48;
190d7f1f1d8Skettenis 	ia.ia_name = "ecadc";
191d7f1f1d8Skettenis 	config_found(self, &ia, iic_print);
192d7f1f1d8Skettenis 
193d7f1f1d8Skettenis 	/* Power supply 2 termperature. */
194d7f1f1d8Skettenis 	ia.ia_addr = 0x49;
195d7f1f1d8Skettenis 	ia.ia_name = "ecadc";
196d7f1f1d8Skettenis 	config_found(self, &ia, iic_print);
197d7f1f1d8Skettenis 
198d7f1f1d8Skettenis 	/* Power supply 3 tempterature. */
199d7f1f1d8Skettenis 	ia.ia_addr = 0x4a;
200d7f1f1d8Skettenis 	ia.ia_name = "ecadc";
201d7f1f1d8Skettenis 	config_found(self, &ia, iic_print);
202d7f1f1d8Skettenis 
203d7f1f1d8Skettenis 	/* Ambient tempterature. */
204d7f1f1d8Skettenis 	ia.ia_addr = 0x4d;
205d7f1f1d8Skettenis 	ia.ia_name = "lm75";
206d7f1f1d8Skettenis 	config_found(self, &ia, iic_print);
207d7f1f1d8Skettenis 
208d7f1f1d8Skettenis 	/* CPU temperatures. */
209d7f1f1d8Skettenis 	ia.ia_addr = 0x4f;
210d7f1f1d8Skettenis 	ia.ia_name = "ecadc";
211d7f1f1d8Skettenis 	config_found(self, &ia, iic_print);
212d7f1f1d8Skettenis }
213d7f1f1d8Skettenis 
214d7f1f1d8Skettenis void
215f620116fSkettenis envctrltwo_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
216f620116fSkettenis {
217f620116fSkettenis 	extern int iic_print(void *, const char *);
218f620116fSkettenis 	struct i2c_attach_args ia;
219f620116fSkettenis 
220f620116fSkettenis 	memset(&ia, 0, sizeof(ia));
221f620116fSkettenis 	ia.ia_tag = iba->iba_tag;
222f620116fSkettenis 	ia.ia_cookie = aux;
223f620116fSkettenis 
224f620116fSkettenis 	ia.ia_addr = 0x4a;
225f620116fSkettenis 	ia.ia_name = "ecadc";
226f620116fSkettenis 	config_found(self, &ia, iic_print);
227f620116fSkettenis 
228f620116fSkettenis 	ia.ia_addr = 0x4f;
229f620116fSkettenis 	ia.ia_name = "ecadc";
230f620116fSkettenis 	config_found(self, &ia, iic_print);
231f620116fSkettenis }
232