drm/nouveau: Add support for I2C hardware monitoring devices.
authorFrancisco Jerez <currojerez@riseup.net>
Thu, 23 Sep 2010 19:00:40 +0000 (21:00 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 24 Sep 2010 06:29:36 +0000 (16:29 +1000)
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_i2c.h
drivers/gpu/drm/nouveau/nouveau_temp.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_tv.c

index 84614858728ba0f7ab959b54989cf9a512d89d6a..fdd7e3de79c895138c93706bc023048772f93026 100644 (file)
@@ -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;
                }
index f71cb32f75715a9e4172a5b65359feca947994ac..c77a6ba66b7c08d56851af6dd4dee0abca9e1604 100644 (file)
@@ -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;
 
index 2f7785ca4e482836b5e7c23fc36fde909029e803..f9eda87d1773bde7e2bd81473a44e907e70a3038 100644 (file)
@@ -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
index e331b4faeb10f32c730dced62cfc1f5d786d2973..4b4f9aabde70cbbb60281c8300b9909c1deb31a2 100644 (file)
@@ -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;
 
index 0b5d012d7c28d4aebacf8aa15576cebe71b36c84..c8dc8a376ad9c21f33c4585610739c3f7dd391ef 100644 (file)
@@ -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);
 }