Commit 5829e9b6 authored by Darren Hart's avatar Darren Hart Committed by Samuel Ortiz

mfd: lpc_sch: Accomodate partial population of the MFD devices

The current probe aborts if any of the 3 base address registers are
disabled. On a TunnelCreek system I am working on, this resulted in the
SMBIOS and GPIO devices being removed when it couldn't read the base
address for the watchdog timer.

This patch accommodates partial population of the lpc_sch_cells array and
only aborts if all the base address registers are disabled. A max size
array is allocated and the individual device cells are added to it after
their base addresses are successfully determined. This simplifies the
code a bit by removing the need for the separate tunnelcreek cells array
and combining some of the add/remove logic.

Cc: Grant Likely <grant.likely@secretlab.ca>,
Cc: Denis Turischev <denis@compulab.co.il>,
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarDarren Hart <dvhart@linux.intel.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent c3e9e6b6
...@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = { ...@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
.flags = IORESOURCE_IO, .flags = IORESOURCE_IO,
}; };
static struct resource gpio_sch_resource = { static struct resource gpio_sch_resource = {
.flags = IORESOURCE_IO, .flags = IORESOURCE_IO,
}; };
static struct mfd_cell lpc_sch_cells[] = { static struct resource wdt_sch_resource = {
{ .flags = IORESOURCE_IO,
};
static struct mfd_cell lpc_sch_cells[3];
static struct mfd_cell isch_smbus_cell = {
.name = "isch_smbus", .name = "isch_smbus",
.num_resources = 1, .num_resources = 1,
.resources = &smbus_sch_resource, .resources = &smbus_sch_resource,
}, };
{
static struct mfd_cell sch_gpio_cell = {
.name = "sch_gpio", .name = "sch_gpio",
.num_resources = 1, .num_resources = 1,
.resources = &gpio_sch_resource, .resources = &gpio_sch_resource,
},
};
static struct resource wdt_sch_resource = {
.flags = IORESOURCE_IO,
}; };
static struct mfd_cell tunnelcreek_cells[] = { static struct mfd_cell wdt_sch_cell = {
{
.name = "ie6xx_wdt", .name = "ie6xx_wdt",
.num_resources = 1, .num_resources = 1,
.resources = &wdt_sch_resource, .resources = &wdt_sch_resource,
},
}; };
static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
...@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev, ...@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
{ {
unsigned int base_addr_cfg; unsigned int base_addr_cfg;
unsigned short base_addr; unsigned short base_addr;
int i; int i, cells = 0;
int ret; int ret;
pci_read_config_dword(dev, SMBASE, &base_addr_cfg); pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
if (!(base_addr_cfg & (1 << 31))) { base_addr = 0;
dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n"); if (!(base_addr_cfg & (1 << 31)))
return -ENODEV; dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
} else
base_addr = (unsigned short)base_addr_cfg; base_addr = (unsigned short)base_addr_cfg;
if (base_addr == 0) {
dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
return -ENODEV;
}
if (base_addr == 0) {
dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
} else {
lpc_sch_cells[cells++] = isch_smbus_cell;
smbus_sch_resource.start = base_addr; smbus_sch_resource.start = base_addr;
smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
}
pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
if (!(base_addr_cfg & (1 << 31))) { base_addr = 0;
dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n"); if (!(base_addr_cfg & (1 << 31)))
return -ENODEV; dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
} else
base_addr = (unsigned short)base_addr_cfg; base_addr = (unsigned short)base_addr_cfg;
if (base_addr == 0) {
dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
return -ENODEV;
}
if (base_addr == 0) {
dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
} else {
lpc_sch_cells[cells++] = sch_gpio_cell;
gpio_sch_resource.start = base_addr; gpio_sch_resource.start = base_addr;
if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
else else
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
}
for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
lpc_sch_cells[i].id = id->device;
ret = mfd_add_devices(&dev->dev, 0,
lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL,
0, NULL);
if (ret)
goto out_dev;
if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
|| id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
if (!(base_addr_cfg & (1 << 31))) { base_addr = 0;
dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n"); if (!(base_addr_cfg & (1 << 31)))
ret = -ENODEV; dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
goto out_dev; else
}
base_addr = (unsigned short)base_addr_cfg; base_addr = (unsigned short)base_addr_cfg;
if (base_addr == 0) { if (base_addr == 0)
dev_err(&dev->dev, "I/O space for WDT uninitialized\n"); dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
ret = -ENODEV; else {
goto out_dev; lpc_sch_cells[cells++] = wdt_sch_cell;
}
wdt_sch_resource.start = base_addr; wdt_sch_resource.start = base_addr;
wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
}
}
for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++) if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
tunnelcreek_cells[i].id = id->device; dev_err(&dev->dev, "Cell count exceeds array size");
return -ENODEV;
}
ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, if (cells == 0) {
ARRAY_SIZE(tunnelcreek_cells), NULL, dev_err(&dev->dev, "All decode registers disabled.\n");
0, NULL); return -ENODEV;
} }
return ret; for (i = 0; i < cells; i++)
out_dev: lpc_sch_cells[i].id = id->device;
ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
if (ret)
mfd_remove_devices(&dev->dev); mfd_remove_devices(&dev->dev);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment