diff options
author | Martin Peres <martin.peres@labri.fr> | 2013-10-20 19:48:55 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-11-08 00:39:54 -0500 |
commit | 9e2b734f1cc43e94558bfd2b779d8e493abea0f4 (patch) | |
tree | 7506e6f685b099eff0667484112834f5cae83e45 | |
parent | fd34381b0e2827228cbda45aa2cca4127ff073b2 (diff) |
drm/nouveau/i2c: use a custom bitbanging delay for the adt7473
This patch adds a way to define a custom delay when scanning for i2c devices
because the adt7473 sometimes doesn't like the default bitbanging udelay.
Signed-off-by: Martin Peres <martin.peres@labri.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/i2c.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/therm/ic.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv04/dfp.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | 22 |
5 files changed, 77 insertions, 49 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h index 7e4e2775f249..9fa5da723871 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h | |||
@@ -60,13 +60,18 @@ void _nouveau_i2c_port_dtor(struct nouveau_object *); | |||
60 | #define _nouveau_i2c_port_init nouveau_object_init | 60 | #define _nouveau_i2c_port_init nouveau_object_init |
61 | #define _nouveau_i2c_port_fini nouveau_object_fini | 61 | #define _nouveau_i2c_port_fini nouveau_object_fini |
62 | 62 | ||
63 | struct nouveau_i2c_board_info { | ||
64 | struct i2c_board_info dev; | ||
65 | u8 udelay; /* set to 0 to use the standard delay */ | ||
66 | }; | ||
67 | |||
63 | struct nouveau_i2c { | 68 | struct nouveau_i2c { |
64 | struct nouveau_subdev base; | 69 | struct nouveau_subdev base; |
65 | 70 | ||
66 | struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); | 71 | struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); |
67 | struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); | 72 | struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); |
68 | int (*identify)(struct nouveau_i2c *, int index, | 73 | int (*identify)(struct nouveau_i2c *, int index, |
69 | const char *what, struct i2c_board_info *, | 74 | const char *what, struct nouveau_i2c_board_info *, |
70 | bool (*match)(struct nouveau_i2c_port *, | 75 | bool (*match)(struct nouveau_i2c_port *, |
71 | struct i2c_board_info *)); | 76 | struct i2c_board_info *)); |
72 | struct list_head ports; | 77 | struct list_head ports; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 2895c19bb152..041fd5edaebf 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c | |||
@@ -195,7 +195,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type) | |||
195 | 195 | ||
196 | static int | 196 | static int |
197 | nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, | 197 | nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, |
198 | struct i2c_board_info *info, | 198 | struct nouveau_i2c_board_info *info, |
199 | bool (*match)(struct nouveau_i2c_port *, | 199 | bool (*match)(struct nouveau_i2c_port *, |
200 | struct i2c_board_info *)) | 200 | struct i2c_board_info *)) |
201 | { | 201 | { |
@@ -208,12 +208,29 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, | |||
208 | } | 208 | } |
209 | 209 | ||
210 | nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); | 210 | nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); |
211 | for (i = 0; info[i].addr; i++) { | 211 | for (i = 0; info[i].dev.addr; i++) { |
212 | if (nv_probe_i2c(port, info[i].addr) && | 212 | u8 orig_udelay = 0; |
213 | (!match || match(port, &info[i]))) { | 213 | |
214 | nv_info(i2c, "detected %s: %s\n", what, info[i].type); | 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) && | ||
224 | (!match || match(port, &info[i].dev))) { | ||
225 | nv_info(i2c, "detected %s: %s\n", what, | ||
226 | info[i].dev.type); | ||
215 | return i; | 227 | return i; |
216 | } | 228 | } |
229 | |||
230 | if (orig_udelay) { | ||
231 | struct i2c_algo_bit_data *algo = port->adapter.algo_data; | ||
232 | algo->udelay = orig_udelay; | ||
233 | } | ||
217 | } | 234 | } |
218 | 235 | ||
219 | nv_debug(i2c, "no devices found.\n"); | 236 | nv_debug(i2c, "no devices found.\n"); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c index 8b3adec5fbb1..13b850076443 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c | |||
@@ -55,28 +55,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, | |||
55 | return true; | 55 | return true; |
56 | } | 56 | } |
57 | 57 | ||
58 | static struct i2c_board_info | 58 | static struct nouveau_i2c_board_info |
59 | nv_board_infos[] = { | 59 | nv_board_infos[] = { |
60 | { I2C_BOARD_INFO("w83l785ts", 0x2d) }, | 60 | { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 }, |
61 | { I2C_BOARD_INFO("w83781d", 0x2d) }, | 61 | { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 }, |
62 | { I2C_BOARD_INFO("adt7473", 0x2e) }, | 62 | { { I2C_BOARD_INFO("adt7473", 0x2e) }, 20 }, |
63 | { I2C_BOARD_INFO("adt7473", 0x2d) }, | 63 | { { I2C_BOARD_INFO("adt7473", 0x2d) }, 20 }, |
64 | { I2C_BOARD_INFO("adt7473", 0x2c) }, | 64 | { { I2C_BOARD_INFO("adt7473", 0x2c) }, 20 }, |
65 | { I2C_BOARD_INFO("f75375", 0x2e) }, | 65 | { { I2C_BOARD_INFO("f75375", 0x2e) }, 0 }, |
66 | { I2C_BOARD_INFO("lm99", 0x4c) }, | 66 | { { I2C_BOARD_INFO("lm99", 0x4c) }, 0 }, |
67 | { I2C_BOARD_INFO("lm90", 0x4c) }, | 67 | { { I2C_BOARD_INFO("lm90", 0x4c) }, 0 }, |
68 | { I2C_BOARD_INFO("lm90", 0x4d) }, | 68 | { { I2C_BOARD_INFO("lm90", 0x4d) }, 0 }, |
69 | { I2C_BOARD_INFO("adm1021", 0x18) }, | 69 | { { I2C_BOARD_INFO("adm1021", 0x18) }, 0 }, |
70 | { I2C_BOARD_INFO("adm1021", 0x19) }, | 70 | { { I2C_BOARD_INFO("adm1021", 0x19) }, 0 }, |
71 | { I2C_BOARD_INFO("adm1021", 0x1a) }, | 71 | { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 }, |
72 | { I2C_BOARD_INFO("adm1021", 0x29) }, | 72 | { { I2C_BOARD_INFO("adm1021", 0x29) }, 0 }, |
73 | { I2C_BOARD_INFO("adm1021", 0x2a) }, | 73 | { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 }, |
74 | { I2C_BOARD_INFO("adm1021", 0x2b) }, | 74 | { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 }, |
75 | { I2C_BOARD_INFO("adm1021", 0x4c) }, | 75 | { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 }, |
76 | { I2C_BOARD_INFO("adm1021", 0x4d) }, | 76 | { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 }, |
77 | { I2C_BOARD_INFO("adm1021", 0x4e) }, | 77 | { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 }, |
78 | { I2C_BOARD_INFO("lm63", 0x18) }, | 78 | { { I2C_BOARD_INFO("lm63", 0x18) }, 0 }, |
79 | { I2C_BOARD_INFO("lm63", 0x4e) }, | 79 | { { I2C_BOARD_INFO("lm63", 0x4e) }, 0 }, |
80 | { } | 80 | { } |
81 | }; | 81 | }; |
82 | 82 | ||
@@ -89,9 +89,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) | |||
89 | struct nvbios_extdev_func extdev_entry; | 89 | struct nvbios_extdev_func extdev_entry; |
90 | 90 | ||
91 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { | 91 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { |
92 | struct i2c_board_info board[] = { | 92 | struct nouveau_i2c_board_info board[] = { |
93 | { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, | 93 | { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0}, |
94 | { } | 94 | { } |
95 | }; | 95 | }; |
96 | 96 | ||
97 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", | 97 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", |
@@ -101,9 +101,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) | |||
101 | } | 101 | } |
102 | 102 | ||
103 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { | 103 | if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { |
104 | struct i2c_board_info board[] = { | 104 | struct nouveau_i2c_board_info board[] = { |
105 | { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, | 105 | { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 }, |
106 | { } | 106 | { } |
107 | }; | 107 | }; |
108 | 108 | ||
109 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", | 109 | i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", |
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index bb6c3c3f981d..936a71c59080 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c | |||
@@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) | |||
625 | struct nouveau_drm *drm = nouveau_drm(dev); | 625 | struct nouveau_drm *drm = nouveau_drm(dev); |
626 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | 626 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); |
627 | struct nouveau_i2c_port *port = i2c->find(i2c, 2); | 627 | struct nouveau_i2c_port *port = i2c->find(i2c, 2); |
628 | struct i2c_board_info info[] = { | 628 | struct nouveau_i2c_board_info info[] = { |
629 | { | 629 | { |
630 | .type = "sil164", | 630 | { |
631 | .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), | 631 | .type = "sil164", |
632 | .platform_data = &(struct sil164_encoder_params) { | 632 | .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), |
633 | SIL164_INPUT_EDGE_RISING | 633 | .platform_data = &(struct sil164_encoder_params) { |
634 | } | 634 | SIL164_INPUT_EDGE_RISING |
635 | } | ||
636 | }, 0 | ||
635 | }, | 637 | }, |
636 | { } | 638 | { } |
637 | }; | 639 | }; |
@@ -646,7 +648,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) | |||
646 | return; | 648 | return; |
647 | 649 | ||
648 | drm_i2c_encoder_init(dev, to_encoder_slave(encoder), | 650 | drm_i2c_encoder_init(dev, to_encoder_slave(encoder), |
649 | &port->adapter, &info[type]); | 651 | &port->adapter, &info[type].dev); |
650 | } | 652 | } |
651 | 653 | ||
652 | static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { | 654 | static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { |
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index bf13db4e8631..cc4b208ce546 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | |||
@@ -37,15 +37,18 @@ | |||
37 | 37 | ||
38 | #include <subdev/i2c.h> | 38 | #include <subdev/i2c.h> |
39 | 39 | ||
40 | static struct i2c_board_info nv04_tv_encoder_info[] = { | 40 | static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = { |
41 | { | 41 | { |
42 | I2C_BOARD_INFO("ch7006", 0x75), | 42 | { |
43 | .platform_data = &(struct ch7006_encoder_params) { | 43 | I2C_BOARD_INFO("ch7006", 0x75), |
44 | CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, | 44 | .platform_data = &(struct ch7006_encoder_params) { |
45 | 0, 0, 0, | 45 | CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, |
46 | CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, | 46 | 0, 0, 0, |
47 | CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC | 47 | CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, |
48 | } | 48 | CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC |
49 | } | ||
50 | }, | ||
51 | 0 | ||
49 | }, | 52 | }, |
50 | { } | 53 | { } |
51 | }; | 54 | }; |
@@ -229,7 +232,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) | |||
229 | 232 | ||
230 | /* Run the slave-specific initialization */ | 233 | /* Run the slave-specific initialization */ |
231 | ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), | 234 | ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), |
232 | &port->adapter, &nv04_tv_encoder_info[type]); | 235 | &port->adapter, |
236 | &nv04_tv_encoder_info[type].dev); | ||
233 | if (ret < 0) | 237 | if (ret < 0) |
234 | goto fail_cleanup; | 238 | goto fail_cleanup; |
235 | 239 | ||