root/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nvkm_i2c_aux_i2c_xfer
  2. nvkm_i2c_aux_i2c_func
  3. nvkm_i2c_aux_monitor
  4. nvkm_i2c_aux_release
  5. nvkm_i2c_aux_acquire
  6. nvkm_i2c_aux_xfer
  7. nvkm_i2c_aux_lnk_ctl
  8. nvkm_i2c_aux_del
  9. nvkm_i2c_aux_init
  10. nvkm_i2c_aux_fini
  11. nvkm_i2c_aux_ctor
  12. nvkm_i2c_aux_new_

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

/* [<][>][^][v][top][bottom][index][help] */