Commit 9e2b734f authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs

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: default avatarMartin Peres <martin.peres@labri.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent fd34381b
...@@ -60,13 +60,18 @@ void _nouveau_i2c_port_dtor(struct nouveau_object *); ...@@ -60,13 +60,18 @@ void _nouveau_i2c_port_dtor(struct nouveau_object *);
#define _nouveau_i2c_port_init nouveau_object_init #define _nouveau_i2c_port_init nouveau_object_init
#define _nouveau_i2c_port_fini nouveau_object_fini #define _nouveau_i2c_port_fini nouveau_object_fini
struct nouveau_i2c_board_info {
struct i2c_board_info dev;
u8 udelay; /* set to 0 to use the standard delay */
};
struct nouveau_i2c { struct nouveau_i2c {
struct nouveau_subdev base; struct nouveau_subdev base;
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
int (*identify)(struct nouveau_i2c *, int index, int (*identify)(struct nouveau_i2c *, int index,
const char *what, struct i2c_board_info *, const char *what, struct nouveau_i2c_board_info *,
bool (*match)(struct nouveau_i2c_port *, bool (*match)(struct nouveau_i2c_port *,
struct i2c_board_info *)); struct i2c_board_info *));
struct list_head ports; struct list_head ports;
......
...@@ -195,7 +195,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type) ...@@ -195,7 +195,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
static int static int
nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
struct i2c_board_info *info, struct nouveau_i2c_board_info *info,
bool (*match)(struct nouveau_i2c_port *, bool (*match)(struct nouveau_i2c_port *,
struct i2c_board_info *)) struct i2c_board_info *))
{ {
...@@ -208,12 +208,29 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, ...@@ -208,12 +208,29 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
} }
nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
for (i = 0; info[i].addr; i++) { for (i = 0; info[i].dev.addr; i++) {
if (nv_probe_i2c(port, info[i].addr) && u8 orig_udelay = 0;
(!match || match(port, &info[i]))) {
nv_info(i2c, "detected %s: %s\n", what, info[i].type); if ((port->adapter.algo == &i2c_bit_algo) &&
(info[i].udelay != 0)) {
struct i2c_algo_bit_data *algo = port->adapter.algo_data;
nv_debug(i2c, "using custom udelay %d instead of %d\n",
info[i].udelay, algo->udelay);
orig_udelay = algo->udelay;
algo->udelay = info[i].udelay;
}
if (nv_probe_i2c(port, info[i].dev.addr) &&
(!match || match(port, &info[i].dev))) {
nv_info(i2c, "detected %s: %s\n", what,
info[i].dev.type);
return i; return i;
} }
if (orig_udelay) {
struct i2c_algo_bit_data *algo = port->adapter.algo_data;
algo->udelay = orig_udelay;
}
} }
nv_debug(i2c, "no devices found.\n"); nv_debug(i2c, "no devices found.\n");
......
...@@ -55,28 +55,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, ...@@ -55,28 +55,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
return true; return true;
} }
static struct i2c_board_info static struct nouveau_i2c_board_info
nv_board_infos[] = { nv_board_infos[] = {
{ I2C_BOARD_INFO("w83l785ts", 0x2d) }, { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
{ I2C_BOARD_INFO("w83781d", 0x2d) }, { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 },
{ I2C_BOARD_INFO("adt7473", 0x2e) }, { { I2C_BOARD_INFO("adt7473", 0x2e) }, 20 },
{ I2C_BOARD_INFO("adt7473", 0x2d) }, { { I2C_BOARD_INFO("adt7473", 0x2d) }, 20 },
{ I2C_BOARD_INFO("adt7473", 0x2c) }, { { I2C_BOARD_INFO("adt7473", 0x2c) }, 20 },
{ I2C_BOARD_INFO("f75375", 0x2e) }, { { I2C_BOARD_INFO("f75375", 0x2e) }, 0 },
{ I2C_BOARD_INFO("lm99", 0x4c) }, { { I2C_BOARD_INFO("lm99", 0x4c) }, 0 },
{ I2C_BOARD_INFO("lm90", 0x4c) }, { { I2C_BOARD_INFO("lm90", 0x4c) }, 0 },
{ I2C_BOARD_INFO("lm90", 0x4d) }, { { I2C_BOARD_INFO("lm90", 0x4d) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x18) }, { { I2C_BOARD_INFO("adm1021", 0x18) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x19) }, { { I2C_BOARD_INFO("adm1021", 0x19) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x1a) }, { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x29) }, { { I2C_BOARD_INFO("adm1021", 0x29) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x2a) }, { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x2b) }, { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x4c) }, { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x4d) }, { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 },
{ I2C_BOARD_INFO("adm1021", 0x4e) }, { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 },
{ I2C_BOARD_INFO("lm63", 0x18) }, { { I2C_BOARD_INFO("lm63", 0x18) }, 0 },
{ I2C_BOARD_INFO("lm63", 0x4e) }, { { I2C_BOARD_INFO("lm63", 0x4e) }, 0 },
{ } { }
}; };
...@@ -89,8 +89,8 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) ...@@ -89,8 +89,8 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
struct nvbios_extdev_func extdev_entry; struct nvbios_extdev_func extdev_entry;
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
struct i2c_board_info board[] = { struct nouveau_i2c_board_info board[] = {
{ I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
{ } { }
}; };
...@@ -101,8 +101,8 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) ...@@ -101,8 +101,8 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
} }
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
struct i2c_board_info board[] = { struct nouveau_i2c_board_info board[] = {
{ I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
{ } { }
}; };
......
...@@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) ...@@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_i2c *i2c = nouveau_i2c(drm->device); struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
struct nouveau_i2c_port *port = i2c->find(i2c, 2); struct nouveau_i2c_port *port = i2c->find(i2c, 2);
struct i2c_board_info info[] = { struct nouveau_i2c_board_info info[] = {
{
{ {
.type = "sil164", .type = "sil164",
.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
.platform_data = &(struct sil164_encoder_params) { .platform_data = &(struct sil164_encoder_params) {
SIL164_INPUT_EDGE_RISING SIL164_INPUT_EDGE_RISING
} }
}, 0
}, },
{ } { }
}; };
...@@ -646,7 +648,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) ...@@ -646,7 +648,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
return; return;
drm_i2c_encoder_init(dev, to_encoder_slave(encoder), drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
&port->adapter, &info[type]); &port->adapter, &info[type].dev);
} }
static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
......
...@@ -37,7 +37,8 @@ ...@@ -37,7 +37,8 @@
#include <subdev/i2c.h> #include <subdev/i2c.h>
static struct i2c_board_info nv04_tv_encoder_info[] = { static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = {
{
{ {
I2C_BOARD_INFO("ch7006", 0x75), I2C_BOARD_INFO("ch7006", 0x75),
.platform_data = &(struct ch7006_encoder_params) { .platform_data = &(struct ch7006_encoder_params) {
...@@ -47,6 +48,8 @@ static struct i2c_board_info nv04_tv_encoder_info[] = { ...@@ -47,6 +48,8 @@ static struct i2c_board_info nv04_tv_encoder_info[] = {
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
} }
}, },
0
},
{ } { }
}; };
...@@ -229,7 +232,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) ...@@ -229,7 +232,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
/* Run the slave-specific initialization */ /* Run the slave-specific initialization */
ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
&port->adapter, &nv04_tv_encoder_info[type]); &port->adapter,
&nv04_tv_encoder_info[type].dev);
if (ret < 0) if (ret < 0)
goto fail_cleanup; goto fail_cleanup;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment