chrome_ec.c revision 297793
1263936Sbr/*- 2263936Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3263936Sbr * All rights reserved. 4263936Sbr * 5263936Sbr * Redistribution and use in source and binary forms, with or without 6263936Sbr * modification, are permitted provided that the following conditions 7263936Sbr * are met: 8263936Sbr * 1. Redistributions of source code must retain the above copyright 9263936Sbr * notice, this list of conditions and the following disclaimer. 10263936Sbr * 2. Redistributions in binary form must reproduce the above copyright 11263936Sbr * notice, this list of conditions and the following disclaimer in the 12263936Sbr * documentation and/or other materials provided with the distribution. 13263936Sbr * 14263936Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15263936Sbr * ANY EXPREC OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16263936Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNEC FOR A PARTICULAR PURPOSE 17263936Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18263936Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19263936Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20263936Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINEC INTERRUPTION) 21263936Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22263936Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23263936Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24263936Sbr * SUCH DAMAGE. 25263936Sbr */ 26263936Sbr 27263936Sbr/* 28263936Sbr * Samsung Chromebook Embedded Controller 29263936Sbr */ 30263936Sbr 31263936Sbr#include <sys/cdefs.h> 32263936Sbr__FBSDID("$FreeBSD: head/sys/arm/samsung/exynos/chrome_ec.c 297793 2016-04-10 23:07:00Z pfg $"); 33263936Sbr 34263936Sbr#include <sys/param.h> 35263936Sbr#include <sys/systm.h> 36263936Sbr#include <sys/bus.h> 37263936Sbr#include <sys/kernel.h> 38263936Sbr#include <sys/module.h> 39263936Sbr#include <sys/malloc.h> 40263936Sbr#include <sys/rman.h> 41263936Sbr#include <sys/timeet.h> 42263936Sbr#include <sys/timetc.h> 43263936Sbr#include <sys/watchdog.h> 44263936Sbr#include <sys/gpio.h> 45263936Sbr 46263936Sbr#include <dev/ofw/openfirm.h> 47263936Sbr#include <dev/ofw/ofw_bus.h> 48263936Sbr#include <dev/ofw/ofw_bus_subr.h> 49263936Sbr 50263936Sbr#include <machine/bus.h> 51263936Sbr#include <machine/cpu.h> 52263936Sbr#include <machine/intr.h> 53263936Sbr 54263936Sbr#include <dev/iicbus/iiconf.h> 55263936Sbr 56263936Sbr#include "iicbus_if.h" 57263936Sbr#include "gpio_if.h" 58263936Sbr 59263936Sbr#include <arm/samsung/exynos/chrome_ec.h> 60263936Sbr 61263936Sbrstruct ec_softc { 62263936Sbr device_t dev; 63266785Sbr int have_arbitrator; 64266785Sbr pcell_t our_gpio; 65266785Sbr pcell_t ec_gpio; 66263936Sbr}; 67263936Sbr 68263936Sbrstruct ec_softc *ec_sc; 69263936Sbr 70263936Sbr/* 71263936Sbr * bus_claim, bus_release 72263936Sbr * both functions used for bus arbitration 73263936Sbr * in multi-master mode 74263936Sbr */ 75263936Sbr 76263936Sbrstatic int 77263936Sbrbus_claim(struct ec_softc *sc) 78263936Sbr{ 79263936Sbr device_t gpio_dev; 80263936Sbr int status; 81263936Sbr 82266785Sbr if (sc->our_gpio == 0 || sc->ec_gpio == 0) { 83266785Sbr device_printf(sc->dev, "i2c arbitrator is not configured\n"); 84266785Sbr return (1); 85266785Sbr } 86266785Sbr 87263936Sbr gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 88266785Sbr if (gpio_dev == NULL) { 89263936Sbr device_printf(sc->dev, "cant find gpio_dev\n"); 90263936Sbr return (1); 91263936Sbr } 92263936Sbr 93263936Sbr /* Say we want the bus */ 94266785Sbr GPIO_PIN_SET(gpio_dev, sc->our_gpio, GPIO_PIN_LOW); 95263936Sbr 96269369Sbr /* TODO: insert a delay to allow EC to react. */ 97266785Sbr 98263936Sbr /* Check EC decision */ 99266785Sbr GPIO_PIN_GET(gpio_dev, sc->ec_gpio, &status); 100263936Sbr 101263936Sbr if (status == 1) { 102263936Sbr /* Okay. We have bus */ 103263936Sbr return (0); 104263936Sbr } 105263936Sbr 106263936Sbr /* EC is master */ 107263936Sbr return (-1); 108263936Sbr} 109263936Sbr 110263936Sbrstatic int 111263936Sbrbus_release(struct ec_softc *sc) 112263936Sbr{ 113263936Sbr device_t gpio_dev; 114263936Sbr 115266785Sbr if (sc->our_gpio == 0 || sc->ec_gpio == 0) { 116266785Sbr device_printf(sc->dev, "i2c arbitrator is not configured\n"); 117266785Sbr return (1); 118266785Sbr } 119266785Sbr 120263936Sbr gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 121266785Sbr if (gpio_dev == NULL) { 122263936Sbr device_printf(sc->dev, "cant find gpio_dev\n"); 123263936Sbr return (1); 124263936Sbr } 125263936Sbr 126266785Sbr GPIO_PIN_SET(gpio_dev, sc->our_gpio, GPIO_PIN_HIGH); 127263936Sbr 128263936Sbr return (0); 129263936Sbr} 130263936Sbr 131263936Sbrstatic int 132263936Sbrec_probe(device_t dev) 133263936Sbr{ 134263936Sbr 135263936Sbr device_set_desc(dev, "Chromebook Embedded Controller"); 136263936Sbr return (BUS_PROBE_DEFAULT); 137263936Sbr} 138263936Sbr 139263936Sbrstatic int 140263936Sbrfill_checksum(uint8_t *data_out, int len) 141263936Sbr{ 142263936Sbr int res; 143263936Sbr int i; 144263936Sbr 145263936Sbr res = 0; 146263936Sbr for (i = 0; i < len; i++) { 147263936Sbr res += data_out[i]; 148263936Sbr } 149263936Sbr 150263936Sbr data_out[len] = (res & 0xff); 151263936Sbr 152263936Sbr return (0); 153263936Sbr} 154263936Sbr 155263936Sbrint 156263936Sbrec_command(uint8_t cmd, uint8_t *dout, uint8_t dout_len, 157263936Sbr uint8_t *dinp, uint8_t dinp_len) 158263936Sbr{ 159263936Sbr struct ec_softc *sc; 160263936Sbr uint8_t *msg_dout; 161263936Sbr uint8_t *msg_dinp; 162263936Sbr int ret; 163263936Sbr int i; 164263936Sbr 165263936Sbr msg_dout = malloc(dout_len + 4, M_DEVBUF, M_NOWAIT); 166266945Sbr msg_dinp = malloc(dinp_len + 3, M_DEVBUF, M_NOWAIT); 167263936Sbr 168263936Sbr if (ec_sc == NULL) 169263936Sbr return (-1); 170263936Sbr 171263936Sbr sc = ec_sc; 172263936Sbr 173263936Sbr msg_dout[0] = EC_CMD_VERSION0; 174263936Sbr msg_dout[1] = cmd; 175263936Sbr msg_dout[2] = dout_len; 176263936Sbr 177263936Sbr for (i = 0; i < dout_len; i++) { 178263936Sbr msg_dout[i + 3] = dout[i]; 179297793Spfg } 180263936Sbr 181263936Sbr fill_checksum(msg_dout, dout_len + 3); 182263936Sbr 183263936Sbr struct iic_msg msgs[] = { 184263936Sbr { 0x1e, IIC_M_WR, dout_len + 4, msg_dout, }, 185266945Sbr { 0x1e, IIC_M_RD, dinp_len + 3, msg_dinp, }, 186263936Sbr }; 187263936Sbr 188263936Sbr ret = iicbus_transfer(sc->dev, msgs, 2); 189263936Sbr if (ret != 0) { 190263936Sbr device_printf(sc->dev, "i2c transfer returned %d\n", ret); 191263936Sbr free(msg_dout, M_DEVBUF); 192263936Sbr free(msg_dinp, M_DEVBUF); 193263936Sbr return (-1); 194263936Sbr } 195263936Sbr 196263936Sbr for (i = 0; i < dinp_len; i++) { 197266945Sbr dinp[i] = msg_dinp[i + 2]; 198297793Spfg } 199263936Sbr 200263936Sbr free(msg_dout, M_DEVBUF); 201263936Sbr free(msg_dinp, M_DEVBUF); 202263936Sbr return (0); 203263936Sbr} 204263936Sbr 205263936Sbrint ec_hello(void) 206263936Sbr{ 207263936Sbr uint8_t data_in[4]; 208263936Sbr uint8_t data_out[4]; 209263936Sbr 210263936Sbr data_in[0] = 0x40; 211263936Sbr data_in[1] = 0x30; 212263936Sbr data_in[2] = 0x20; 213263936Sbr data_in[3] = 0x10; 214263936Sbr 215269369Sbr ec_command(EC_CMD_HELLO, data_in, 4, 216263936Sbr data_out, 4); 217263936Sbr 218263936Sbr return (0); 219263936Sbr} 220263936Sbr 221266785Sbrstatic void 222266785Sbrconfigure_i2c_arbitrator(struct ec_softc *sc) 223266785Sbr{ 224266785Sbr phandle_t arbitrator; 225266785Sbr 226269369Sbr /* TODO: look for compatible entry instead of hard-coded path */ 227266785Sbr arbitrator = OF_finddevice("/i2c-arbitrator"); 228266785Sbr if (arbitrator > 0 && 229266785Sbr OF_hasprop(arbitrator, "freebsd,our-gpio") && 230266785Sbr OF_hasprop(arbitrator, "freebsd,ec-gpio")) { 231266785Sbr sc->have_arbitrator = 1; 232266785Sbr OF_getencprop(arbitrator, "freebsd,our-gpio", 233266785Sbr &sc->our_gpio, sizeof(sc->our_gpio)); 234266785Sbr OF_getencprop(arbitrator, "freebsd,ec-gpio", 235266785Sbr &sc->ec_gpio, sizeof(sc->ec_gpio)); 236266785Sbr } else { 237266785Sbr sc->have_arbitrator = 0; 238266785Sbr sc->our_gpio = 0; 239266785Sbr sc->ec_gpio = 0; 240266785Sbr } 241266785Sbr} 242266785Sbr 243263936Sbrstatic int 244263936Sbrec_attach(device_t dev) 245263936Sbr{ 246263936Sbr struct ec_softc *sc; 247263936Sbr 248263936Sbr sc = device_get_softc(dev); 249263936Sbr sc->dev = dev; 250263936Sbr 251263936Sbr ec_sc = sc; 252263936Sbr 253266785Sbr configure_i2c_arbitrator(sc); 254266785Sbr 255263936Sbr /* 256263936Sbr * Claim the bus. 257263936Sbr * 258263936Sbr * We don't know cases when EC is master, 259263936Sbr * so hold the bus forever for us. 260263936Sbr * 261263936Sbr */ 262263936Sbr 263266785Sbr if (sc->have_arbitrator && bus_claim(sc) != 0) { 264263936Sbr return (ENXIO); 265263936Sbr } 266263936Sbr 267263936Sbr return (0); 268263936Sbr} 269263936Sbr 270263981Sbrstatic int 271263981Sbrec_detach(device_t dev) 272263981Sbr{ 273263981Sbr struct ec_softc *sc; 274263981Sbr 275263981Sbr sc = device_get_softc(dev); 276263981Sbr 277266785Sbr if (sc->have_arbitrator) { 278266785Sbr bus_release(sc); 279266785Sbr } 280263981Sbr 281263981Sbr return (0); 282263981Sbr} 283263981Sbr 284263936Sbrstatic device_method_t ec_methods[] = { 285263936Sbr DEVMETHOD(device_probe, ec_probe), 286263936Sbr DEVMETHOD(device_attach, ec_attach), 287263981Sbr DEVMETHOD(device_detach, ec_detach), 288263936Sbr { 0, 0 } 289263936Sbr}; 290263936Sbr 291263936Sbrstatic driver_t ec_driver = { 292263936Sbr "chrome_ec", 293263936Sbr ec_methods, 294263936Sbr sizeof(struct ec_softc), 295263936Sbr}; 296263936Sbr 297263936Sbrstatic devclass_t ec_devclass; 298263936Sbr 299263936SbrDRIVER_MODULE(chrome_ec, iicbus, ec_driver, ec_devclass, 0, 0); 300263936SbrMODULE_VERSION(chrome_ec, 1); 301263936SbrMODULE_DEPEND(chrome_ec, iicbus, 1, 1, 1); 302