drm/nouveau/i2c: start hiding subdev-internal interfaces
[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 30#include <subdev/vga.h>
6ee73861 31
c26fe843
BS
32#include "priv.h"
33
7dcd060c
BS
34/******************************************************************************
35 * interface to linux i2c bit-banging algorithm
36 *****************************************************************************/
37
38#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
39#define CSTMSEL true
40#else
41#define CSTMSEL false
42#endif
43
44static int
45nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
4196faa8 46{
7dcd060c
BS
47 struct i2c_algo_bit_data *bit = adap->algo_data;
48 struct nouveau_i2c_port *port = bit->data;
49 if (port->func->acquire)
50 port->func->acquire(port);
51 return 0;
52}
4196faa8 53
7dcd060c
BS
54static void
55nouveau_i2c_setscl(void *data, int state)
56{
57 struct nouveau_i2c_port *port = data;
58 port->func->drive_scl(port, state);
59}
4196faa8 60
7dcd060c
BS
61static void
62nouveau_i2c_setsda(void *data, int state)
63{
64 struct nouveau_i2c_port *port = data;
65 port->func->drive_sda(port, state);
4196faa8
BS
66}
67
7dcd060c
BS
68static int
69nouveau_i2c_getscl(void *data)
4196faa8 70{
7dcd060c
BS
71 struct nouveau_i2c_port *port = data;
72 return port->func->sense_scl(port);
73}
4196faa8 74
7dcd060c
BS
75static int
76nouveau_i2c_getsda(void *data)
77{
78 struct nouveau_i2c_port *port = data;
79 return port->func->sense_sda(port);
80}
4196faa8 81
7dcd060c
BS
82/******************************************************************************
83 * base i2c "port" class implementation
84 *****************************************************************************/
85
86void
87_nouveau_i2c_port_dtor(struct nouveau_object *object)
88{
89 struct nouveau_i2c_port *port = (void *)object;
90 i2c_del_adapter(&port->adapter);
91 nouveau_object_destroy(&port->base);
4196faa8
BS
92}
93
7dcd060c
BS
94int
95nouveau_i2c_port_create_(struct nouveau_object *parent,
96 struct nouveau_object *engine,
97 struct nouveau_oclass *oclass, u8 index,
98 const struct i2c_algorithm *algo,
c865534f 99 const struct nouveau_i2c_func *func,
7dcd060c 100 int size, void **pobject)
4196faa8 101{
7dcd060c
BS
102 struct nouveau_device *device = nv_device(parent);
103 struct nouveau_i2c *i2c = (void *)engine;
104 struct nouveau_i2c_port *port;
105 int ret;
106
107 ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
108 port = *pobject;
109 if (ret)
110 return ret;
111
112 snprintf(port->adapter.name, sizeof(port->adapter.name),
113 "nouveau-%s-%d", device->name, index);
114 port->adapter.owner = THIS_MODULE;
420b9469 115 port->adapter.dev.parent = nv_device_base(device);
7dcd060c 116 port->index = index;
c865534f 117 port->func = func;
7dcd060c
BS
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
d395f1e4 144 if (ret == 0)
7dcd060c 145 list_add_tail(&port->head, &i2c->ports);
7dcd060c 146 return ret;
4196faa8
BS
147}
148
7dcd060c
BS
149/******************************************************************************
150 * base i2c subdev class implementation
151 *****************************************************************************/
152
4196faa8
BS
153static struct nouveau_i2c_port *
154nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
155{
156 struct nouveau_bios *bios = nouveau_bios(i2c);
157 struct nouveau_i2c_port *port;
158
159 if (index == NV_I2C_DEFAULT(0) ||
160 index == NV_I2C_DEFAULT(1)) {
161 u8 ver, hdr, cnt, len;
162 u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
163 if (i2c && ver >= 0x30) {
164 u8 auxidx = nv_ro08(bios, i2c + 4);
165 if (index == NV_I2C_DEFAULT(0))
166 index = (auxidx & 0x0f) >> 0;
167 else
168 index = (auxidx & 0xf0) >> 4;
169 } else {
170 index = 2;
171 }
172 }
173
174 list_for_each_entry(port, &i2c->ports, head) {
175 if (port->index == index)
df3ef6a1 176 return port;
4196faa8
BS
177 }
178
df3ef6a1 179 return NULL;
4196faa8
BS
180}
181
548ddb6d
BS
182static struct nouveau_i2c_port *
183nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
184{
185 struct nouveau_i2c_port *port;
186
187 list_for_each_entry(port, &i2c->ports, head) {
7dcd060c 188 if (nv_hclass(port) == type)
548ddb6d
BS
189 return port;
190 }
191
192 return NULL;
193}
194
4196faa8
BS
195static int
196nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
9e2b734f 197 struct nouveau_i2c_board_info *info,
4196faa8 198 bool (*match)(struct nouveau_i2c_port *,
fdd239ac 199 struct i2c_board_info *, void *), void *data)
6ee73861 200{
4196faa8
BS
201 struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index);
202 int i;
203
204 if (!port) {
205 nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
206 return -ENODEV;
207 }
208
209 nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
9e2b734f
MP
210 for (i = 0; info[i].dev.addr; i++) {
211 u8 orig_udelay = 0;
212
213 if ((port->adapter.algo == &i2c_bit_algo) &&
214 (info[i].udelay != 0)) {
215 struct i2c_algo_bit_data *algo = port->adapter.algo_data;
216 nv_debug(i2c, "using custom udelay %d instead of %d\n",
217 info[i].udelay, algo->udelay);
218 orig_udelay = algo->udelay;
219 algo->udelay = info[i].udelay;
220 }
221
222 if (nv_probe_i2c(port, info[i].dev.addr) &&
fdd239ac 223 (!match || match(port, &info[i].dev, data))) {
9e2b734f
MP
224 nv_info(i2c, "detected %s: %s\n", what,
225 info[i].dev.type);
4196faa8
BS
226 return i;
227 }
9e2b734f
MP
228
229 if (orig_udelay) {
230 struct i2c_algo_bit_data *algo = port->adapter.algo_data;
231 algo->udelay = orig_udelay;
232 }
4196faa8
BS
233 }
234
235 nv_debug(i2c, "no devices found.\n");
236 return -ENODEV;
237}
238
7dcd060c
BS
239int
240_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
4196faa8 241{
7dcd060c
BS
242 struct nouveau_i2c *i2c = (void *)object;
243 struct nouveau_i2c_port *port;
244 int ret;
4196faa8 245
7dcd060c
BS
246 list_for_each_entry(port, &i2c->ports, head) {
247 ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
248 if (ret && suspend)
249 goto fail;
2bdb06e3 250 }
4196faa8 251
7dcd060c
BS
252 return nouveau_subdev_fini(&i2c->base, suspend);
253fail:
254 list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
255 nv_ofuncs(port)->init(nv_object(port));
2bdb06e3 256 }
7dcd060c
BS
257
258 return ret;
6ee73861
BS
259}
260
4196faa8 261int
7dcd060c 262_nouveau_i2c_init(struct nouveau_object *object)
eeb3ca12 263{
7dcd060c
BS
264 struct nouveau_i2c *i2c = (void *)object;
265 struct nouveau_i2c_port *port;
266 int ret;
267
268 ret = nouveau_subdev_init(&i2c->base);
269 if (ret == 0) {
270 list_for_each_entry(port, &i2c->ports, head) {
271 ret = nv_ofuncs(port)->init(nv_object(port));
272 if (ret)
273 goto fail;
274 }
2bdb06e3 275 }
4196faa8 276
7dcd060c
BS
277 return ret;
278fail:
279 list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
280 nv_ofuncs(port)->fini(nv_object(port), false);
2bdb06e3 281 }
4196faa8 282
7dcd060c 283 return ret;
eeb3ca12 284}
6ee73861 285
7dcd060c
BS
286void
287_nouveau_i2c_dtor(struct nouveau_object *object)
df3ef6a1 288{
7dcd060c
BS
289 struct nouveau_i2c *i2c = (void *)object;
290 struct nouveau_i2c_port *port, *temp;
291
292 list_for_each_entry_safe(port, temp, &i2c->ports, head) {
293 nouveau_object_ref(NULL, (struct nouveau_object **)&port);
df3ef6a1
BS
294 }
295
7dcd060c 296 nouveau_subdev_destroy(&i2c->base);
df3ef6a1
BS
297}
298
5effecd4
BS
299static struct nouveau_oclass *
300nouveau_i2c_extdev_sclass[] = {
301 nouveau_anx9805_sclass,
302};
303
7dcd060c
BS
304int
305nouveau_i2c_create_(struct nouveau_object *parent,
306 struct nouveau_object *engine,
307 struct nouveau_oclass *oclass,
7dcd060c 308 int length, void **pobject)
6ee73861 309{
c26fe843 310 const struct nouveau_i2c_impl *impl = (void *)oclass;
4196faa8 311 struct nouveau_bios *bios = nouveau_bios(parent);
4196faa8 312 struct nouveau_i2c *i2c;
7dcd060c 313 struct nouveau_object *object;
4196faa8 314 struct dcb_i2c_entry info;
5effecd4
BS
315 int ret, i, j, index = -1;
316 struct dcb_output outp;
317 u8 ver, hdr;
318 u32 data;
4196faa8
BS
319
320 ret = nouveau_subdev_create(parent, engine, oclass, 0,
321 "I2C", "i2c", &i2c);
322 *pobject = nv_object(i2c);
323 if (ret)
324 return ret;
325
326 i2c->find = nouveau_i2c_find;
548ddb6d 327 i2c->find_type = nouveau_i2c_find_type;
4196faa8
BS
328 i2c->identify = nouveau_i2c_identify;
329 INIT_LIST_HEAD(&i2c->ports);
330
7dcd060c 331 while (!dcb_i2c_parse(bios, ++index, &info)) {
4196faa8
BS
332 if (info.type == DCB_I2C_UNUSED)
333 continue;
6ee73861 334
c26fe843 335 oclass = impl->sclass;
7dcd060c
BS
336 do {
337 ret = -EINVAL;
338 if (oclass->handle == info.type) {
339 ret = nouveau_object_ctor(*pobject, *pobject,
340 oclass, &info,
341 index, &object);
4196faa8 342 }
7dcd060c 343 } while (ret && (++oclass)->handle);
6ee73861
BS
344 }
345
5effecd4
BS
346 /* in addition to the busses specified in the i2c table, there
347 * may be ddc/aux channels hiding behind external tmds/dp/etc
348 * transmitters.
349 */
350 index = ((index + 0x0f) / 0x10) * 0x10;
351 i = -1;
352 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
353 if (!outp.location || !outp.extdev)
354 continue;
355
356 switch (outp.type) {
357 case DCB_OUTPUT_TMDS:
358 info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
359 break;
360 case DCB_OUTPUT_DP:
361 info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
362 break;
363 default:
364 continue;
365 }
366
367 ret = -ENODEV;
368 j = -1;
369 while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) {
370 parent = nv_object(i2c->find(i2c, outp.i2c_index));
371 oclass = nouveau_i2c_extdev_sclass[j];
372 do {
373 if (oclass->handle != info.type)
374 continue;
375 ret = nouveau_object_ctor(parent, *pobject,
376 oclass, NULL,
377 index++, &object);
378 } while (ret && (++oclass)->handle);
379 }
380 }
381
6ee73861
BS
382 return 0;
383}
c26fe843
BS
384
385int
386_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
387 struct nouveau_oclass *oclass, void *data, u32 size,
388 struct nouveau_object **pobject)
389{
390 struct nouveau_i2c *i2c;
391 int ret;
392
393 ret = nouveau_i2c_create(parent, engine, oclass, &i2c);
394 *pobject = nv_object(i2c);
395 if (ret)
396 return ret;
397
398 return 0;
399}
This page took 0.318249 seconds and 5 git commands to generate.