aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2012-07-23 11:34:15 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-09-14 03:52:13 -0400
commit4f600ada70beeb1dfe08e11e871bf31015aa0a3d (patch)
tree7ab75ca987a49e661c6e33c052e59d56bc83a219
parentcdabc1c88a12e9fc2a49f2a54ce9be470398d8a9 (diff)
gpio: gpio-ich: Share ownership of GPIO groups
The ICH chips have their GPIO pins organized in 2 or 3 independent groups of 32 GPIO pins. It can happen that the ACPI BIOS wants to make use of pins in one group, preventing the OS to access these. This does not prevent the OS from accessing the other group(s). This is the case for example on my Asus Z8NA-D6 board. The ACPI BIOS wants to control GPIO 18 (group 1), while I (the OS) need to control GPIO 52 and 53 (group 2) for SMBus multiplexing. So instead of checking for ACPI resource conflict on the whole I/O range, check on a per-group basis, and consider it a success if at least one of the groups is available for the OS to use. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Peter Tyser <ptyser@xes-inc.com> Cc: Aaron Sierra <asierra@xes-inc.com> Cc: Grant Likely <grant.likely@secretlab.ca> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/gpio/gpio-ich.c79
-rw-r--r--drivers/mfd/lpc_ich.c29
-rw-r--r--include/linux/mfd/lpc_ich.h1
3 files changed, 97 insertions, 12 deletions
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index b7c06517403d..d4d617966696 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -49,6 +49,10 @@ static const u8 ichx_regs[3][3] = {
49 {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ 49 {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
50}; 50};
51 51
52static const u8 ichx_reglen[3] = {
53 0x30, 0x10, 0x10,
54};
55
52#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) 56#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
53#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) 57#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
54 58
@@ -75,6 +79,7 @@ static struct {
75 struct resource *pm_base; /* Power Mangagment IO base */ 79 struct resource *pm_base; /* Power Mangagment IO base */
76 struct ichx_desc *desc; /* Pointer to chipset-specific description */ 80 struct ichx_desc *desc; /* Pointer to chipset-specific description */
77 u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ 81 u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
82 u8 use_gpio; /* Which GPIO groups are usable */
78} ichx_priv; 83} ichx_priv;
79 84
80static int modparam_gpiobase = -1; /* dynamic */ 85static int modparam_gpiobase = -1; /* dynamic */
@@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr)
123 return data & (1 << bit) ? 1 : 0; 128 return data & (1 << bit) ? 1 : 0;
124} 129}
125 130
131static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
132{
133 return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO;
134}
135
126static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) 136static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
127{ 137{
138 if (!ichx_gpio_check_available(gpio, nr))
139 return -ENXIO;
140
128 /* 141 /*
129 * Try setting pin as an input and verify it worked since many pins 142 * Try setting pin as an input and verify it worked since many pins
130 * are output-only. 143 * are output-only.
@@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
138static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, 151static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
139 int val) 152 int val)
140{ 153{
154 if (!ichx_gpio_check_available(gpio, nr))
155 return -ENXIO;
156
141 /* Set GPIO output value. */ 157 /* Set GPIO output value. */
142 ichx_write_bit(GPIO_LVL, nr, val, 0); 158 ichx_write_bit(GPIO_LVL, nr, val, 0);
143 159
@@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
153 169
154static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) 170static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
155{ 171{
172 if (!ichx_gpio_check_available(chip, nr))
173 return -ENXIO;
174
156 return ichx_read_bit(GPIO_LVL, nr); 175 return ichx_read_bit(GPIO_LVL, nr);
157} 176}
158 177
@@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
161 unsigned long flags; 180 unsigned long flags;
162 u32 data; 181 u32 data;
163 182
183 if (!ichx_gpio_check_available(chip, nr))
184 return -ENXIO;
185
164 /* 186 /*
165 * GPI 0 - 15 need to be read from the power management registers on 187 * GPI 0 - 15 need to be read from the power management registers on
166 * a ICH6/3100 bridge. 188 * a ICH6/3100 bridge.
@@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = {
291 .ngpio = 76, 313 .ngpio = 76,
292}; 314};
293 315
316static int __devinit ichx_gpio_request_regions(struct resource *res_base,
317 const char *name, u8 use_gpio)
318{
319 int i;
320
321 if (!res_base || !res_base->start || !res_base->end)
322 return -ENODEV;
323
324 for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
325 if (!(use_gpio & (1 << i)))
326 continue;
327 if (!request_region(res_base->start + ichx_regs[0][i],
328 ichx_reglen[i], name))
329 goto request_err;
330 }
331 return 0;
332
333request_err:
334 /* Clean up: release already requested regions, if any */
335 for (i--; i >= 0; i--) {
336 if (!(use_gpio & (1 << i)))
337 continue;
338 release_region(res_base->start + ichx_regs[0][i],
339 ichx_reglen[i]);
340 }
341 return -EBUSY;
342}
343
344static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
345{
346 int i;
347
348 for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
349 if (!(use_gpio & (1 << i)))
350 continue;
351 release_region(res_base->start + ichx_regs[0][i],
352 ichx_reglen[i]);
353 }
354}
355
294static int __devinit ichx_gpio_probe(struct platform_device *pdev) 356static int __devinit ichx_gpio_probe(struct platform_device *pdev)
295{ 357{
296 struct resource *res_base, *res_pm; 358 struct resource *res_base, *res_pm;
@@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev)
329 } 391 }
330 392
331 res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); 393 res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
332 if (!res_base || !res_base->start || !res_base->end) 394 ichx_priv.use_gpio = ich_info->use_gpio;
333 return -ENODEV; 395 err = ichx_gpio_request_regions(res_base, pdev->name,
334 396 ichx_priv.use_gpio);
335 if (!request_region(res_base->start, resource_size(res_base), 397 if (err)
336 pdev->name)) 398 return err;
337 return -EBUSY;
338 399
339 ichx_priv.gpio_base = res_base; 400 ichx_priv.gpio_base = res_base;
340 401
@@ -374,8 +435,7 @@ init:
374 return 0; 435 return 0;
375 436
376add_err: 437add_err:
377 release_region(ichx_priv.gpio_base->start, 438 ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
378 resource_size(ichx_priv.gpio_base));
379 if (ichx_priv.pm_base) 439 if (ichx_priv.pm_base)
380 release_region(ichx_priv.pm_base->start, 440 release_region(ichx_priv.pm_base->start,
381 resource_size(ichx_priv.pm_base)); 441 resource_size(ichx_priv.pm_base));
@@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev)
393 return err; 453 return err;
394 } 454 }
395 455
396 release_region(ichx_priv.gpio_base->start, 456 ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
397 resource_size(ichx_priv.gpio_base));
398 if (ichx_priv.pm_base) 457 if (ichx_priv.pm_base)
399 release_region(ichx_priv.pm_base->start, 458 release_region(ichx_priv.pm_base->start,
400 resource_size(ichx_priv.pm_base)); 459 resource_size(ichx_priv.pm_base));
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index 092ad4b44b6d..d142622a3fb0 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -683,6 +683,30 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell,
683 cell->pdata_size = sizeof(struct lpc_ich_info); 683 cell->pdata_size = sizeof(struct lpc_ich_info);
684} 684}
685 685
686/*
687 * We don't check for resource conflict globally. There are 2 or 3 independent
688 * GPIO groups and it's enough to have access to one of these to instantiate
689 * the device.
690 */
691static int __devinit lpc_ich_check_conflict_gpio(struct resource *res)
692{
693 int ret;
694 u8 use_gpio = 0;
695
696 if (resource_size(res) >= 0x50 &&
697 !acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3"))
698 use_gpio |= 1 << 2;
699
700 if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2"))
701 use_gpio |= 1 << 1;
702
703 ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1");
704 if (!ret)
705 use_gpio |= 1 << 0;
706
707 return use_gpio ? use_gpio : ret;
708}
709
686static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, 710static int __devinit lpc_ich_init_gpio(struct pci_dev *dev,
687 const struct pci_device_id *id) 711 const struct pci_device_id *id)
688{ 712{
@@ -740,12 +764,13 @@ gpe0_done:
740 break; 764 break;
741 } 765 }
742 766
743 ret = acpi_check_resource_conflict(res); 767 ret = lpc_ich_check_conflict_gpio(res);
744 if (ret) { 768 if (ret < 0) {
745 /* this isn't necessarily fatal for the GPIO */ 769 /* this isn't necessarily fatal for the GPIO */
746 acpi_conflict = true; 770 acpi_conflict = true;
747 goto gpio_done; 771 goto gpio_done;
748 } 772 }
773 lpc_chipset_info[id->driver_data].use_gpio = ret;
749 lpc_ich_enable_gpio_space(dev); 774 lpc_ich_enable_gpio_space(dev);
750 775
751 lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); 776 lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
diff --git a/include/linux/mfd/lpc_ich.h b/include/linux/mfd/lpc_ich.h
index fec5256c3f5d..3e1df644c407 100644
--- a/include/linux/mfd/lpc_ich.h
+++ b/include/linux/mfd/lpc_ich.h
@@ -43,6 +43,7 @@ struct lpc_ich_info {
43 char name[32]; 43 char name[32];
44 unsigned int iTCO_version; 44 unsigned int iTCO_version;
45 unsigned int gpio_version; 45 unsigned int gpio_version;
46 u8 use_gpio;
46}; 47};
47 48
48#endif 49#endif