These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / subdev / i2c / aux.c
index 1c18860..f0851d5 100644 (file)
  *
  * Authors: Ben Skeggs
  */
-#include "priv.h"
-
-int
-nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
-       struct nvkm_i2c *i2c = nvkm_i2c(port);
-       if (port->func->aux) {
-               int ret = i2c->acquire(port, 0);
-               if (ret == 0) {
-                       ret = port->func->aux(port, true, 9, addr, data, size);
-                       i2c->release(port);
-               }
-               return ret;
-       }
-       return -ENODEV;
-}
-
-int
-nv_wraux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
-       struct nvkm_i2c *i2c = nvkm_i2c(port);
-       if (port->func->aux) {
-               int ret = i2c->acquire(port, 0);
-               if (ret == 0) {
-                       ret = port->func->aux(port, true, 8, addr, data, size);
-                       i2c->release(port);
-               }
-               return ret;
-       }
-       return -ENODEV;
-}
+#include "aux.h"
+#include "pad.h"
 
 static int
-aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       struct nvkm_i2c_port *port = adap->algo_data;
-       struct nvkm_i2c *i2c = nvkm_i2c(port);
+       struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c);
        struct i2c_msg *msg = msgs;
        int ret, mcnt = num;
 
-       if (!port->func->aux)
-               return -ENODEV;
-
-       ret = i2c->acquire(port, 0);
+       ret = nvkm_i2c_aux_acquire(aux);
        if (ret)
                return ret;
 
@@ -84,9 +51,9 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        if (mcnt || remaining > 16)
                                cmd |= 4; /* MOT */
 
-                       ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
+                       ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, cnt);
                        if (ret < 0) {
-                               i2c->release(port);
+                               nvkm_i2c_aux_release(aux);
                                return ret;
                        }
 
@@ -97,17 +64,111 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                msg++;
        }
 
-       i2c->release(port);
+       nvkm_i2c_aux_release(aux);
        return num;
 }
 
 static u32
-aux_func(struct i2c_adapter *adap)
+nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
-const struct i2c_algorithm nvkm_i2c_aux_algo = {
-       .master_xfer = aux_xfer,
-       .functionality = aux_func
+const struct i2c_algorithm
+nvkm_i2c_aux_i2c_algo = {
+       .master_xfer = nvkm_i2c_aux_i2c_xfer,
+       .functionality = nvkm_i2c_aux_i2c_func
 };
+
+void
+nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor)
+{
+       struct nvkm_i2c_pad *pad = aux->pad;
+       AUX_TRACE(aux, "monitor: %s", monitor ? "yes" : "no");
+       if (monitor)
+               nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX);
+       else
+               nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF);
+}
+
+void
+nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux)
+{
+       struct nvkm_i2c_pad *pad = aux->pad;
+       AUX_TRACE(aux, "release");
+       nvkm_i2c_pad_release(pad);
+       mutex_unlock(&aux->mutex);
+}
+
+int
+nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux)
+{
+       struct nvkm_i2c_pad *pad = aux->pad;
+       int ret;
+       AUX_TRACE(aux, "acquire");
+       mutex_lock(&aux->mutex);
+       ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX);
+       if (ret)
+               mutex_unlock(&aux->mutex);
+       return ret;
+}
+
+int
+nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type,
+                 u32 addr, u8 *data, u8 size)
+{
+       return aux->func->xfer(aux, retry, type, addr, data, size);
+}
+
+int
+nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef)
+{
+       if (aux->func->lnk_ctl)
+               return aux->func->lnk_ctl(aux, nr, bw, ef);
+       return -ENODEV;
+}
+
+void
+nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux)
+{
+       struct nvkm_i2c_aux *aux = *paux;
+       if (aux && !WARN_ON(!aux->func)) {
+               AUX_TRACE(aux, "dtor");
+               list_del(&aux->head);
+               i2c_del_adapter(&aux->i2c);
+               kfree(*paux);
+               *paux = NULL;
+       }
+}
+
+int
+nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
+                 struct nvkm_i2c_pad *pad, int id,
+                 struct nvkm_i2c_aux *aux)
+{
+       struct nvkm_device *device = pad->i2c->subdev.device;
+
+       aux->func = func;
+       aux->pad = pad;
+       aux->id = id;
+       mutex_init(&aux->mutex);
+       list_add_tail(&aux->head, &pad->i2c->aux);
+       AUX_TRACE(aux, "ctor");
+
+       snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x",
+                dev_name(device->dev), id);
+       aux->i2c.owner = THIS_MODULE;
+       aux->i2c.dev.parent = device->dev;
+       aux->i2c.algo = &nvkm_i2c_aux_i2c_algo;
+       return i2c_add_adapter(&aux->i2c);
+}
+
+int
+nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
+                 struct nvkm_i2c_pad *pad, int id,
+                 struct nvkm_i2c_aux **paux)
+{
+       if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL)))
+               return -ENOMEM;
+       return nvkm_i2c_aux_ctor(func, pad, id, *paux);
+}