diff options
Diffstat (limited to 'drivers/mfd/lpc_ich.c')
-rw-r--r-- | drivers/mfd/lpc_ich.c | 109 |
1 files changed, 76 insertions, 33 deletions
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index d9d930302e9..a0cfdf98074 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -75,8 +75,10 @@ #define ACPIBASE_GCS_OFF 0x3410 #define ACPIBASE_GCS_END 0x3414 -#define GPIOBASE 0x48 -#define GPIOCTRL 0x4C +#define GPIOBASE_ICH0 0x58 +#define GPIOCTRL_ICH0 0x5C +#define GPIOBASE_ICH6 0x48 +#define GPIOCTRL_ICH6 0x4C #define RCBABASE 0xf0 @@ -84,8 +86,17 @@ #define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i) #define wdt_res(b, i) (&wdt_ich_res[(b) + (i)]) -static int lpc_ich_acpi_save = -1; -static int lpc_ich_gpio_save = -1; +struct lpc_ich_cfg { + int base; + int ctrl; + int save; +}; + +struct lpc_ich_priv { + int chipset; + struct lpc_ich_cfg acpi; + struct lpc_ich_cfg gpio; +}; static struct resource wdt_ich_res[] = { /* ACPI - TCO */ @@ -661,39 +672,44 @@ MODULE_DEVICE_TABLE(pci, lpc_ich_ids); static void lpc_ich_restore_config_space(struct pci_dev *dev) { - if (lpc_ich_acpi_save >= 0) { - pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save); - lpc_ich_acpi_save = -1; + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + + if (priv->acpi.save >= 0) { + pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save); + priv->acpi.save = -1; } - if (lpc_ich_gpio_save >= 0) { - pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save); - lpc_ich_gpio_save = -1; + if (priv->gpio.save >= 0) { + pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save); + priv->gpio.save = -1; } } static void lpc_ich_enable_acpi_space(struct pci_dev *dev) { + struct lpc_ich_priv *priv = pci_get_drvdata(dev); u8 reg_save; - pci_read_config_byte(dev, ACPICTRL, ®_save); - pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10); - lpc_ich_acpi_save = reg_save; + pci_read_config_byte(dev, priv->acpi.ctrl, ®_save); + pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10); + priv->acpi.save = reg_save; } static void lpc_ich_enable_gpio_space(struct pci_dev *dev) { + struct lpc_ich_priv *priv = pci_get_drvdata(dev); u8 reg_save; - pci_read_config_byte(dev, GPIOCTRL, ®_save); - pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10); - lpc_ich_gpio_save = reg_save; + pci_read_config_byte(dev, priv->gpio.ctrl, ®_save); + pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10); + priv->gpio.save = reg_save; } -static void lpc_ich_finalize_cell(struct mfd_cell *cell, - const struct pci_device_id *id) +static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell) { - cell->platform_data = &lpc_chipset_info[id->driver_data]; + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + + cell->platform_data = &lpc_chipset_info[priv->chipset]; cell->pdata_size = sizeof(struct lpc_ich_info); } @@ -721,9 +737,9 @@ static int lpc_ich_check_conflict_gpio(struct resource *res) return use_gpio ? use_gpio : ret; } -static int lpc_ich_init_gpio(struct pci_dev *dev, - const struct pci_device_id *id) +static int lpc_ich_init_gpio(struct pci_dev *dev) { + struct lpc_ich_priv *priv = pci_get_drvdata(dev); u32 base_addr_cfg; u32 base_addr; int ret; @@ -731,7 +747,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev, struct resource *res; /* Setup power management base register */ - pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); + pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); @@ -757,7 +773,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev, gpe0_done: /* Setup GPIO base register */ - pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); + pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n"); @@ -768,7 +784,7 @@ gpe0_done: /* Older devices provide fewer GPIO and have a smaller resource size. */ res = &gpio_ich_res[ICH_RES_GPIO]; res->start = base_addr; - switch (lpc_chipset_info[id->driver_data].gpio_version) { + switch (lpc_chipset_info[priv->chipset].gpio_version) { case ICH_V5_GPIO: case ICH_V10CORP_GPIO: res->end = res->start + 128 - 1; @@ -784,10 +800,10 @@ gpe0_done: acpi_conflict = true; goto gpio_done; } - lpc_chipset_info[id->driver_data].use_gpio = ret; + lpc_chipset_info[priv->chipset].use_gpio = ret; lpc_ich_enable_gpio_space(dev); - lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); + lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]); ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO], 1, NULL, 0, NULL); @@ -798,16 +814,16 @@ gpio_done: return ret; } -static int lpc_ich_init_wdt(struct pci_dev *dev, - const struct pci_device_id *id) +static int lpc_ich_init_wdt(struct pci_dev *dev) { + struct lpc_ich_priv *priv = pci_get_drvdata(dev); u32 base_addr_cfg; u32 base_addr; int ret; struct resource *res; /* Setup power management base register */ - pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg); + pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); @@ -830,7 +846,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev, * we have to read RCBA from PCI Config space 0xf0 and use * it as base. GCS = RCBA + ICH6_GCS(0x3410). */ - if (lpc_chipset_info[id->driver_data].iTCO_version == 1) { + if (lpc_chipset_info[priv->chipset].iTCO_version == 1) { /* Don't register iomem for TCO ver 1 */ lpc_ich_cells[LPC_WDT].num_resources--; } else { @@ -847,7 +863,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev, res->end = base_addr + ACPIBASE_GCS_END; } - lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id); + lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]); ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT], 1, NULL, 0, NULL); @@ -858,14 +874,35 @@ wdt_done: static int lpc_ich_probe(struct pci_dev *dev, const struct pci_device_id *id) { + struct lpc_ich_priv *priv; int ret; bool cell_added = false; - ret = lpc_ich_init_wdt(dev, id); + priv = kmalloc(GFP_KERNEL, sizeof(struct lpc_ich_priv)); + if (!priv) + return -ENOMEM; + + priv->chipset = id->driver_data; + priv->acpi.save = -1; + priv->acpi.base = ACPIBASE; + priv->acpi.ctrl = ACPICTRL; + + priv->gpio.save = -1; + if (priv->chipset <= LPC_ICH5) { + priv->gpio.base = GPIOBASE_ICH0; + priv->gpio.ctrl = GPIOCTRL_ICH0; + } else { + priv->gpio.base = GPIOBASE_ICH6; + priv->gpio.ctrl = GPIOCTRL_ICH6; + } + + pci_set_drvdata(dev, priv); + + ret = lpc_ich_init_wdt(dev); if (!ret) cell_added = true; - ret = lpc_ich_init_gpio(dev, id); + ret = lpc_ich_init_gpio(dev); if (!ret) cell_added = true; @@ -876,6 +913,8 @@ static int lpc_ich_probe(struct pci_dev *dev, if (!cell_added) { dev_warn(&dev->dev, "No MFD cells added\n"); lpc_ich_restore_config_space(dev); + pci_set_drvdata(dev, NULL); + kfree(priv); return -ENODEV; } @@ -884,8 +923,12 @@ static int lpc_ich_probe(struct pci_dev *dev, static void lpc_ich_remove(struct pci_dev *dev) { + void *priv = pci_get_drvdata(dev); + mfd_remove_devices(&dev->dev); lpc_ich_restore_config_space(dev); + pci_set_drvdata(dev, NULL); + kfree(priv); } static struct pci_driver lpc_ich_driver = { |