Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 331548
b: refs/heads/master
c: 3ad7ea1
h: refs/heads/master
v: v3
  • Loading branch information
Jean Delvare authored and Jean Delvare committed Oct 5, 2012
1 parent 05f4598 commit 97b075c
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 01d56a6aa1c3a506426c8f3ff87c8d698023f336
refs/heads/master: 3ad7ea18ae8c7ddda46b7276e0bda73e707ea9c1
1 change: 1 addition & 0 deletions trunk/drivers/i2c/busses/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ config I2C_I801
tristate "Intel 82801 (ICH/PCH)"
depends on PCI
select CHECK_SIGNATURE if X86 && DMI
select GPIOLIB if I2C_MUX
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
Expand Down
214 changes: 213 additions & 1 deletion trunk/drivers/i2c/busses/i2c-i801.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/err.h>

#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
#include <linux/gpio.h>
#include <linux/i2c-mux-gpio.h>
#include <linux/platform_device.h>
#endif

/* I801 SMBus address offsets */
#define SMBHSTSTS(p) (0 + (p)->smba)
Expand Down Expand Up @@ -158,6 +165,15 @@
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22

struct i801_mux_config {
char *gpio_chip;
unsigned values[3];
int n_values;
unsigned classes[3];
unsigned gpios[2]; /* Relative to gpio_chip->base */
int n_gpios;
};

struct i801_priv {
struct i2c_adapter adapter;
unsigned long smba;
Expand All @@ -175,6 +191,12 @@ struct i801_priv {
int count;
int len;
u8 *data;

#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
const struct i801_mux_config *mux_drvdata;
unsigned mux_priv[2];
struct platform_device *mux_pdev;
#endif
};

static struct pci_driver i801_driver;
Expand Down Expand Up @@ -900,6 +922,193 @@ static void __init input_apanel_init(void) {}
static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
#endif /* CONFIG_X86 && CONFIG_DMI */

#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
.gpio_chip = "gpio_ich",
.values = { 0x02, 0x03 },
.n_values = 2,
.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
.gpios = { 52, 53 },
.n_gpios = 2,
};

static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
.gpio_chip = "gpio_ich",
.values = { 0x02, 0x03, 0x01 },
.n_values = 3,
.classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
.gpios = { 52, 53 },
.n_gpios = 2,
};

static struct dmi_system_id __devinitdata mux_dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
},
.driver_data = &i801_mux_config_asus_z8_d18,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
},
.driver_data = &i801_mux_config_asus_z8_d18,
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
},
.driver_data = &i801_mux_config_asus_z8_d12,
},
{ }
};

static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
void *data)
{
return !strcmp(chip->label, data);
}

/* Setup multiplexing if needed */
static int __devinit i801_add_mux(struct i801_priv *priv)
{
struct device *dev = &priv->adapter.dev;
const struct i801_mux_config *mux_config;
struct gpio_chip *gpio;
struct i2c_mux_gpio_platform_data gpio_data;
int i, err;

if (!priv->mux_drvdata)
return 0;
mux_config = priv->mux_drvdata;

/* Find GPIO chip */
gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label);
if (gpio) {
dev_info(dev,
"GPIO chip %s found, SMBus multiplexing enabled\n",
mux_config->gpio_chip);
} else {
dev_err(dev,
"GPIO chip %s not found, SMBus multiplexing disabled\n",
mux_config->gpio_chip);
return -ENODEV;
}

/* Find absolute GPIO pin numbers */
if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) {
dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n",
ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios);
return -ENODEV;
}
for (i = 0; i < mux_config->n_gpios; i++)
priv->mux_priv[i] = gpio->base + mux_config->gpios[i];

/* Prepare the platform data */
memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
gpio_data.parent = priv->adapter.nr;
gpio_data.values = mux_config->values;
gpio_data.n_values = mux_config->n_values;
gpio_data.classes = mux_config->classes;
gpio_data.gpios = priv->mux_priv;
gpio_data.n_gpios = mux_config->n_gpios;
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;

/* Register the mux device */
priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
priv->mux_priv[0], &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);
priv->mux_pdev = NULL;
dev_err(dev, "Failed to register i2c-mux-gpio device\n");
return err;
}

return 0;
}

static void __devexit i801_del_mux(struct i801_priv *priv)
{
if (priv->mux_pdev)
platform_device_unregister(priv->mux_pdev);
}

static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
{
const struct dmi_system_id *id;
const struct i801_mux_config *mux_config;
unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
int i;

id = dmi_first_match(mux_dmi_table);
if (id) {
/* Remove from branch classes from trunk */
mux_config = id->driver_data;
for (i = 0; i < mux_config->n_values; i++)
class &= ~mux_config->classes[i];

/* Remember for later */
priv->mux_drvdata = mux_config;
}

return class;
}
#else
static inline int i801_add_mux(struct i801_priv *priv) { return 0; }
static inline void i801_del_mux(struct i801_priv *priv) { }

static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
{
return I2C_CLASS_HWMON | I2C_CLASS_SPD;
}
#endif

static int __devinit i801_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
Expand All @@ -913,7 +1122,7 @@ static int __devinit i801_probe(struct pci_dev *dev,

i2c_set_adapdata(&priv->adapter, priv);
priv->adapter.owner = THIS_MODULE;
priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
priv->adapter.class = i801_get_adapter_class(priv);
priv->adapter.algo = &smbus_algorithm;

priv->pci_dev = dev;
Expand Down Expand Up @@ -1033,6 +1242,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
}

i801_probe_optional_slaves(priv);
/* We ignore errors - multiplexing is optional */
i801_add_mux(priv);

pci_set_drvdata(dev, priv);

Expand All @@ -1052,6 +1263,7 @@ static void __devexit i801_remove(struct pci_dev *dev)
{
struct i801_priv *priv = pci_get_drvdata(dev);

i801_del_mux(priv);
i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);

Expand Down

0 comments on commit 97b075c

Please sign in to comment.