diff options
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 214 |
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 | ||
168 | struct 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 | |||
161 | struct i801_priv { | 177 | struct 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 | ||
180 | static struct pci_driver i801_driver; | 202 | static struct pci_driver i801_driver; |
@@ -900,6 +922,193 @@ static void __init input_apanel_init(void) {} | |||
900 | static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {} | 922 | static 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 | ||
926 | static 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 | |||
935 | static 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 | |||
944 | static 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 | |||
1011 | static 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 */ | ||
1018 | static 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 | |||
1076 | static void __devexit i801_del_mux(struct i801_priv *priv) | ||
1077 | { | ||
1078 | if (priv->mux_pdev) | ||
1079 | platform_device_unregister(priv->mux_pdev); | ||
1080 | } | ||
1081 | |||
1082 | static 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 | ||
1103 | static inline int i801_add_mux(struct i801_priv *priv) { return 0; } | ||
1104 | static inline void i801_del_mux(struct i801_priv *priv) { } | ||
1105 | |||
1106 | static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) | ||
1107 | { | ||
1108 | return I2C_CLASS_HWMON | I2C_CLASS_SPD; | ||
1109 | } | ||
1110 | #endif | ||
1111 | |||
903 | static int __devinit i801_probe(struct pci_dev *dev, | 1112 | static 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 | ||