1 /* $OpenBSD: tsciic.c,v 1.1 2014/12/24 18:46:14 miod Exp $ */ 2 /* $NetBSD: tsciic.c,v 1.1 2014/02/21 12:23:30 jdc Exp $ */ 3 4 /* 5 * Copyright (c) 2013 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Julian Coleman. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/rwlock.h> 37 38 #include <alpha/pci/tsreg.h> 39 #include <alpha/pci/tsvar.h> 40 41 #include <dev/i2c/i2cvar.h> 42 #include <dev/i2c/i2c_bitbang.h> 43 44 struct tsciic_softc { 45 struct device sc_dev; 46 47 bus_space_tag_t sc_iot; 48 bus_space_handle_t sc_ioh; 49 50 struct i2c_controller sc_i2c_tag; 51 struct rwlock sc_i2c_lock; 52 }; 53 54 int tsciic_match(struct device *, void *, void *); 55 void tsciic_attach(struct device *, struct device *, void *); 56 57 const struct cfattach tsciic_ca = { 58 .ca_devsize = sizeof(struct tsciic_softc), 59 .ca_match = tsciic_match, 60 .ca_attach = tsciic_attach 61 }; 62 63 struct cfdriver tsciic_cd = { 64 .cd_name = "tsciic", 65 .cd_class = DV_DULL 66 }; 67 68 /* I2C glue */ 69 int tsciic_acquire_bus(void *, int); 70 void tsciic_release_bus(void *, int); 71 int tsciic_send_start(void *, int); 72 int tsciic_send_stop(void *, int); 73 int tsciic_initiate_xfer(void *, i2c_addr_t, int); 74 int tsciic_read_byte(void *, uint8_t *, int); 75 int tsciic_write_byte(void *, uint8_t, int); 76 77 /* I2C bitbang glue */ 78 void tsciicbb_set_bits(void *, uint32_t); 79 void tsciicbb_set_dir(void *, uint32_t); 80 uint32_t tsciicbb_read(void *); 81 82 #define MPD_BIT_SDA 0x01 83 #define MPD_BIT_SCL 0x02 84 static const struct i2c_bitbang_ops tsciicbb_ops = { 85 .ibo_set_bits = tsciicbb_set_bits, 86 .ibo_set_dir = tsciicbb_set_dir, 87 .ibo_read_bits = tsciicbb_read, 88 .ibo_bits = { 89 [I2C_BIT_SDA] MPD_BIT_SDA, 90 [I2C_BIT_SCL] MPD_BIT_SCL 91 } 92 }; 93 94 int 95 tsciic_match(struct device *parent, void *match, void *aux) 96 { 97 struct tsp_attach_args *tsp = (struct tsp_attach_args *)aux; 98 99 return strcmp(tsp->tsp_name, tsciic_cd.cd_name) == 0; 100 } 101 102 void 103 tsciic_attach(struct device *parent, struct device *self, void *aux) 104 { 105 struct tsciic_softc *sc = (struct tsciic_softc *)self; 106 struct i2cbus_attach_args iba; 107 108 printf("\n"); 109 110 rw_init(&sc->sc_i2c_lock, "tsciiclk"); 111 sc->sc_i2c_tag.ic_cookie = sc; 112 sc->sc_i2c_tag.ic_acquire_bus = tsciic_acquire_bus; 113 sc->sc_i2c_tag.ic_release_bus = tsciic_release_bus; 114 sc->sc_i2c_tag.ic_send_start = tsciic_send_start; 115 sc->sc_i2c_tag.ic_send_stop = tsciic_send_stop; 116 sc->sc_i2c_tag.ic_initiate_xfer = tsciic_initiate_xfer; 117 sc->sc_i2c_tag.ic_read_byte = tsciic_read_byte; 118 sc->sc_i2c_tag.ic_write_byte = tsciic_write_byte; 119 120 memset(&iba, 0, sizeof iba); 121 iba.iba_name = "iic"; 122 iba.iba_tag = &sc->sc_i2c_tag; 123 config_found(self, &iba, iicbus_print); 124 } 125 126 int 127 tsciic_acquire_bus(void *cookie, int flags) 128 { 129 struct tsciic_softc *sc = cookie; 130 131 if (cold || (flags & I2C_F_POLL)) 132 return 0; 133 134 return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR); 135 } 136 137 void 138 tsciic_release_bus(void *cookie, int flags) 139 { 140 struct tsciic_softc *sc = cookie; 141 142 if (cold || (flags & I2C_F_POLL)) 143 return; 144 145 rw_exit(&sc->sc_i2c_lock); 146 } 147 148 int 149 tsciic_send_start(void *cookie, int flags) 150 { 151 return i2c_bitbang_send_start(cookie, flags, &tsciicbb_ops); 152 } 153 154 int 155 tsciic_send_stop(void *cookie, int flags) 156 { 157 return i2c_bitbang_send_stop(cookie, flags, &tsciicbb_ops); 158 } 159 160 int 161 tsciic_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 162 { 163 return i2c_bitbang_initiate_xfer(cookie, addr, flags, &tsciicbb_ops); 164 } 165 166 int 167 tsciic_read_byte(void *cookie, uint8_t *valp, int flags) 168 { 169 return i2c_bitbang_read_byte(cookie, valp, flags, &tsciicbb_ops); 170 } 171 172 int 173 tsciic_write_byte(void *cookie, uint8_t val, int flags) 174 { 175 return i2c_bitbang_write_byte(cookie, val, flags, &tsciicbb_ops); 176 } 177 178 /* I2C bitbanging */ 179 void 180 tsciicbb_set_bits(void *cookie, uint32_t bits) 181 { 182 uint64_t val; 183 184 val = (bits & MPD_BIT_SDA ? MPD_DS : 0) | 185 (bits & MPD_BIT_SCL ? MPD_CKS : 0); 186 alpha_mb(); 187 STQP(TS_C_MPD) = val; 188 alpha_mb(); 189 } 190 191 void 192 tsciicbb_set_dir(void *cookie, uint32_t dir) 193 { 194 /* Nothing to do */ 195 } 196 197 uint32_t 198 tsciicbb_read(void *cookie) 199 { 200 uint64_t val; 201 uint32_t bits; 202 203 val = LDQP(TS_C_MPD); 204 bits = (val & MPD_DR ? MPD_BIT_SDA : 0) | 205 (val & MPD_CKR ? MPD_BIT_SCL : 0); 206 return bits; 207 } 208