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