1*231bb9b4SBenjamin Szőke /* 2*231bb9b4SBenjamin Szőke * Copyright 2009 Red Hat Inc. 3*231bb9b4SBenjamin Szőke * 4*231bb9b4SBenjamin Szőke * Permission is hereby granted, free of charge, to any person obtaining a 5*231bb9b4SBenjamin Szőke * copy of this software and associated documentation files (the "Software"), 6*231bb9b4SBenjamin Szőke * to deal in the Software without restriction, including without limitation 7*231bb9b4SBenjamin Szőke * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*231bb9b4SBenjamin Szőke * and/or sell copies of the Software, and to permit persons to whom the 9*231bb9b4SBenjamin Szőke * Software is furnished to do so, subject to the following conditions: 10*231bb9b4SBenjamin Szőke * 11*231bb9b4SBenjamin Szőke * The above copyright notice and this permission notice shall be included in 12*231bb9b4SBenjamin Szőke * all copies or substantial portions of the Software. 13*231bb9b4SBenjamin Szőke * 14*231bb9b4SBenjamin Szőke * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*231bb9b4SBenjamin Szőke * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*231bb9b4SBenjamin Szőke * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17*231bb9b4SBenjamin Szőke * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18*231bb9b4SBenjamin Szőke * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19*231bb9b4SBenjamin Szőke * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20*231bb9b4SBenjamin Szőke * OTHER DEALINGS IN THE SOFTWARE. 21*231bb9b4SBenjamin Szőke * 22*231bb9b4SBenjamin Szőke * Authors: Ben Skeggs 23*231bb9b4SBenjamin Szőke */ 24*231bb9b4SBenjamin Szőke 25*231bb9b4SBenjamin Szőke #include <linux/string_helpers.h> 26*231bb9b4SBenjamin Szőke 27*231bb9b4SBenjamin Szőke #include "auxch.h" 28*231bb9b4SBenjamin Szőke #include "pad.h" 29*231bb9b4SBenjamin Szőke 30*231bb9b4SBenjamin Szőke static int 31*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 32*231bb9b4SBenjamin Szőke { 33*231bb9b4SBenjamin Szőke struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c); 34*231bb9b4SBenjamin Szőke struct i2c_msg *msg = msgs; 35*231bb9b4SBenjamin Szőke int ret, mcnt = num; 36*231bb9b4SBenjamin Szőke 37*231bb9b4SBenjamin Szőke ret = nvkm_i2c_aux_acquire(aux); 38*231bb9b4SBenjamin Szőke if (ret) 39*231bb9b4SBenjamin Szőke return ret; 40*231bb9b4SBenjamin Szőke 41*231bb9b4SBenjamin Szőke while (mcnt--) { 42*231bb9b4SBenjamin Szőke u8 remaining = msg->len; 43*231bb9b4SBenjamin Szőke u8 *ptr = msg->buf; 44*231bb9b4SBenjamin Szőke 45*231bb9b4SBenjamin Szőke while (remaining) { 46*231bb9b4SBenjamin Szőke u8 cnt, retries, cmd; 47*231bb9b4SBenjamin Szőke 48*231bb9b4SBenjamin Szőke if (msg->flags & I2C_M_RD) 49*231bb9b4SBenjamin Szőke cmd = 1; 50*231bb9b4SBenjamin Szőke else 51*231bb9b4SBenjamin Szőke cmd = 0; 52*231bb9b4SBenjamin Szőke 53*231bb9b4SBenjamin Szőke if (mcnt || remaining > 16) 54*231bb9b4SBenjamin Szőke cmd |= 4; /* MOT */ 55*231bb9b4SBenjamin Szőke 56*231bb9b4SBenjamin Szőke for (retries = 0, cnt = 0; 57*231bb9b4SBenjamin Szőke retries < 32 && !cnt; 58*231bb9b4SBenjamin Szőke retries++) { 59*231bb9b4SBenjamin Szőke cnt = min_t(u8, remaining, 16); 60*231bb9b4SBenjamin Szőke ret = aux->func->xfer(aux, true, cmd, 61*231bb9b4SBenjamin Szőke msg->addr, ptr, &cnt); 62*231bb9b4SBenjamin Szőke if (ret < 0) 63*231bb9b4SBenjamin Szőke goto out; 64*231bb9b4SBenjamin Szőke } 65*231bb9b4SBenjamin Szőke if (!cnt) { 66*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "no data after 32 retries"); 67*231bb9b4SBenjamin Szőke ret = -EIO; 68*231bb9b4SBenjamin Szőke goto out; 69*231bb9b4SBenjamin Szőke } 70*231bb9b4SBenjamin Szőke 71*231bb9b4SBenjamin Szőke ptr += cnt; 72*231bb9b4SBenjamin Szőke remaining -= cnt; 73*231bb9b4SBenjamin Szőke } 74*231bb9b4SBenjamin Szőke 75*231bb9b4SBenjamin Szőke msg++; 76*231bb9b4SBenjamin Szőke } 77*231bb9b4SBenjamin Szőke 78*231bb9b4SBenjamin Szőke ret = num; 79*231bb9b4SBenjamin Szőke out: 80*231bb9b4SBenjamin Szőke nvkm_i2c_aux_release(aux); 81*231bb9b4SBenjamin Szőke return ret; 82*231bb9b4SBenjamin Szőke } 83*231bb9b4SBenjamin Szőke 84*231bb9b4SBenjamin Szőke static u32 85*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) 86*231bb9b4SBenjamin Szőke { 87*231bb9b4SBenjamin Szőke return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 88*231bb9b4SBenjamin Szőke } 89*231bb9b4SBenjamin Szőke 90*231bb9b4SBenjamin Szőke static const struct i2c_algorithm 91*231bb9b4SBenjamin Szőke nvkm_i2c_aux_i2c_algo = { 92*231bb9b4SBenjamin Szőke .master_xfer = nvkm_i2c_aux_i2c_xfer, 93*231bb9b4SBenjamin Szőke .functionality = nvkm_i2c_aux_i2c_func 94*231bb9b4SBenjamin Szőke }; 95*231bb9b4SBenjamin Szőke 96*231bb9b4SBenjamin Szőke void 97*231bb9b4SBenjamin Szőke nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor) 98*231bb9b4SBenjamin Szőke { 99*231bb9b4SBenjamin Szőke struct nvkm_i2c_pad *pad = aux->pad; 100*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "monitor: %s", str_yes_no(monitor)); 101*231bb9b4SBenjamin Szőke if (monitor) 102*231bb9b4SBenjamin Szőke nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX); 103*231bb9b4SBenjamin Szőke else 104*231bb9b4SBenjamin Szőke nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF); 105*231bb9b4SBenjamin Szőke } 106*231bb9b4SBenjamin Szőke 107*231bb9b4SBenjamin Szőke void 108*231bb9b4SBenjamin Szőke nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux) 109*231bb9b4SBenjamin Szőke { 110*231bb9b4SBenjamin Szőke struct nvkm_i2c_pad *pad = aux->pad; 111*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "release"); 112*231bb9b4SBenjamin Szőke nvkm_i2c_pad_release(pad); 113*231bb9b4SBenjamin Szőke mutex_unlock(&aux->mutex); 114*231bb9b4SBenjamin Szőke } 115*231bb9b4SBenjamin Szőke 116*231bb9b4SBenjamin Szőke int 117*231bb9b4SBenjamin Szőke nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux) 118*231bb9b4SBenjamin Szőke { 119*231bb9b4SBenjamin Szőke struct nvkm_i2c_pad *pad = aux->pad; 120*231bb9b4SBenjamin Szőke int ret; 121*231bb9b4SBenjamin Szőke 122*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "acquire"); 123*231bb9b4SBenjamin Szőke mutex_lock(&aux->mutex); 124*231bb9b4SBenjamin Szőke 125*231bb9b4SBenjamin Szőke if (aux->enabled) 126*231bb9b4SBenjamin Szőke ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX); 127*231bb9b4SBenjamin Szőke else 128*231bb9b4SBenjamin Szőke ret = -EIO; 129*231bb9b4SBenjamin Szőke 130*231bb9b4SBenjamin Szőke if (ret) 131*231bb9b4SBenjamin Szőke mutex_unlock(&aux->mutex); 132*231bb9b4SBenjamin Szőke return ret; 133*231bb9b4SBenjamin Szőke } 134*231bb9b4SBenjamin Szőke 135*231bb9b4SBenjamin Szőke int 136*231bb9b4SBenjamin Szőke nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type, 137*231bb9b4SBenjamin Szőke u32 addr, u8 *data, u8 *size) 138*231bb9b4SBenjamin Szőke { 139*231bb9b4SBenjamin Szőke if (!*size && !aux->func->address_only) { 140*231bb9b4SBenjamin Szőke AUX_ERR(aux, "address-only transaction dropped"); 141*231bb9b4SBenjamin Szőke return -ENOSYS; 142*231bb9b4SBenjamin Szőke } 143*231bb9b4SBenjamin Szőke return aux->func->xfer(aux, retry, type, addr, data, size); 144*231bb9b4SBenjamin Szőke } 145*231bb9b4SBenjamin Szőke 146*231bb9b4SBenjamin Szőke int 147*231bb9b4SBenjamin Szőke nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef) 148*231bb9b4SBenjamin Szőke { 149*231bb9b4SBenjamin Szőke if (aux->func->lnk_ctl) 150*231bb9b4SBenjamin Szőke return aux->func->lnk_ctl(aux, nr, bw, ef); 151*231bb9b4SBenjamin Szőke return -ENODEV; 152*231bb9b4SBenjamin Szőke } 153*231bb9b4SBenjamin Szőke 154*231bb9b4SBenjamin Szőke void 155*231bb9b4SBenjamin Szőke nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux) 156*231bb9b4SBenjamin Szőke { 157*231bb9b4SBenjamin Szőke struct nvkm_i2c_aux *aux = *paux; 158*231bb9b4SBenjamin Szőke if (aux && !WARN_ON(!aux->func)) { 159*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "dtor"); 160*231bb9b4SBenjamin Szőke list_del(&aux->head); 161*231bb9b4SBenjamin Szőke i2c_del_adapter(&aux->i2c); 162*231bb9b4SBenjamin Szőke kfree(*paux); 163*231bb9b4SBenjamin Szőke *paux = NULL; 164*231bb9b4SBenjamin Szőke } 165*231bb9b4SBenjamin Szőke } 166*231bb9b4SBenjamin Szőke 167*231bb9b4SBenjamin Szőke void 168*231bb9b4SBenjamin Szőke nvkm_i2c_aux_init(struct nvkm_i2c_aux *aux) 169*231bb9b4SBenjamin Szőke { 170*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "init"); 171*231bb9b4SBenjamin Szőke mutex_lock(&aux->mutex); 172*231bb9b4SBenjamin Szőke aux->enabled = true; 173*231bb9b4SBenjamin Szőke mutex_unlock(&aux->mutex); 174*231bb9b4SBenjamin Szőke } 175*231bb9b4SBenjamin Szőke 176*231bb9b4SBenjamin Szőke void 177*231bb9b4SBenjamin Szőke nvkm_i2c_aux_fini(struct nvkm_i2c_aux *aux) 178*231bb9b4SBenjamin Szőke { 179*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "fini"); 180*231bb9b4SBenjamin Szőke mutex_lock(&aux->mutex); 181*231bb9b4SBenjamin Szőke aux->enabled = false; 182*231bb9b4SBenjamin Szőke mutex_unlock(&aux->mutex); 183*231bb9b4SBenjamin Szőke } 184*231bb9b4SBenjamin Szőke 185*231bb9b4SBenjamin Szőke int 186*231bb9b4SBenjamin Szőke nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func, 187*231bb9b4SBenjamin Szőke struct nvkm_i2c_pad *pad, int id, 188*231bb9b4SBenjamin Szőke struct nvkm_i2c_aux *aux) 189*231bb9b4SBenjamin Szőke { 190*231bb9b4SBenjamin Szőke struct nvkm_device *device = pad->i2c->subdev.device; 191*231bb9b4SBenjamin Szőke 192*231bb9b4SBenjamin Szőke aux->func = func; 193*231bb9b4SBenjamin Szőke aux->pad = pad; 194*231bb9b4SBenjamin Szőke aux->id = id; 195*231bb9b4SBenjamin Szőke mutex_init(&aux->mutex); 196*231bb9b4SBenjamin Szőke list_add_tail(&aux->head, &pad->i2c->aux); 197*231bb9b4SBenjamin Szőke AUX_TRACE(aux, "ctor"); 198*231bb9b4SBenjamin Szőke 199*231bb9b4SBenjamin Szőke snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x", 200*231bb9b4SBenjamin Szőke dev_name(device->dev), id); 201*231bb9b4SBenjamin Szőke aux->i2c.owner = THIS_MODULE; 202*231bb9b4SBenjamin Szőke aux->i2c.dev.parent = device->dev; 203*231bb9b4SBenjamin Szőke aux->i2c.algo = &nvkm_i2c_aux_i2c_algo; 204*231bb9b4SBenjamin Szőke return i2c_add_adapter(&aux->i2c); 205*231bb9b4SBenjamin Szőke } 206*231bb9b4SBenjamin Szőke 207*231bb9b4SBenjamin Szőke int 208*231bb9b4SBenjamin Szőke nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func, 209*231bb9b4SBenjamin Szőke struct nvkm_i2c_pad *pad, int id, 210*231bb9b4SBenjamin Szőke struct nvkm_i2c_aux **paux) 211*231bb9b4SBenjamin Szőke { 212*231bb9b4SBenjamin Szőke if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL))) 213*231bb9b4SBenjamin Szőke return -ENOMEM; 214*231bb9b4SBenjamin Szőke return nvkm_i2c_aux_ctor(func, pad, id, *paux); 215*231bb9b4SBenjamin Szőke } 216