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
ofwiic_pci_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)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
ofwiic_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)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