jbus-i2c.c revision 1.1
1/* $NetBSD: jbus-i2c.c,v 1.1 2018/10/20 06:25:46 macallan 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.1 2018/10/20 06:25:46 macallan 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 <dev/pci/pcivar.h> 43#include <dev/pci/pcireg.h> 44#include <sparc64/dev/iommureg.h> 45#include <sparc64/dev/iommuvar.h> 46#include <sparc64/dev/schizovar.h> 47#include <sparc64/dev/schizoreg.h> 48#include <machine/openfirm.h> 49 50#define DPRINTF printf 51 52/* I2C glue */ 53static int jbusi2c_i2c_acquire_bus(void *, int); 54static void jbusi2c_i2c_release_bus(void *, int); 55static int jbusi2c_i2c_send_start(void *, int); 56static int jbusi2c_i2c_send_stop(void *, int); 57static int jbusi2c_i2c_initiate_xfer(void *, i2c_addr_t, int); 58static int jbusi2c_i2c_read_byte(void *, uint8_t *, int); 59static int jbusi2c_i2c_write_byte(void *, uint8_t, int); 60 61/* I2C bitbang glue */ 62static void jbusi2c_i2cbb_set_bits(void *, uint32_t); 63static void jbusi2c_i2cbb_set_dir(void *, uint32_t); 64static uint32_t jbusi2c_i2cbb_read(void *); 65 66static const struct i2c_bitbang_ops jbusi2c_i2cbb_ops = { 67 jbusi2c_i2cbb_set_bits, 68 jbusi2c_i2cbb_set_dir, 69 jbusi2c_i2cbb_read, 70 { 71 2, /* bit 1 is data */ 72 1, /* bit 0 is clock */ 73 3, /* direction register for both out */ 74 1 /* data in, clock out */ 75 } 76}; 77 78static int jbusi2c_match(device_t, cfdata_t, void *); 79static void jbusi2c_attach(device_t, device_t, void *); 80 81struct jbusi2c_softc { 82 device_t sc_dev; 83 struct i2c_controller sc_i2c; 84 kmutex_t sc_i2c_lock; 85 int sc_node; 86}; 87 88static void jbusi2c_setup_i2c(struct jbusi2c_softc *); 89 90CFATTACH_DECL_NEW(jbusi2c, sizeof(struct jbusi2c_softc), 91 jbusi2c_match, jbusi2c_attach, NULL, NULL); 92 93extern struct schizo_softc *schizo0; 94 95int 96jbusi2c_match(device_t parent, cfdata_t match, void *aux) 97{ 98 struct mainbus_attach_args *ma = aux; 99 char *str; 100 101 if (strcmp(ma->ma_name, "i2c") != 0) 102 return (0); 103 104 str = prom_getpropstring(ma->ma_node, "compatible"); 105 if (strcmp(str, "jbus-i2c") == 0) 106 return (1); 107 108 return (0); 109} 110 111void 112jbusi2c_attach(device_t parent, device_t self, void *aux) 113{ 114 struct jbusi2c_softc *sc = device_private(self); 115 struct mainbus_attach_args *ma = aux; 116 117 aprint_normal("\n"); 118 119 sc->sc_dev = self; 120 sc->sc_node = ma->ma_node; 121 122 if (schizo0 != NULL) 123 jbusi2c_setup_i2c(sc); 124} 125 126 127 128static void 129jbusi2c_setup_i2c(struct jbusi2c_softc *sc) 130{ 131 struct i2cbus_attach_args iba; 132 prop_array_t cfg; 133 prop_dictionary_t dev; 134 prop_data_t data; 135 prop_dictionary_t dict = device_properties(sc->sc_dev); 136 int ret, devs, regs[2], addr; 137 uint8_t reg = 0, val[128]; 138 char name[64], compat[256]; 139 140 sc->sc_i2c.ic_cookie = schizo0; 141 sc->sc_i2c.ic_acquire_bus = jbusi2c_i2c_acquire_bus; 142 sc->sc_i2c.ic_release_bus = jbusi2c_i2c_release_bus; 143 sc->sc_i2c.ic_send_start = jbusi2c_i2c_send_start; 144 sc->sc_i2c.ic_send_stop = jbusi2c_i2c_send_stop; 145 sc->sc_i2c.ic_initiate_xfer = jbusi2c_i2c_initiate_xfer; 146 sc->sc_i2c.ic_read_byte = jbusi2c_i2c_read_byte; 147 sc->sc_i2c.ic_write_byte = jbusi2c_i2c_write_byte; 148 sc->sc_i2c.ic_exec = NULL; 149 150 val[0] = 0; 151 ret = iic_exec(&sc->sc_i2c, I2C_OP_READ_WITH_STOP, 0x50, 152 ®, 1, val, 1, I2C_F_POLL); 153 printf("ret %d val %02x\n", ret, val[0]); 154 155 /* round up i2c devices */ 156 devs = OF_child(sc->sc_node); 157 cfg = prop_array_create(); 158 prop_dictionary_set(dict, "i2c-child-devices", cfg); 159 prop_object_release(cfg); 160 while (devs != 0) { 161 if (OF_getprop(devs, "name", name, 256) <= 0) 162 goto skip; 163 memset(compat, 0, sizeof(compat)); 164 if (OF_getprop(devs, "compatible", 165 compat, 255) <= 0) 166 goto skip; 167 if (OF_getprop(devs, "reg", regs, 8) <= 0) 168 goto skip; 169 if (regs[0] != 0) goto skip; 170 addr = (regs[1] & 0xff) >> 1; 171 DPRINTF("-> %s@%d,%x\n", name, regs[0], addr); 172 dev = prop_dictionary_create(); 173 prop_dictionary_set_cstring(dev, "name", name); 174 data = prop_data_create_data(compat, strlen(compat)+1); 175 prop_dictionary_set(dev, "compatible", data); 176 prop_object_release(data); 177 prop_dictionary_set_uint32(dev, "addr", addr); 178 prop_dictionary_set_uint64(dev, "cookie", devs); 179 prop_array_add(cfg, dev); 180 prop_object_release(dev); 181 skip: 182 devs = OF_peer(devs); 183 } 184 memset(&iba, 0, sizeof(iba)); 185 iba.iba_tag = &sc->sc_i2c; 186 mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE); 187 config_found_ia(sc->sc_dev, "i2cbus", &iba, 188 iicbus_print); 189} 190 191/* I2C bitbanging */ 192static void 193jbusi2c_i2cbb_set_bits(void *cookie, uint32_t bits) 194{ 195 struct schizo_softc *sc = cookie; 196 197 schizo_write(sc, SCZ_JBUS_GPIO_DATA, bits); 198} 199 200static void 201jbusi2c_i2cbb_set_dir(void *cookie, uint32_t dir) 202{ 203 struct schizo_softc *sc = cookie; 204 205 schizo_write(sc, SCZ_JBUS_GPIO_DIR, dir); 206} 207 208static uint32_t 209jbusi2c_i2cbb_read(void *cookie) 210{ 211 struct schizo_softc *sc = cookie; 212 213 return schizo_read(sc, SCZ_JBUS_GPIO_DATA); 214} 215 216/* higher level I2C stuff */ 217static int 218jbusi2c_i2c_acquire_bus(void *cookie, int flags) 219{ 220 221 /* private bus */ 222 return 0; 223} 224 225static void 226jbusi2c_i2c_release_bus(void *cookie, int flags) 227{ 228 229 /* private bus */ 230} 231 232static int 233jbusi2c_i2c_send_start(void *cookie, int flags) 234{ 235 236 return i2c_bitbang_send_start(cookie, flags, &jbusi2c_i2cbb_ops); 237} 238 239static int 240jbusi2c_i2c_send_stop(void *cookie, int flags) 241{ 242 243 return i2c_bitbang_send_stop(cookie, flags, &jbusi2c_i2cbb_ops); 244} 245 246static int 247jbusi2c_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 248{ 249 250 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 251 &jbusi2c_i2cbb_ops); 252} 253 254static int 255jbusi2c_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 256{ 257 258 return i2c_bitbang_read_byte(cookie, valp, flags, &jbusi2c_i2cbb_ops); 259} 260 261static int 262jbusi2c_i2c_write_byte(void *cookie, uint8_t val, int flags) 263{ 264 265 return i2c_bitbang_write_byte(cookie, val, flags, &jbusi2c_i2cbb_ops); 266} 267