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