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>
This commit is contained in:
Martin Peres 2013-10-21 01:48:55 +02:00 committed by Ben Skeggs
parent fd34381b0e
commit 9e2b734f1c
5 changed files with 77 additions and 49 deletions

View file

@ -60,13 +60,18 @@ void _nouveau_i2c_port_dtor(struct nouveau_object *);
#define _nouveau_i2c_port_init nouveau_object_init
#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_subdev base;
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
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 *,
struct i2c_board_info *));
struct list_head ports;

View file

@ -195,7 +195,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
static int
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 *,
struct i2c_board_info *))
{
@ -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);
for (i = 0; info[i].addr; i++) {
if (nv_probe_i2c(port, info[i].addr) &&
(!match || match(port, &info[i]))) {
nv_info(i2c, "detected %s: %s\n", what, info[i].type);
for (i = 0; info[i].dev.addr; i++) {
u8 orig_udelay = 0;
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;
}
if (orig_udelay) {
struct i2c_algo_bit_data *algo = port->adapter.algo_data;
algo->udelay = orig_udelay;
}
}
nv_debug(i2c, "no devices found.\n");

View file

@ -55,28 +55,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
return true;
}
static struct i2c_board_info
static struct nouveau_i2c_board_info
nv_board_infos[] = {
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
{ I2C_BOARD_INFO("w83781d", 0x2d) },
{ I2C_BOARD_INFO("adt7473", 0x2e) },
{ I2C_BOARD_INFO("adt7473", 0x2d) },
{ I2C_BOARD_INFO("adt7473", 0x2c) },
{ I2C_BOARD_INFO("f75375", 0x2e) },
{ I2C_BOARD_INFO("lm99", 0x4c) },
{ I2C_BOARD_INFO("lm90", 0x4c) },
{ I2C_BOARD_INFO("lm90", 0x4d) },
{ I2C_BOARD_INFO("adm1021", 0x18) },
{ I2C_BOARD_INFO("adm1021", 0x19) },
{ I2C_BOARD_INFO("adm1021", 0x1a) },
{ I2C_BOARD_INFO("adm1021", 0x29) },
{ I2C_BOARD_INFO("adm1021", 0x2a) },
{ I2C_BOARD_INFO("adm1021", 0x2b) },
{ I2C_BOARD_INFO("adm1021", 0x4c) },
{ I2C_BOARD_INFO("adm1021", 0x4d) },
{ I2C_BOARD_INFO("adm1021", 0x4e) },
{ I2C_BOARD_INFO("lm63", 0x18) },
{ I2C_BOARD_INFO("lm63", 0x4e) },
{ { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
{ { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 },
{ { I2C_BOARD_INFO("adt7473", 0x2e) }, 20 },
{ { I2C_BOARD_INFO("adt7473", 0x2d) }, 20 },
{ { I2C_BOARD_INFO("adt7473", 0x2c) }, 20 },
{ { I2C_BOARD_INFO("f75375", 0x2e) }, 0 },
{ { I2C_BOARD_INFO("lm99", 0x4c) }, 0 },
{ { I2C_BOARD_INFO("lm90", 0x4c) }, 0 },
{ { I2C_BOARD_INFO("lm90", 0x4d) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x18) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x19) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x29) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 },
{ { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 },
{ { I2C_BOARD_INFO("lm63", 0x18) }, 0 },
{ { I2C_BOARD_INFO("lm63", 0x4e) }, 0 },
{ }
};
@ -89,9 +89,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
struct nvbios_extdev_func extdev_entry;
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
struct i2c_board_info board[] = {
{ I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
{ }
struct nouveau_i2c_board_info board[] = {
{ { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
{ }
};
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
@ -101,9 +101,9 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm)
}
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
struct i2c_board_info board[] = {
{ I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
{ }
struct nouveau_i2c_board_info board[] = {
{ { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
{ }
};
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",

View file

@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
struct nouveau_i2c_port *port = i2c->find(i2c, 2);
struct i2c_board_info info[] = {
struct nouveau_i2c_board_info info[] = {
{
.type = "sil164",
.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
.platform_data = &(struct sil164_encoder_params) {
SIL164_INPUT_EDGE_RISING
}
{
.type = "sil164",
.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
.platform_data = &(struct sil164_encoder_params) {
SIL164_INPUT_EDGE_RISING
}
}, 0
},
{ }
};
@ -646,7 +648,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
return;
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 = {

View file

@ -37,15 +37,18 @@
#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),
.platform_data = &(struct ch7006_encoder_params) {
CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
0, 0, 0,
CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
}
{
I2C_BOARD_INFO("ch7006", 0x75),
.platform_data = &(struct ch7006_encoder_params) {
CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
0, 0, 0,
CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
}
},
0
},
{ }
};
@ -229,7 +232,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
/* Run the slave-specific initialization */
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)
goto fail_cleanup;