xref: /openbsd/sys/arch/sparc64/dev/ofwi2c.c (revision fc61954a)
1 /*	$OpenBSD: ofwi2c.c,v 1.9 2014/02/21 21:28:26 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Theo de Raadt
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 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 
23 #include <dev/i2c/i2cvar.h>
24 #include <dev/ofw/openfirm.h>
25 
26 #include <dev/pci/pcivar.h>
27 #include <dev/pci/pcireg.h>
28 #include <sparc64/pci_machdep.h>
29 
30 #include <arch/sparc64/dev/ofwi2cvar.h>
31 
32 void
33 ofwiic_pci_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
34 {
35 	struct pci_attach_args *pa = aux;
36 	pcitag_t tag = pa->pa_tag;
37 	int iba_node = PCITAG_NODE(tag);
38 	char name[32];
39 	int node;
40 
41 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
42 		memset(name, 0, sizeof(name));
43 
44 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
45 			continue;
46 		if (name[0] == '\0')
47 			continue;
48 
49 		if (strcmp(name, "i2c-smbus") == 0 ||
50 		    strcmp(name, "i2c") == 0)
51 			ofwiic_scan(self, iba, &node);
52 	}
53 }
54 
55 void
56 ofwiic_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
57 {
58 	int iba_node = *(int *)aux;
59 	extern int iic_print(void *, const char *);
60 	struct i2c_attach_args ia;
61 	char name[32];
62 	u_int32_t reg[2];
63 	int node;
64 
65 	for (node = OF_child(iba_node); node; node = OF_peer(node)) {
66 		memset(name, 0, sizeof(name));
67 		memset(reg, 0, sizeof(reg));
68 
69 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
70 			continue;
71 		if (name[0] == '\0')
72 			continue;
73 
74 		if (OF_getprop(node, "reg", reg, sizeof(reg)) == -1)
75 			continue;
76 
77 		memset(&ia, 0, sizeof(ia));
78 		ia.ia_tag = iba->iba_tag;
79 		ia.ia_addr = (reg[0] << 7) | (reg[1] >> 1);
80 		ia.ia_name = name;
81 		ia.ia_cookie = &node;
82 
83 		if (strncmp(ia.ia_name, "i2c-", strlen("i2c-")) == 0)
84 			ia.ia_name += strlen("i2c-");
85 
86 		/* Skip non-SPD EEPROMs.  */
87 		if (strcmp(ia.ia_name, "at24c64") == 0 ||
88 		    strcmp(ia.ia_name, "at34c02") == 0) {
89 			if (OF_getprop(node, "name", name, sizeof(name)) == -1)
90 				continue;
91 			if (strcmp(name, "dimm") == 0 ||
92 			    strcmp(name, "dimm-spd") == 0)
93 				ia.ia_name = "spd";
94 			else
95 				continue;
96 		}
97 
98 		/*
99 		 * XXX alipm crashes on some machines for an unknown reason
100 		 * when doing the periodic i2c accesses things like sensors
101 		 * need.  However, devices accessed only at boot are fine.
102 		 */
103 		if (strcmp(self->dv_parent->dv_xname, "alipm0") == 0 &&
104 		    (ia.ia_addr < 0x50 || ia.ia_addr > 0x57)) {
105 			iic_print(&ia, self->dv_parent->dv_xname);
106 			printf(" skipped due to %s bugs\n",
107 			    self->dv_parent->dv_xname);
108 			continue;
109 		}
110 
111 		config_found(self, &ia, iic_print);
112 	}
113 }
114