From 66146da06643d8ee89bc5255fb0254006e3d0e79 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 23 Sep 2010 21:00:40 +0200 Subject: [PATCH] drm/nouveau: Add support for I2C hardware monitoring devices. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_i2c.c | 8 +++-- drivers/gpu/drm/nouveau/nouveau_i2c.h | 5 ++- drivers/gpu/drm/nouveau/nouveau_temp.c | 48 ++++++++++++++++++++++++-- drivers/gpu/drm/nouveau/nv04_dfp.c | 2 +- drivers/gpu/drm/nouveau/nv04_tv.c | 4 +-- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 84614858728b..fdd7e3de79c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -299,7 +299,10 @@ nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr) int nouveau_i2c_identify(struct drm_device *dev, const char *what, - struct i2c_board_info *info, int index) + struct i2c_board_info *info, + bool (*match)(struct nouveau_i2c_chan *, + struct i2c_board_info *), + int index) { struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index); int i; @@ -307,7 +310,8 @@ nouveau_i2c_identify(struct drm_device *dev, const char *what, NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); for (i = 0; info[i].addr; i++) { - if (nouveau_probe_i2c_addr(i2c, info[i].addr)) { + if (nouveau_probe_i2c_addr(i2c, info[i].addr) && + (!match || match(i2c, &info[i]))) { NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); return i; } diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index f71cb32f7571..c77a6ba66b7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -44,7 +44,10 @@ void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); int nouveau_i2c_identify(struct drm_device *dev, const char *what, - struct i2c_board_info *info, int index); + struct i2c_board_info *info, + bool (*match)(struct nouveau_i2c_chan *, + struct i2c_board_info *), + int index); extern const struct i2c_algorithm nouveau_dp_i2c_algo; diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 2f7785ca4e48..f9eda87d1773 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -235,6 +235,48 @@ nouveau_temp_safety_checks(struct drm_device *dev) temps->fan_boost = 40; } +static bool +probe_monitoring_device(struct nouveau_i2c_chan *i2c, + struct i2c_board_info *info) +{ + char modalias[16] = "i2c:"; + struct i2c_client *client; + + strlcat(modalias, info->type, sizeof(modalias)); + request_module(modalias); + + client = i2c_new_device(&i2c->adapter, info); + if (!client) + return false; + + if (!client->driver || client->driver->detect(client, info)) { + i2c_unregister_device(client); + return false; + } + + return true; +} + +static void +nouveau_temp_probe_i2c(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; + struct i2c_board_info info[] = { + { I2C_BOARD_INFO("w83l785ts", 0x2d) }, + { I2C_BOARD_INFO("w83781d", 0x2d) }, + { I2C_BOARD_INFO("f75375", 0x2e) }, + { I2C_BOARD_INFO("adt7473", 0x2e) }, + { I2C_BOARD_INFO("lm99", 0x4c) }, + { } + }; + int idx = (dcb->version >= 0x40 ? + dcb->i2c_default_indices & 0xf : 2); + + nouveau_i2c_identify(dev, "monitoring device", info, + probe_monitoring_device, idx); +} + void nouveau_temp_init(struct drm_device *dev) { @@ -253,11 +295,11 @@ nouveau_temp_init(struct drm_device *dev) temp = ROMPTR(bios, P.data[16]); else NV_WARN(dev, "unknown temp for BIT P %d\n", P.version); - } else { - NV_WARN(dev, "BMP entry unknown for temperature table.\n"); + + nouveau_temp_vbios_parse(dev, temp); } - nouveau_temp_vbios_parse(dev, temp); + nouveau_temp_probe_i2c(dev); } void diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index e331b4faeb10..4b4f9aabde70 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -635,7 +635,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) get_tmds_slave(encoder)) return; - type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); + type = nouveau_i2c_identify(dev, "TMDS transmitter", info, NULL, 2); if (type < 0) return; diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 0b5d012d7c28..c8dc8a376ad9 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -49,8 +49,8 @@ static struct i2c_board_info nv04_tv_encoder_info[] = { int nv04_tv_identify(struct drm_device *dev, int i2c_index) { - return nouveau_i2c_identify(dev, "TV encoder", - nv04_tv_encoder_info, i2c_index); + return nouveau_i2c_identify(dev, "TV encoder", nv04_tv_encoder_info, + NULL, i2c_index); }