jbus-i2c.c revision 1.7
1/* $NetBSD: jbus-i2c.c,v 1.7 2021/08/07 16:19:05 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2018 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: jbus-i2c.c,v 1.7 2021/08/07 16:19:05 thorpej Exp $"); 31 32#include <sys/param.h> 33#include <sys/device.h> 34#include <sys/errno.h> 35 36#include <sys/bus.h> 37#include <machine/autoconf.h> 38 39#include <dev/i2c/i2cvar.h> 40#include <dev/i2c/i2c_bitbang.h> 41 42#include <machine/openfirm.h> 43 44#ifdef JBUSI2C_DEBUG 45#define DPRINTF printf 46#else 47#define DPRINTF if (0) printf 48#endif 49 50/* I2C glue */ 51static int jbusi2c_i2c_send_start(void *, int); 52static int jbusi2c_i2c_send_stop(void *, int); 53static int jbusi2c_i2c_initiate_xfer(void *, i2c_addr_t, int); 54static int jbusi2c_i2c_read_byte(void *, uint8_t *, int); 55static int jbusi2c_i2c_write_byte(void *, uint8_t, int); 56 57/* I2C bitbang glue */ 58static void jbusi2c_i2cbb_set_bits(void *, uint32_t); 59static void jbusi2c_i2cbb_set_dir(void *, uint32_t); 60static uint32_t jbusi2c_i2cbb_read(void *); 61 62static const struct i2c_bitbang_ops jbusi2c_i2cbb_ops = { 63 jbusi2c_i2cbb_set_bits, 64 jbusi2c_i2cbb_set_dir, 65 jbusi2c_i2cbb_read, 66 { 67 2, /* bit 1 is data */ 68 1, /* bit 0 is clock */ 69 3, /* direction register for both out */ 70 1 /* data in, clock out */ 71 } 72}; 73 74static int jbusi2c_match(device_t, cfdata_t, void *); 75static void jbusi2c_attach(device_t, device_t, void *); 76 77struct jbusi2c_softc { 78 device_t sc_dev; 79 struct i2c_controller sc_i2c; 80 bus_space_tag_t sc_bustag; 81 bus_space_handle_t sc_regh; 82 int sc_node; 83}; 84 85static void jbusi2c_setup_i2c(struct jbusi2c_softc *); 86 87CFATTACH_DECL_NEW(jbusi2c, sizeof(struct jbusi2c_softc), 88 jbusi2c_match, jbusi2c_attach, NULL, NULL); 89 90/* schizo GPIO registers */ 91#define DATA 0 92#define DIR 8 93 94int 95jbusi2c_match(device_t parent, cfdata_t match, void *aux) 96{ 97 struct mainbus_attach_args *ma = aux; 98 char *str; 99 100 if (strcmp(ma->ma_name, "i2c") != 0) 101 return (0); 102 103 str = prom_getpropstring(ma->ma_node, "compatible"); 104 if (strcmp(str, "jbus-i2c") == 0) 105 return (1); 106 107 return (0); 108} 109 110void 111jbusi2c_attach(device_t parent, device_t self, void *aux) 112{ 113 struct jbusi2c_softc *sc = device_private(self); 114 struct mainbus_attach_args *ma = aux; 115 116 aprint_normal(": addr %" PRIx64 "\n", ma->ma_reg[0].ur_paddr); 117 118 sc->sc_dev = self; 119 sc->sc_node = ma->ma_node; 120 sc->sc_bustag = ma->ma_bustag; 121 122 if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr, 16, 0, 123 &sc->sc_regh)) { 124 aprint_error(": failed to map registers\n"); 125 return; 126 } 127 128 jbusi2c_setup_i2c(sc); 129} 130 131 132 133static void 134jbusi2c_setup_i2c(struct jbusi2c_softc *sc) 135{ 136 struct i2cbus_attach_args iba; 137 prop_array_t cfg; 138 prop_dictionary_t dev; 139 prop_dictionary_t dict = device_properties(sc->sc_dev); 140 int devs, regs[2], addr; 141 char name[64], compat[256]; 142 143 iic_tag_init(&sc->sc_i2c); 144 sc->sc_i2c.ic_cookie = sc; 145 sc->sc_i2c.ic_send_start = jbusi2c_i2c_send_start; 146 sc->sc_i2c.ic_send_stop = jbusi2c_i2c_send_stop; 147 sc->sc_i2c.ic_initiate_xfer = jbusi2c_i2c_initiate_xfer; 148 sc->sc_i2c.ic_read_byte = jbusi2c_i2c_read_byte; 149 sc->sc_i2c.ic_write_byte = jbusi2c_i2c_write_byte; 150 151 /* round up i2c devices */ 152 devs = OF_child(sc->sc_node); 153 cfg = prop_array_create(); 154 prop_dictionary_set(dict, "i2c-child-devices", cfg); 155 prop_object_release(cfg); 156 while (devs != 0) { 157 if (OF_getprop(devs, "name", name, 256) <= 0) 158 goto skip; 159 memset(compat, 0, sizeof(compat)); 160 if (OF_getprop(devs, "compatible", 161 compat, 255) <= 0) 162 goto skip; 163 if (OF_getprop(devs, "reg", regs, 8) <= 0) 164 goto skip; 165 if (regs[0] != 0) goto skip; 166 addr = (regs[1] & 0xff) >> 1; 167 DPRINTF("-> %s@%d,%x\n", name, regs[0], addr); 168 dev = prop_dictionary_create(); 169 prop_dictionary_set_string(dev, "name", name); 170 prop_dictionary_set_data(dev, "compatible", compat, 171 strlen(compat)+1); 172 prop_dictionary_set_uint32(dev, "addr", addr); 173 prop_dictionary_set_uint64(dev, "cookie", devs); 174 prop_array_add(cfg, dev); 175 prop_object_release(dev); 176 skip: 177 devs = OF_peer(devs); 178 } 179 memset(&iba, 0, sizeof(iba)); 180 iba.iba_tag = &sc->sc_i2c; 181 config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE); 182} 183 184static inline void 185jbusi2c_write(struct jbusi2c_softc *sc, int reg, uint64_t bits) 186{ 187 bus_space_write_8(sc->sc_bustag, sc->sc_regh, reg, bits); 188} 189 190static inline uint64_t 191jbusi2c_read(struct jbusi2c_softc *sc, int reg) 192{ 193 return bus_space_read_8(sc->sc_bustag, sc->sc_regh, reg); 194} 195 196/* I2C bitbanging */ 197static void 198jbusi2c_i2cbb_set_bits(void *cookie, uint32_t bits) 199{ 200 struct jbusi2c_softc *sc = cookie; 201 202 jbusi2c_write(sc, DATA, bits); 203} 204 205static void 206jbusi2c_i2cbb_set_dir(void *cookie, uint32_t dir) 207{ 208 struct jbusi2c_softc *sc = cookie; 209 210 jbusi2c_write(sc, DIR, dir); 211} 212 213static uint32_t 214jbusi2c_i2cbb_read(void *cookie) 215{ 216 struct jbusi2c_softc *sc = cookie; 217 218 return jbusi2c_read(sc, DATA); 219} 220 221/* higher level I2C stuff */ 222static int 223jbusi2c_i2c_send_start(void *cookie, int flags) 224{ 225 226 return i2c_bitbang_send_start(cookie, flags, &jbusi2c_i2cbb_ops); 227} 228 229static int 230jbusi2c_i2c_send_stop(void *cookie, int flags) 231{ 232 233 return i2c_bitbang_send_stop(cookie, flags, &jbusi2c_i2cbb_ops); 234} 235 236static int 237jbusi2c_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 238{ 239 240 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 241 &jbusi2c_i2cbb_ops); 242} 243 244static int 245jbusi2c_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 246{ 247 248 return i2c_bitbang_read_byte(cookie, valp, flags, &jbusi2c_i2cbb_ops); 249} 250 251static int 252jbusi2c_i2c_write_byte(void *cookie, uint8_t val, int flags) 253{ 254 255 return i2c_bitbang_write_byte(cookie, val, flags, &jbusi2c_i2cbb_ops); 256} 257