linux/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 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
  25#include <core/option.h>
  26
  27#include <subdev/bios.h>
  28#include <subdev/bios/dcb.h>
  29#include <subdev/bios/i2c.h>
  30#include <subdev/i2c.h>
  31#include <subdev/vga.h>
  32
  33/******************************************************************************
  34 * interface to linux i2c bit-banging algorithm
  35 *****************************************************************************/
  36
  37#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
  38#define CSTMSEL true
  39#else
  40#define CSTMSEL false
  41#endif
  42
  43static int
  44nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
  45{
  46        struct i2c_algo_bit_data *bit = adap->algo_data;
  47        struct nouveau_i2c_port *port = bit->data;
  48        if (port->func->acquire)
  49                port->func->acquire(port);
  50        return 0;
  51}
  52
  53static void
  54nouveau_i2c_setscl(void *data, int state)
  55{
  56        struct nouveau_i2c_port *port = data;
  57        port->func->drive_scl(port, state);
  58}
  59
  60static void
  61nouveau_i2c_setsda(void *data, int state)
  62{
  63        struct nouveau_i2c_port *port = data;
  64        port->func->drive_sda(port, state);
  65}
  66
  67static int
  68nouveau_i2c_getscl(void *data)
  69{
  70        struct nouveau_i2c_port *port = data;
  71        return port->func->sense_scl(port);
  72}
  73
  74static int
  75nouveau_i2c_getsda(void *data)
  76{
  77        struct nouveau_i2c_port *port = data;
  78        return port->func->sense_sda(port);
  79}
  80
  81/******************************************************************************
  82 * base i2c "port" class implementation
  83 *****************************************************************************/
  84
  85void
  86_nouveau_i2c_port_dtor(struct nouveau_object *object)
  87{
  88        struct nouveau_i2c_port *port = (void *)object;
  89        i2c_del_adapter(&port->adapter);
  90        nouveau_object_destroy(&port->base);
  91}
  92
  93int
  94nouveau_i2c_port_create_(struct nouveau_object *parent,
  95                         struct nouveau_object *engine,
  96                         struct nouveau_oclass *oclass, u8 index,
  97                         const struct i2c_algorithm *algo,
  98                         int size, void **pobject)
  99{
 100        struct nouveau_device *device = nv_device(parent);
 101        struct nouveau_i2c *i2c = (void *)engine;
 102        struct nouveau_i2c_port *port;
 103        int ret;
 104
 105        ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
 106        port = *pobject;
 107        if (ret)
 108                return ret;
 109
 110        snprintf(port->adapter.name, sizeof(port->adapter.name),
 111                 "nouveau-%s-%d", device->name, index);
 112        port->adapter.owner = THIS_MODULE;
 113        port->adapter.dev.parent = &device->pdev->dev;
 114        port->index = index;
 115        i2c_set_adapdata(&port->adapter, i2c);
 116
 117        if ( algo == &nouveau_i2c_bit_algo &&
 118            !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
 119                struct i2c_algo_bit_data *bit;
 120
 121                bit = kzalloc(sizeof(*bit), GFP_KERNEL);
 122                if (!bit)
 123                        return -ENOMEM;
 124
 125                bit->udelay = 10;
 126                bit->timeout = usecs_to_jiffies(2200);
 127                bit->data = port;
 128                bit->pre_xfer = nouveau_i2c_pre_xfer;
 129                bit->setsda = nouveau_i2c_setsda;
 130                bit->setscl = nouveau_i2c_setscl;
 131                bit->getsda = nouveau_i2c_getsda;
 132                bit->getscl = nouveau_i2c_getscl;
 133
 134                port->adapter.algo_data = bit;
 135                ret = i2c_bit_add_bus(&port->adapter);
 136        } else {
 137                port->adapter.algo_data = port;
 138                port->adapter.algo = algo;
 139                ret = i2c_add_adapter(&port->adapter);
 140        }
 141
 142        /* drop port's i2c subdev refcount, i2c handles this itself */
 143        if (ret == 0)
 144                list_add_tail(&port->head, &i2c->ports);
 145        return ret;
 146}
 147
 148/******************************************************************************
 149 * base i2c subdev class implementation
 150 *****************************************************************************/
 151
 152static struct nouveau_i2c_port *
 153nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
 154{
 155        struct nouveau_bios *bios = nouveau_bios(i2c);
 156        struct nouveau_i2c_port *port;
 157
 158        if (index == NV_I2C_DEFAULT(0) ||
 159            index == NV_I2C_DEFAULT(1)) {
 160                u8  ver, hdr, cnt, len;
 161                u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
 162                if (i2c && ver >= 0x30) {
 163                        u8 auxidx = nv_ro08(bios, i2c + 4);
 164                        if (index == NV_I2C_DEFAULT(0))
 165                                index = (auxidx & 0x0f) >> 0;
 166                        else
 167                                index = (auxidx & 0xf0) >> 4;
 168                } else {
 169                        index = 2;
 170                }
 171        }
 172
 173        list_for_each_entry(port, &i2c->ports, head) {
 174                if (port->index == index)
 175                        return port;
 176        }
 177
 178        return NULL;
 179}
 180
 181static struct nouveau_i2c_port *
 182nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
 183{
 184        struct nouveau_i2c_port *port;
 185
 186        list_for_each_entry(port, &i2c->ports, head) {
 187                if (nv_hclass(port) == type)
 188                        return port;
 189        }
 190
 191        return NULL;
 192}
 193
 194static int
 195nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
 196                     struct i2c_board_info *info,
 197                     bool (*match)(struct nouveau_i2c_port *,
 198                                   struct i2c_board_info *))
 199{
 200        struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index);
 201        int i;
 202
 203        if (!port) {
 204                nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
 205                return -ENODEV;
 206        }
 207
 208        nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
 209        for (i = 0; info[i].addr; i++) {
 210                if (nv_probe_i2c(port, info[i].addr) &&
 211                    (!match || match(port, &info[i]))) {
 212                        nv_info(i2c, "detected %s: %s\n", what, info[i].type);
 213                        return i;
 214                }
 215        }
 216
 217        nv_debug(i2c, "no devices found.\n");
 218        return -ENODEV;
 219}
 220
 221int
 222_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
 223{
 224        struct nouveau_i2c *i2c = (void *)object;
 225        struct nouveau_i2c_port *port;
 226        int ret;
 227
 228        list_for_each_entry(port, &i2c->ports, head) {
 229                ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
 230                if (ret && suspend)
 231                        goto fail;
 232        }
 233
 234        return nouveau_subdev_fini(&i2c->base, suspend);
 235fail:
 236        list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
 237                nv_ofuncs(port)->init(nv_object(port));
 238        }
 239
 240        return ret;
 241}
 242
 243int
 244_nouveau_i2c_init(struct nouveau_object *object)
 245{
 246        struct nouveau_i2c *i2c = (void *)object;
 247        struct nouveau_i2c_port *port;
 248        int ret;
 249
 250        ret = nouveau_subdev_init(&i2c->base);
 251        if (ret == 0) {
 252                list_for_each_entry(port, &i2c->ports, head) {
 253                        ret = nv_ofuncs(port)->init(nv_object(port));
 254                        if (ret)
 255                                goto fail;
 256                }
 257        }
 258
 259        return ret;
 260fail:
 261        list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
 262                nv_ofuncs(port)->fini(nv_object(port), false);
 263        }
 264
 265        return ret;
 266}
 267
 268void
 269_nouveau_i2c_dtor(struct nouveau_object *object)
 270{
 271        struct nouveau_i2c *i2c = (void *)object;
 272        struct nouveau_i2c_port *port, *temp;
 273
 274        list_for_each_entry_safe(port, temp, &i2c->ports, head) {
 275                nouveau_object_ref(NULL, (struct nouveau_object **)&port);
 276        }
 277
 278        nouveau_subdev_destroy(&i2c->base);
 279}
 280
 281static struct nouveau_oclass *
 282nouveau_i2c_extdev_sclass[] = {
 283        nouveau_anx9805_sclass,
 284};
 285
 286int
 287nouveau_i2c_create_(struct nouveau_object *parent,
 288                    struct nouveau_object *engine,
 289                    struct nouveau_oclass *oclass,
 290                    struct nouveau_oclass *sclass,
 291                    int length, void **pobject)
 292{
 293        struct nouveau_bios *bios = nouveau_bios(parent);
 294        struct nouveau_i2c *i2c;
 295        struct nouveau_object *object;
 296        struct dcb_i2c_entry info;
 297        int ret, i, j, index = -1;
 298        struct dcb_output outp;
 299        u8  ver, hdr;
 300        u32 data;
 301
 302        ret = nouveau_subdev_create(parent, engine, oclass, 0,
 303                                    "I2C", "i2c", &i2c);
 304        *pobject = nv_object(i2c);
 305        if (ret)
 306                return ret;
 307
 308        i2c->find = nouveau_i2c_find;
 309        i2c->find_type = nouveau_i2c_find_type;
 310        i2c->identify = nouveau_i2c_identify;
 311        INIT_LIST_HEAD(&i2c->ports);
 312
 313        while (!dcb_i2c_parse(bios, ++index, &info)) {
 314                if (info.type == DCB_I2C_UNUSED)
 315                        continue;
 316
 317                oclass = sclass;
 318                do {
 319                        ret = -EINVAL;
 320                        if (oclass->handle == info.type) {
 321                                ret = nouveau_object_ctor(*pobject, *pobject,
 322                                                          oclass, &info,
 323                                                          index, &object);
 324                        }
 325                } while (ret && (++oclass)->handle);
 326        }
 327
 328        /* in addition to the busses specified in the i2c table, there
 329         * may be ddc/aux channels hiding behind external tmds/dp/etc
 330         * transmitters.
 331         */
 332        index = ((index + 0x0f) / 0x10) * 0x10;
 333        i = -1;
 334        while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
 335                if (!outp.location || !outp.extdev)
 336                        continue;
 337
 338                switch (outp.type) {
 339                case DCB_OUTPUT_TMDS:
 340                        info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
 341                        break;
 342                case DCB_OUTPUT_DP:
 343                        info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
 344                        break;
 345                default:
 346                        continue;
 347                }
 348
 349                ret = -ENODEV;
 350                j = -1;
 351                while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) {
 352                        parent = nv_object(i2c->find(i2c, outp.i2c_index));
 353                        oclass = nouveau_i2c_extdev_sclass[j];
 354                        do {
 355                                if (oclass->handle != info.type)
 356                                        continue;
 357                                ret = nouveau_object_ctor(parent, *pobject,
 358                                                          oclass, NULL,
 359                                                          index++, &object);
 360                        } while (ret && (++oclass)->handle);
 361                }
 362        }
 363
 364        return 0;
 365}
 366