aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2012-10-05 16:23:53 -0400
committerJean Delvare <khali@endymion.delvare>2012-10-05 16:23:53 -0400
commit3ad7ea18ae8c7ddda46b7276e0bda73e707ea9c1 (patch)
tree7d2fca72b185fc7dd985306e9cc16caecdbdad04 /drivers/i2c
parent01d56a6aa1c3a506426c8f3ff87c8d698023f336 (diff)
i2c-i801: Support SMBus multiplexing on Asus Z8 series
Add support for SMBus multiplexing on Asus Z8 motherboard series. On these boards, the memory slots are behind a GPIO-controlled I2C multiplexer. Models with 6 or 12 memory slots have 2 segments behind the multiplexer, while models with 18 memory slots have 3 such segments. On these boards, only the memory slots are behind the multiplexer, so it is possible to keep the autodetection mechanism. The code is generic enough so it could work on other boards as long as the multiplexer is controlled by GPIO pins. For other forms of multiplexing (for example using an I2C device) additional code will be needed. Thanks to Asus for providing a board to develop and test this feature, as well as all the technical information required. At the moment, the GPIO driver must be loaded before the i2c-i801 driver, but I hope to solve this soon, using deferred probing on the i2c-mux-gpio side. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/i2c-i801.c214
2 files changed, 214 insertions, 1 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7f69f500daf2..ff01c389e2da 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -81,6 +81,7 @@ config I2C_I801
81 tristate "Intel 82801 (ICH/PCH)" 81 tristate "Intel 82801 (ICH/PCH)"
82 depends on PCI 82 depends on PCI
83 select CHECK_SIGNATURE if X86 && DMI 83 select CHECK_SIGNATURE if X86 && DMI
84 select GPIOLIB if I2C_MUX
84 help 85 help
85 If you say yes to this option, support will be included for the Intel 86 If you say yes to this option, support will be included for the Intel
86 801 family of mainboard I2C interfaces. Specifically, the following 87 801 family of mainboard I2C interfaces. Specifically, the following
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 33e9b0c09af2..bb1d7291cf21 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -80,6 +80,13 @@
80#include <linux/dmi.h> 80#include <linux/dmi.h>
81#include <linux/slab.h> 81#include <linux/slab.h>
82#include <linux/wait.h> 82#include <linux/wait.h>
83#include <linux/err.h>
84
85#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
86#include <linux/gpio.h>
87#include <linux/i2c-mux-gpio.h>
88#include <linux/platform_device.h>
89#endif
83 90
84/* I801 SMBus address offsets */ 91/* I801 SMBus address offsets */
85#define SMBHSTSTS(p) (0 + (p)->smba) 92#define SMBHSTSTS(p) (0 + (p)->smba)
@@ -158,6 +165,15 @@
158#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 165#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
159#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 166#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
160 167
168struct i801_mux_config {
169 char *gpio_chip;
170 unsigned values[3];
171 int n_values;
172 unsigned classes[3];
173 unsigned gpios[2]; /* Relative to gpio_chip->base */
174 int n_gpios;
175};
176
161struct i801_priv { 177struct i801_priv {
162 struct i2c_adapter adapter; 178 struct i2c_adapter adapter;
163 unsigned long smba; 179 unsigned long smba;
@@ -175,6 +191,12 @@ struct i801_priv {
175 int count; 191 int count;
176 int len; 192 int len;
177 u8 *data; 193 u8 *data;
194
195#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
196 const struct i801_mux_config *mux_drvdata;
197 unsigned mux_priv[2];
198 struct platform_device *mux_pdev;
199#endif
178}; 200};
179 201
180static struct pci_driver i801_driver; 202static struct pci_driver i801_driver;
@@ -900,6 +922,193 @@ static void __init input_apanel_init(void) {}
900static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {} 922static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
901#endif /* CONFIG_X86 && CONFIG_DMI */ 923#endif /* CONFIG_X86 && CONFIG_DMI */
902 924
925#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
926static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
927 .gpio_chip = "gpio_ich",
928 .values = { 0x02, 0x03 },
929 .n_values = 2,
930 .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
931 .gpios = { 52, 53 },
932 .n_gpios = 2,
933};
934
935static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
936 .gpio_chip = "gpio_ich",
937 .values = { 0x02, 0x03, 0x01 },
938 .n_values = 3,
939 .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
940 .gpios = { 52, 53 },
941 .n_gpios = 2,
942};
943
944static struct dmi_system_id __devinitdata mux_dmi_table[] = {
945 {
946 .matches = {
947 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
948 DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
949 },
950 .driver_data = &i801_mux_config_asus_z8_d12,
951 },
952 {
953 .matches = {
954 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
955 DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
956 },
957 .driver_data = &i801_mux_config_asus_z8_d12,
958 },
959 {
960 .matches = {
961 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
962 DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
963 },
964 .driver_data = &i801_mux_config_asus_z8_d12,
965 },
966 {
967 .matches = {
968 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
969 DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
970 },
971 .driver_data = &i801_mux_config_asus_z8_d12,
972 },
973 {
974 .matches = {
975 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
976 DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
977 },
978 .driver_data = &i801_mux_config_asus_z8_d12,
979 },
980 {
981 .matches = {
982 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
983 DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
984 },
985 .driver_data = &i801_mux_config_asus_z8_d12,
986 },
987 {
988 .matches = {
989 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
990 DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
991 },
992 .driver_data = &i801_mux_config_asus_z8_d18,
993 },
994 {
995 .matches = {
996 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
997 DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
998 },
999 .driver_data = &i801_mux_config_asus_z8_d18,
1000 },
1001 {
1002 .matches = {
1003 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
1004 DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
1005 },
1006 .driver_data = &i801_mux_config_asus_z8_d12,
1007 },
1008 { }
1009};
1010
1011static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
1012 void *data)
1013{
1014 return !strcmp(chip->label, data);
1015}
1016
1017/* Setup multiplexing if needed */
1018static int __devinit i801_add_mux(struct i801_priv *priv)
1019{
1020 struct device *dev = &priv->adapter.dev;
1021 const struct i801_mux_config *mux_config;
1022 struct gpio_chip *gpio;
1023 struct i2c_mux_gpio_platform_data gpio_data;
1024 int i, err;
1025
1026 if (!priv->mux_drvdata)
1027 return 0;
1028 mux_config = priv->mux_drvdata;
1029
1030 /* Find GPIO chip */
1031 gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label);
1032 if (gpio) {
1033 dev_info(dev,
1034 "GPIO chip %s found, SMBus multiplexing enabled\n",
1035 mux_config->gpio_chip);
1036 } else {
1037 dev_err(dev,
1038 "GPIO chip %s not found, SMBus multiplexing disabled\n",
1039 mux_config->gpio_chip);
1040 return -ENODEV;
1041 }
1042
1043 /* Find absolute GPIO pin numbers */
1044 if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) {
1045 dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n",
1046 ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios);
1047 return -ENODEV;
1048 }
1049 for (i = 0; i < mux_config->n_gpios; i++)
1050 priv->mux_priv[i] = gpio->base + mux_config->gpios[i];
1051
1052 /* Prepare the platform data */
1053 memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
1054 gpio_data.parent = priv->adapter.nr;
1055 gpio_data.values = mux_config->values;
1056 gpio_data.n_values = mux_config->n_values;
1057 gpio_data.classes = mux_config->classes;
1058 gpio_data.gpios = priv->mux_priv;
1059 gpio_data.n_gpios = mux_config->n_gpios;
1060 gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
1061
1062 /* Register the mux device */
1063 priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
1064 priv->mux_priv[0], &gpio_data,
1065 sizeof(struct i2c_mux_gpio_platform_data));
1066 if (IS_ERR(priv->mux_pdev)) {
1067 err = PTR_ERR(priv->mux_pdev);
1068 priv->mux_pdev = NULL;
1069 dev_err(dev, "Failed to register i2c-mux-gpio device\n");
1070 return err;
1071 }
1072
1073 return 0;
1074}
1075
1076static void __devexit i801_del_mux(struct i801_priv *priv)
1077{
1078 if (priv->mux_pdev)
1079 platform_device_unregister(priv->mux_pdev);
1080}
1081
1082static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
1083{
1084 const struct dmi_system_id *id;
1085 const struct i801_mux_config *mux_config;
1086 unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
1087 int i;
1088
1089 id = dmi_first_match(mux_dmi_table);
1090 if (id) {
1091 /* Remove from branch classes from trunk */
1092 mux_config = id->driver_data;
1093 for (i = 0; i < mux_config->n_values; i++)
1094 class &= ~mux_config->classes[i];
1095
1096 /* Remember for later */
1097 priv->mux_drvdata = mux_config;
1098 }
1099
1100 return class;
1101}
1102#else
1103static inline int i801_add_mux(struct i801_priv *priv) { return 0; }
1104static inline void i801_del_mux(struct i801_priv *priv) { }
1105
1106static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
1107{
1108 return I2C_CLASS_HWMON | I2C_CLASS_SPD;
1109}
1110#endif
1111
903static int __devinit i801_probe(struct pci_dev *dev, 1112static int __devinit i801_probe(struct pci_dev *dev,
904 const struct pci_device_id *id) 1113 const struct pci_device_id *id)
905{ 1114{
@@ -913,7 +1122,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
913 1122
914 i2c_set_adapdata(&priv->adapter, priv); 1123 i2c_set_adapdata(&priv->adapter, priv);
915 priv->adapter.owner = THIS_MODULE; 1124 priv->adapter.owner = THIS_MODULE;
916 priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; 1125 priv->adapter.class = i801_get_adapter_class(priv);
917 priv->adapter.algo = &smbus_algorithm; 1126 priv->adapter.algo = &smbus_algorithm;
918 1127
919 priv->pci_dev = dev; 1128 priv->pci_dev = dev;
@@ -1033,6 +1242,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
1033 } 1242 }
1034 1243
1035 i801_probe_optional_slaves(priv); 1244 i801_probe_optional_slaves(priv);
1245 /* We ignore errors - multiplexing is optional */
1246 i801_add_mux(priv);
1036 1247
1037 pci_set_drvdata(dev, priv); 1248 pci_set_drvdata(dev, priv);
1038 1249
@@ -1052,6 +1263,7 @@ static void __devexit i801_remove(struct pci_dev *dev)
1052{ 1263{
1053 struct i801_priv *priv = pci_get_drvdata(dev); 1264 struct i801_priv *priv = pci_get_drvdata(dev);
1054 1265
1266 i801_del_mux(priv);
1055 i2c_del_adapter(&priv->adapter); 1267 i2c_del_adapter(&priv->adapter);
1056 pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); 1268 pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
1057 1269