Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs <bskeggs@redhat.com>
0023  */
0024 #include "bus.h"
0025 #include "pad.h"
0026 
0027 #include <core/option.h>
0028 
0029 /*******************************************************************************
0030  * i2c-algo-bit
0031  ******************************************************************************/
0032 static int
0033 nvkm_i2c_bus_pre_xfer(struct i2c_adapter *adap)
0034 {
0035     struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
0036     return nvkm_i2c_bus_acquire(bus);
0037 }
0038 
0039 static void
0040 nvkm_i2c_bus_post_xfer(struct i2c_adapter *adap)
0041 {
0042     struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
0043     return nvkm_i2c_bus_release(bus);
0044 }
0045 
0046 static void
0047 nvkm_i2c_bus_setscl(void *data, int state)
0048 {
0049     struct nvkm_i2c_bus *bus = data;
0050     bus->func->drive_scl(bus, state);
0051 }
0052 
0053 static void
0054 nvkm_i2c_bus_setsda(void *data, int state)
0055 {
0056     struct nvkm_i2c_bus *bus = data;
0057     bus->func->drive_sda(bus, state);
0058 }
0059 
0060 static int
0061 nvkm_i2c_bus_getscl(void *data)
0062 {
0063     struct nvkm_i2c_bus *bus = data;
0064     return bus->func->sense_scl(bus);
0065 }
0066 
0067 static int
0068 nvkm_i2c_bus_getsda(void *data)
0069 {
0070     struct nvkm_i2c_bus *bus = data;
0071     return bus->func->sense_sda(bus);
0072 }
0073 
0074 /*******************************************************************************
0075  * !i2c-algo-bit (off-chip i2c bus / hw i2c / internal bit-banging algo)
0076  ******************************************************************************/
0077 static int
0078 nvkm_i2c_bus_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
0079 {
0080     struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c);
0081     int ret;
0082 
0083     ret = nvkm_i2c_bus_acquire(bus);
0084     if (ret)
0085         return ret;
0086 
0087     ret = bus->func->xfer(bus, msgs, num);
0088     nvkm_i2c_bus_release(bus);
0089     return ret;
0090 }
0091 
0092 static u32
0093 nvkm_i2c_bus_func(struct i2c_adapter *adap)
0094 {
0095     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
0096 }
0097 
0098 static const struct i2c_algorithm
0099 nvkm_i2c_bus_algo = {
0100     .master_xfer = nvkm_i2c_bus_xfer,
0101     .functionality = nvkm_i2c_bus_func,
0102 };
0103 
0104 /*******************************************************************************
0105  * nvkm_i2c_bus base
0106  ******************************************************************************/
0107 void
0108 nvkm_i2c_bus_init(struct nvkm_i2c_bus *bus)
0109 {
0110     BUS_TRACE(bus, "init");
0111     if (bus->func->init)
0112         bus->func->init(bus);
0113 
0114     mutex_lock(&bus->mutex);
0115     bus->enabled = true;
0116     mutex_unlock(&bus->mutex);
0117 }
0118 
0119 void
0120 nvkm_i2c_bus_fini(struct nvkm_i2c_bus *bus)
0121 {
0122     BUS_TRACE(bus, "fini");
0123     mutex_lock(&bus->mutex);
0124     bus->enabled = false;
0125     mutex_unlock(&bus->mutex);
0126 }
0127 
0128 void
0129 nvkm_i2c_bus_release(struct nvkm_i2c_bus *bus)
0130 {
0131     struct nvkm_i2c_pad *pad = bus->pad;
0132     BUS_TRACE(bus, "release");
0133     nvkm_i2c_pad_release(pad);
0134     mutex_unlock(&bus->mutex);
0135 }
0136 
0137 int
0138 nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *bus)
0139 {
0140     struct nvkm_i2c_pad *pad = bus->pad;
0141     int ret;
0142 
0143     BUS_TRACE(bus, "acquire");
0144     mutex_lock(&bus->mutex);
0145 
0146     if (bus->enabled)
0147         ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C);
0148     else
0149         ret = -EIO;
0150 
0151     if (ret)
0152         mutex_unlock(&bus->mutex);
0153     return ret;
0154 }
0155 
0156 int
0157 nvkm_i2c_bus_probe(struct nvkm_i2c_bus *bus, const char *what,
0158            struct nvkm_i2c_bus_probe *info,
0159            bool (*match)(struct nvkm_i2c_bus *,
0160                  struct i2c_board_info *, void *), void *data)
0161 {
0162     int i;
0163 
0164     BUS_DBG(bus, "probing %ss", what);
0165     for (i = 0; info[i].dev.addr; i++) {
0166         u8 orig_udelay = 0;
0167 
0168         if ((bus->i2c.algo == &i2c_bit_algo) && (info[i].udelay != 0)) {
0169             struct i2c_algo_bit_data *algo = bus->i2c.algo_data;
0170             BUS_DBG(bus, "%dms delay instead of %dms",
0171                      info[i].udelay, algo->udelay);
0172             orig_udelay = algo->udelay;
0173             algo->udelay = info[i].udelay;
0174         }
0175 
0176         if (nvkm_probe_i2c(&bus->i2c, info[i].dev.addr) &&
0177             (!match || match(bus, &info[i].dev, data))) {
0178             BUS_DBG(bus, "detected %s: %s",
0179                 what, info[i].dev.type);
0180             return i;
0181         }
0182 
0183         if (orig_udelay) {
0184             struct i2c_algo_bit_data *algo = bus->i2c.algo_data;
0185             algo->udelay = orig_udelay;
0186         }
0187     }
0188 
0189     BUS_DBG(bus, "no devices found.");
0190     return -ENODEV;
0191 }
0192 
0193 void
0194 nvkm_i2c_bus_del(struct nvkm_i2c_bus **pbus)
0195 {
0196     struct nvkm_i2c_bus *bus = *pbus;
0197     if (bus && !WARN_ON(!bus->func)) {
0198         BUS_TRACE(bus, "dtor");
0199         list_del(&bus->head);
0200         i2c_del_adapter(&bus->i2c);
0201         kfree(bus->i2c.algo_data);
0202         kfree(*pbus);
0203         *pbus = NULL;
0204     }
0205 }
0206 
0207 int
0208 nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *func,
0209           struct nvkm_i2c_pad *pad, int id,
0210           struct nvkm_i2c_bus *bus)
0211 {
0212     struct nvkm_device *device = pad->i2c->subdev.device;
0213     struct i2c_algo_bit_data *bit;
0214 #ifndef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
0215     const bool internal = false;
0216 #else
0217     const bool internal = true;
0218 #endif
0219     int ret;
0220 
0221     bus->func = func;
0222     bus->pad = pad;
0223     bus->id = id;
0224     mutex_init(&bus->mutex);
0225     list_add_tail(&bus->head, &pad->i2c->bus);
0226     BUS_TRACE(bus, "ctor");
0227 
0228     snprintf(bus->i2c.name, sizeof(bus->i2c.name), "nvkm-%s-bus-%04x",
0229          dev_name(device->dev), id);
0230     bus->i2c.owner = THIS_MODULE;
0231     bus->i2c.dev.parent = device->dev;
0232 
0233     if ( bus->func->drive_scl &&
0234         !nvkm_boolopt(device->cfgopt, "NvI2C", internal)) {
0235         if (!(bit = kzalloc(sizeof(*bit), GFP_KERNEL)))
0236             return -ENOMEM;
0237         bit->udelay = 10;
0238         bit->timeout = usecs_to_jiffies(2200);
0239         bit->data = bus;
0240         bit->pre_xfer = nvkm_i2c_bus_pre_xfer;
0241         bit->post_xfer = nvkm_i2c_bus_post_xfer;
0242         bit->setscl = nvkm_i2c_bus_setscl;
0243         bit->setsda = nvkm_i2c_bus_setsda;
0244         bit->getscl = nvkm_i2c_bus_getscl;
0245         bit->getsda = nvkm_i2c_bus_getsda;
0246         bus->i2c.algo_data = bit;
0247         ret = i2c_bit_add_bus(&bus->i2c);
0248     } else {
0249         bus->i2c.algo = &nvkm_i2c_bus_algo;
0250         ret = i2c_add_adapter(&bus->i2c);
0251     }
0252 
0253     return ret;
0254 }
0255 
0256 int
0257 nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *func,
0258           struct nvkm_i2c_pad *pad, int id,
0259           struct nvkm_i2c_bus **pbus)
0260 {
0261     if (!(*pbus = kzalloc(sizeof(**pbus), GFP_KERNEL)))
0262         return -ENOMEM;
0263     return nvkm_i2c_bus_ctor(func, pad, id, *pbus);
0264 }