OSDN Git Service

Merge tag 'drm-intel-next-2015-04-23-fixed' of git://anongit.freedesktop.org/drm...
[uclinux-h8/linux.git] / drivers / gpu / drm / i915 / intel_i2c.c
index 56e437e..3daa7e3 100644 (file)
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-struct gmbus_port {
+struct gmbus_pin {
        const char *name;
        int reg;
 };
 
-static const struct gmbus_port gmbus_ports[] = {
-       { "ssc", GPIOB },
-       { "vga", GPIOA },
-       { "panel", GPIOC },
-       { "dpc", GPIOD },
-       { "dpb", GPIOE },
-       { "dpd", GPIOF },
+/* Map gmbus pin pairs to names and registers. */
+static const struct gmbus_pin gmbus_pins[] = {
+       [GMBUS_PIN_SSC] = { "ssc", GPIOB },
+       [GMBUS_PIN_VGADDC] = { "vga", GPIOA },
+       [GMBUS_PIN_PANEL] = { "panel", GPIOC },
+       [GMBUS_PIN_DPC] = { "dpc", GPIOD },
+       [GMBUS_PIN_DPB] = { "dpb", GPIOE },
+       [GMBUS_PIN_DPD] = { "dpd", GPIOF },
 };
 
+static const struct gmbus_pin gmbus_pins_bxt[] = {
+       [GMBUS_PIN_1_BXT] = { "dpb", PCH_GPIOB },
+       [GMBUS_PIN_2_BXT] = { "dpc", PCH_GPIOC },
+       [GMBUS_PIN_3_BXT] = { "misc", PCH_GPIOD },
+};
+
+/* pin is expected to be valid */
+static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
+                                            unsigned int pin)
+{
+       if (IS_BROXTON(dev_priv))
+               return &gmbus_pins_bxt[pin];
+       else
+               return &gmbus_pins[pin];
+}
+
+bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
+                             unsigned int pin)
+{
+       unsigned int size;
+
+       if (IS_BROXTON(dev_priv))
+               size = ARRAY_SIZE(gmbus_pins_bxt);
+       else
+               size = ARRAY_SIZE(gmbus_pins);
+
+       return pin < size && get_gmbus_pin(dev_priv, pin)->reg;
+}
+
 /* Intel GPIO access functions */
 
 #define I2C_RISEFALL_TIME 10
@@ -182,15 +212,15 @@ intel_gpio_post_xfer(struct i2c_adapter *adapter)
 }
 
 static void
-intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
+intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
 {
        struct drm_i915_private *dev_priv = bus->dev_priv;
        struct i2c_algo_bit_data *algo;
 
        algo = &bus->bit_algo;
 
-       /* -1 to map pin pair to gmbus index */
-       bus->gpio_reg = dev_priv->gpio_mmio_base + gmbus_ports[pin - 1].reg;
+       bus->gpio_reg = dev_priv->gpio_mmio_base +
+               get_gmbus_pin(dev_priv, pin)->reg;
 
        bus->adapter.algo_data = algo;
        algo->setsda = set_data;
@@ -563,7 +593,9 @@ static const struct i2c_algorithm gmbus_algorithm = {
 int intel_setup_gmbus(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret, i;
+       struct intel_gmbus *bus;
+       unsigned int pin;
+       int ret;
 
        if (HAS_PCH_NOP(dev))
                return 0;
@@ -577,16 +609,18 @@ int intel_setup_gmbus(struct drm_device *dev)
        mutex_init(&dev_priv->gmbus_mutex);
        init_waitqueue_head(&dev_priv->gmbus_wait_queue);
 
-       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
-               struct intel_gmbus *bus = &dev_priv->gmbus[i];
-               u32 port = i + 1; /* +1 to map gmbus index to pin pair */
+       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
+
+               bus = &dev_priv->gmbus[pin];
 
                bus->adapter.owner = THIS_MODULE;
                bus->adapter.class = I2C_CLASS_DDC;
                snprintf(bus->adapter.name,
                         sizeof(bus->adapter.name),
                         "i915 gmbus %s",
-                        gmbus_ports[i].name);
+                        get_gmbus_pin(dev_priv, pin)->name);
 
                bus->adapter.dev.parent = &dev->pdev->dev;
                bus->dev_priv = dev_priv;
@@ -594,13 +628,13 @@ int intel_setup_gmbus(struct drm_device *dev)
                bus->adapter.algo = &gmbus_algorithm;
 
                /* By default use a conservative clock rate */
-               bus->reg0 = port | GMBUS_RATE_100KHZ;
+               bus->reg0 = pin | GMBUS_RATE_100KHZ;
 
                /* gmbus seems to be broken on i830 */
                if (IS_I830(dev))
                        bus->force_bit = 1;
 
-               intel_gpio_setup(bus, port);
+               intel_gpio_setup(bus, pin);
 
                ret = i2c_add_adapter(&bus->adapter);
                if (ret)
@@ -612,20 +646,23 @@ int intel_setup_gmbus(struct drm_device *dev)
        return 0;
 
 err:
-       while (--i) {
-               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+       while (--pin) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
+
+               bus = &dev_priv->gmbus[pin];
                i2c_del_adapter(&bus->adapter);
        }
        return ret;
 }
 
 struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
-                                           unsigned port)
+                                           unsigned int pin)
 {
-       WARN_ON(!intel_gmbus_is_port_valid(port));
-       /* -1 to map pin pair to gmbus index */
-       return (intel_gmbus_is_port_valid(port)) ?
-               &dev_priv->gmbus[port - 1].adapter : NULL;
+       if (WARN_ON(!intel_gmbus_is_valid_pin(dev_priv, pin)))
+               return NULL;
+
+       return &dev_priv->gmbus[pin].adapter;
 }
 
 void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
@@ -648,10 +685,14 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
 void intel_teardown_gmbus(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
+       struct intel_gmbus *bus;
+       unsigned int pin;
+
+       for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) {
+               if (!intel_gmbus_is_valid_pin(dev_priv, pin))
+                       continue;
 
-       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
-               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+               bus = &dev_priv->gmbus[pin];
                i2c_del_adapter(&bus->adapter);
        }
 }