diff options
Diffstat (limited to 'drivers/mfd/lpc_ich.c')
-rw-r--r-- | drivers/mfd/lpc_ich.c | 144 |
1 files changed, 111 insertions, 33 deletions
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index d9d930302e9..9f12f91d629 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -50,6 +50,7 @@ * document number TBD : Panther Point * document number TBD : Lynx Point * document number TBD : Lynx Point-LP + * document number TBD : Wellsburg */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -75,8 +76,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 +87,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 */ @@ -194,6 +206,7 @@ enum lpc_chipsets { LPC_PPT, /* Panther Point */ LPC_LPT, /* Lynx Point */ LPC_LPT_LP, /* Lynx Point-LP */ + LPC_WBG, /* Wellsburg */ }; struct lpc_ich_info lpc_chipset_info[] = { @@ -474,6 +487,10 @@ struct lpc_ich_info lpc_chipset_info[] = { .name = "Lynx Point_LP", .iTCO_version = 2, }, + [LPC_WBG] = { + .name = "Wellsburg", + .iTCO_version = 2, + }, }; /* @@ -655,45 +672,82 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP}, { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP}, { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG}, { 0, }, /* End of list */ }; 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 +775,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 +785,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 +811,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 +822,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 +838,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 +852,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 +884,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 +901,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 +912,36 @@ 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 = devm_kzalloc(&dev->dev, + sizeof(struct lpc_ich_priv), GFP_KERNEL); + 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 +952,7 @@ 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); return -ENODEV; } @@ -886,6 +963,7 @@ static void lpc_ich_remove(struct pci_dev *dev) { mfd_remove_devices(&dev->dev); lpc_ich_restore_config_space(dev); + pci_set_drvdata(dev, NULL); } static struct pci_driver lpc_ich_driver = { |