aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2014-09-02 06:45:19 -0400
committerLee Jones <lee.jones@linaro.org>2014-09-26 03:15:57 -0400
commitb24512c860244716fa8ca74faff2ff617c465515 (patch)
tree1cc314590e334b2812ee9d6a869b38a87e8c415c /drivers/mfd
parentf69a7cf74d5536faa180437581be2a9c0aad1bb1 (diff)
mfd: lpc_sch: Reduce duplicate code and improve manageability
This patch refactors the driver to use helper functions instead of copy'n'pasted pieces of code. It also introduces an additional struct to hold a chipset info. The chipset info will be used to store features that are supported by specific processor or chipset. LPC_SCH supports SMBUS, GPIO and WDT features. As this code base might expand further to support more processors, this implementation will help to keep code base clean and manageable. The patch is partially based on the work done by Chang Rebecca Swee Fun. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Tested-by: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/lpc_sch.c181
1 files changed, 99 insertions, 82 deletions
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index 4ee755034f3b..bde070a3a3c0 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -40,120 +40,137 @@
40#define WDTBASE 0x84 40#define WDTBASE 0x84
41#define WDT_IO_SIZE 64 41#define WDT_IO_SIZE 64
42 42
43static struct resource smbus_sch_resource = { 43enum sch_chipsets {
44 .flags = IORESOURCE_IO, 44 LPC_SCH = 0, /* Intel Poulsbo SCH */
45 LPC_ITC, /* Intel Tunnel Creek */
46 LPC_CENTERTON, /* Intel Centerton */
45}; 47};
46 48
47static struct resource gpio_sch_resource = { 49struct lpc_sch_info {
48 .flags = IORESOURCE_IO, 50 unsigned int io_size_smbus;
51 unsigned int io_size_gpio;
52 unsigned int io_size_wdt;
49}; 53};
50 54
51static struct resource wdt_sch_resource = { 55static struct lpc_sch_info sch_chipset_info[] = {
52 .flags = IORESOURCE_IO, 56 [LPC_SCH] = {
53}; 57 .io_size_smbus = SMBUS_IO_SIZE,
54 58 .io_size_gpio = GPIO_IO_SIZE,
55static struct mfd_cell lpc_sch_cells[3]; 59 },
56 60 [LPC_ITC] = {
57static struct mfd_cell isch_smbus_cell = { 61 .io_size_smbus = SMBUS_IO_SIZE,
58 .name = "isch_smbus", 62 .io_size_gpio = GPIO_IO_SIZE,
59 .num_resources = 1, 63 .io_size_wdt = WDT_IO_SIZE,
60 .resources = &smbus_sch_resource, 64 },
61 .ignore_resource_conflicts = true, 65 [LPC_CENTERTON] = {
62}; 66 .io_size_smbus = SMBUS_IO_SIZE,
63 67 .io_size_gpio = GPIO_IO_SIZE_CENTERTON,
64static struct mfd_cell sch_gpio_cell = { 68 .io_size_wdt = WDT_IO_SIZE,
65 .name = "sch_gpio", 69 },
66 .num_resources = 1,
67 .resources = &gpio_sch_resource,
68 .ignore_resource_conflicts = true,
69};
70
71static struct mfd_cell wdt_sch_cell = {
72 .name = "ie6xx_wdt",
73 .num_resources = 1,
74 .resources = &wdt_sch_resource,
75 .ignore_resource_conflicts = true,
76}; 70};
77 71
78static const struct pci_device_id lpc_sch_ids[] = { 72static const struct pci_device_id lpc_sch_ids[] = {
79 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, 73 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC), LPC_SCH },
80 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, 74 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC), LPC_ITC },
81 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) }, 75 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB), LPC_CENTERTON },
82 { 0, } 76 { 0, }
83}; 77};
84MODULE_DEVICE_TABLE(pci, lpc_sch_ids); 78MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
85 79
86static int lpc_sch_probe(struct pci_dev *dev, 80#define LPC_NO_RESOURCE 1
87 const struct pci_device_id *id) 81#define LPC_SKIP_RESOURCE 2
82
83static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name,
84 struct resource *res, int size)
88{ 85{
89 unsigned int base_addr_cfg; 86 unsigned int base_addr_cfg;
90 unsigned short base_addr; 87 unsigned short base_addr;
91 int i, cells = 0;
92 int ret;
93 88
94 pci_read_config_dword(dev, SMBASE, &base_addr_cfg); 89 if (size == 0)
90 return LPC_NO_RESOURCE;
91
92 pci_read_config_dword(pdev, where, &base_addr_cfg);
95 base_addr = 0; 93 base_addr = 0;
96 if (!(base_addr_cfg & (1 << 31))) 94 if (!(base_addr_cfg & (1 << 31)))
97 dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n"); 95 dev_warn(&pdev->dev, "Decode of the %s I/O range disabled\n",
96 name);
98 else 97 else
99 base_addr = (unsigned short)base_addr_cfg; 98 base_addr = (unsigned short)base_addr_cfg;
100 99
101 if (base_addr == 0) { 100 if (base_addr == 0) {
102 dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n"); 101 dev_warn(&pdev->dev, "I/O space for %s uninitialized\n", name);
103 } else { 102 return LPC_SKIP_RESOURCE;
104 lpc_sch_cells[cells++] = isch_smbus_cell;
105 smbus_sch_resource.start = base_addr;
106 smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
107 } 103 }
108 104
109 pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); 105 res->start = base_addr;
110 base_addr = 0; 106 res->end = base_addr + size - 1;
111 if (!(base_addr_cfg & (1 << 31))) 107 res->flags = IORESOURCE_IO;
112 dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
113 else
114 base_addr = (unsigned short)base_addr_cfg;
115 108
116 if (base_addr == 0) { 109 return 0;
117 dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n"); 110}
118 } else {
119 lpc_sch_cells[cells++] = sch_gpio_cell;
120 gpio_sch_resource.start = base_addr;
121 if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
122 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
123 else
124 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
125 }
126 111
127 if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC 112static int lpc_sch_populate_cell(struct pci_dev *pdev, int where,
128 || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { 113 const char *name, int size, int id,
129 pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); 114 struct mfd_cell *cell)
130 base_addr = 0; 115{
131 if (!(base_addr_cfg & (1 << 31))) 116 struct resource *res;
132 dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n"); 117 int ret;
133 else
134 base_addr = (unsigned short)base_addr_cfg;
135 if (base_addr == 0)
136 dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
137 else {
138 lpc_sch_cells[cells++] = wdt_sch_cell;
139 wdt_sch_resource.start = base_addr;
140 wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
141 }
142 }
143 118
144 if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) { 119 res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL);
145 dev_err(&dev->dev, "Cell count exceeds array size"); 120 if (!res)
146 return -ENODEV; 121 return -ENOMEM;
147 } 122
123 ret = lpc_sch_get_io(pdev, where, name, res, size);
124 if (ret)
125 return ret;
126
127 memset(cell, 0, sizeof(*cell));
128
129 cell->name = name;
130 cell->resources = res;
131 cell->num_resources = 1;
132 cell->ignore_resource_conflicts = true;
133 cell->id = id;
134
135 return 0;
136}
137
138static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
139{
140 struct mfd_cell lpc_sch_cells[3];
141 struct lpc_sch_info *info = &sch_chipset_info[id->driver_data];
142 unsigned int cells = 0;
143 int ret;
144
145 ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus",
146 info->io_size_smbus,
147 id->device, &lpc_sch_cells[cells]);
148 if (ret < 0)
149 return ret;
150 if (ret == 0)
151 cells++;
152
153 ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio",
154 info->io_size_gpio,
155 id->device, &lpc_sch_cells[cells]);
156 if (ret < 0)
157 return ret;
158 if (ret == 0)
159 cells++;
160
161 ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt",
162 info->io_size_wdt,
163 id->device, &lpc_sch_cells[cells]);
164 if (ret < 0)
165 return ret;
166 if (ret == 0)
167 cells++;
148 168
149 if (cells == 0) { 169 if (cells == 0) {
150 dev_err(&dev->dev, "All decode registers disabled.\n"); 170 dev_err(&dev->dev, "All decode registers disabled.\n");
151 return -ENODEV; 171 return -ENODEV;
152 } 172 }
153 173
154 for (i = 0; i < cells; i++)
155 lpc_sch_cells[i].id = id->device;
156
157 ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL); 174 ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
158 if (ret) 175 if (ret)
159 mfd_remove_devices(&dev->dev); 176 mfd_remove_devices(&dev->dev);