aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/lpc_sch.c
diff options
context:
space:
mode:
authorDarren Hart <dvhart@linux.intel.com>2013-02-08 18:20:36 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2013-02-13 18:26:45 -0500
commit5829e9b64e657560e840dc0ecfee177cb002cd69 (patch)
tree282ef54b0edf1c087abe14374ac69132cfdbc612 /drivers/mfd/lpc_sch.c
parentc3e9e6b67db23ae678550f861b5679880481cfa3 (diff)
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: Darren Hart <dvhart@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/lpc_sch.c')
-rw-r--r--drivers/mfd/lpc_sch.c147
1 files changed, 71 insertions, 76 deletions
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index 5624fcbba69b..8cc6aac27cb2 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
45 .flags = IORESOURCE_IO, 45 .flags = IORESOURCE_IO,
46}; 46};
47 47
48
49static struct resource gpio_sch_resource = { 48static struct resource gpio_sch_resource = {
50 .flags = IORESOURCE_IO, 49 .flags = IORESOURCE_IO,
51}; 50};
52 51
53static struct mfd_cell lpc_sch_cells[] = {
54 {
55 .name = "isch_smbus",
56 .num_resources = 1,
57 .resources = &smbus_sch_resource,
58 },
59 {
60 .name = "sch_gpio",
61 .num_resources = 1,
62 .resources = &gpio_sch_resource,
63 },
64};
65
66static struct resource wdt_sch_resource = { 52static struct resource wdt_sch_resource = {
67 .flags = IORESOURCE_IO, 53 .flags = IORESOURCE_IO,
68}; 54};
69 55
70static struct mfd_cell tunnelcreek_cells[] = { 56static struct mfd_cell lpc_sch_cells[3];
71 { 57
72 .name = "ie6xx_wdt", 58static struct mfd_cell isch_smbus_cell = {
73 .num_resources = 1, 59 .name = "isch_smbus",
74 .resources = &wdt_sch_resource, 60 .num_resources = 1,
75 }, 61 .resources = &smbus_sch_resource,
62};
63
64static struct mfd_cell sch_gpio_cell = {
65 .name = "sch_gpio",
66 .num_resources = 1,
67 .resources = &gpio_sch_resource,
68};
69
70static struct mfd_cell wdt_sch_cell = {
71 .name = "ie6xx_wdt",
72 .num_resources = 1,
73 .resources = &wdt_sch_resource,
76}; 74};
77 75
78static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { 76static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
88{ 86{
89 unsigned int base_addr_cfg; 87 unsigned int base_addr_cfg;
90 unsigned short base_addr; 88 unsigned short base_addr;
91 int i; 89 int i, cells = 0;
92 int ret; 90 int ret;
93 91
94 pci_read_config_dword(dev, SMBASE, &base_addr_cfg); 92 pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
95 if (!(base_addr_cfg & (1 << 31))) { 93 base_addr = 0;
96 dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n"); 94 if (!(base_addr_cfg & (1 << 31)))
97 return -ENODEV; 95 dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
98 } 96 else
99 base_addr = (unsigned short)base_addr_cfg; 97 base_addr = (unsigned short)base_addr_cfg;
100 if (base_addr == 0) {
101 dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
102 return -ENODEV;
103 }
104
105 smbus_sch_resource.start = base_addr;
106 smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
107 98
108 pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
109 if (!(base_addr_cfg & (1 << 31))) {
110 dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
111 return -ENODEV;
112 }
113 base_addr = (unsigned short)base_addr_cfg;
114 if (base_addr == 0) { 99 if (base_addr == 0) {
115 dev_err(&dev->dev, "I/O space for GPIO uninitialized\n"); 100 dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
116 return -ENODEV; 101 } else {
102 lpc_sch_cells[cells++] = isch_smbus_cell;
103 smbus_sch_resource.start = base_addr;
104 smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
117 } 105 }
118 106
119 gpio_sch_resource.start = base_addr; 107 pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
120 108 base_addr = 0;
121 if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) 109 if (!(base_addr_cfg & (1 << 31)))
122 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; 110 dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
123 else 111 else
124 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; 112 base_addr = (unsigned short)base_addr_cfg;
125
126 for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
127 lpc_sch_cells[i].id = id->device;
128 113
129 ret = mfd_add_devices(&dev->dev, 0, 114 if (base_addr == 0) {
130 lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 115 dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
131 0, NULL); 116 } else {
132 if (ret) 117 lpc_sch_cells[cells++] = sch_gpio_cell;
133 goto out_dev; 118 gpio_sch_resource.start = base_addr;
119 if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
120 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
121 else
122 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
123 }
134 124
135 if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC 125 if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
136 || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { 126 || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
137 pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); 127 pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
138 if (!(base_addr_cfg & (1 << 31))) { 128 base_addr = 0;
139 dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n"); 129 if (!(base_addr_cfg & (1 << 31)))
140 ret = -ENODEV; 130 dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
141 goto out_dev; 131 else
132 base_addr = (unsigned short)base_addr_cfg;
133 if (base_addr == 0)
134 dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
135 else {
136 lpc_sch_cells[cells++] = wdt_sch_cell;
137 wdt_sch_resource.start = base_addr;
138 wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
142 } 139 }
143 base_addr = (unsigned short)base_addr_cfg; 140 }
144 if (base_addr == 0) {
145 dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
146 ret = -ENODEV;
147 goto out_dev;
148 }
149
150 wdt_sch_resource.start = base_addr;
151 wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
152 141
153 for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++) 142 if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
154 tunnelcreek_cells[i].id = id->device; 143 dev_err(&dev->dev, "Cell count exceeds array size");
144 return -ENODEV;
145 }
155 146
156 ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, 147 if (cells == 0) {
157 ARRAY_SIZE(tunnelcreek_cells), NULL, 148 dev_err(&dev->dev, "All decode registers disabled.\n");
158 0, NULL); 149 return -ENODEV;
159 } 150 }
160 151
161 return ret; 152 for (i = 0; i < cells; i++)
162out_dev: 153 lpc_sch_cells[i].id = id->device;
163 mfd_remove_devices(&dev->dev); 154
155 ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
156 if (ret)
157 mfd_remove_devices(&dev->dev);
158
164 return ret; 159 return ret;
165} 160}
166 161