aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/mellanox/Kconfig1
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c614
-rw-r--r--drivers/platform/x86/mlx-platform.c231
-rw-r--r--include/linux/platform_data/mlxreg.h126
4 files changed, 635 insertions, 337 deletions
diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
index d73529203327..0fb2568716bb 100644
--- a/drivers/platform/mellanox/Kconfig
+++ b/drivers/platform/mellanox/Kconfig
@@ -16,6 +16,7 @@ if MELLANOX_PLATFORM
16 16
17config MLXREG_HOTPLUG 17config MLXREG_HOTPLUG
18 tristate "Mellanox platform hotplug driver support" 18 tristate "Mellanox platform hotplug driver support"
19 depends on REGMAP
19 depends on HWMON 20 depends on HWMON
20 depends on I2C 21 depends on I2C
21 ---help--- 22 ---help---
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index e4f7e8efd397..bcb564fd9f04 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -37,99 +37,97 @@
37#include <linux/hwmon-sysfs.h> 37#include <linux/hwmon-sysfs.h>
38#include <linux/i2c.h> 38#include <linux/i2c.h>
39#include <linux/interrupt.h> 39#include <linux/interrupt.h>
40#include <linux/io.h>
41#include <linux/module.h> 40#include <linux/module.h>
41#include <linux/of_device.h>
42#include <linux/platform_data/mlxreg.h> 42#include <linux/platform_data/mlxreg.h>
43#include <linux/platform_device.h> 43#include <linux/platform_device.h>
44#include <linux/spinlock.h> 44#include <linux/spinlock.h>
45#include <linux/regmap.h>
45#include <linux/workqueue.h> 46#include <linux/workqueue.h>
46 47
47/* Offset of event and mask registers from status register */ 48/* Offset of event and mask registers from status register. */
48#define MLXREG_HOTPLUG_EVENT_OFF 1 49#define MLXREG_HOTPLUG_EVENT_OFF 1
49#define MLXREG_HOTPLUG_MASK_OFF 2 50#define MLXREG_HOTPLUG_MASK_OFF 2
50#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 51#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
51 52
52#define MLXREG_HOTPLUG_ATTRS_NUM 8 53/* ASIC health parameters. */
54#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
55#define MLXREG_HOTPLUG_RST_CNTR 3
53 56
54/** 57#define MLXREG_HOTPLUG_ATTRS_MAX 24
55 * enum mlxreg_hotplug_attr_type - sysfs attributes for hotplug events:
56 * @MLXREG_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute;
57 * @MLXREG_HOTPLUG_ATTR_TYPE_PWR: power cable attribute;
58 * @MLXREG_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute;
59 */
60enum mlxreg_hotplug_attr_type {
61 MLXREG_HOTPLUG_ATTR_TYPE_PSU,
62 MLXREG_HOTPLUG_ATTR_TYPE_PWR,
63 MLXREG_HOTPLUG_ATTR_TYPE_FAN,
64};
65 58
66/** 59/**
67 * struct mlxreg_hotplug_priv_data - platform private data: 60 * struct mlxreg_hotplug_priv_data - platform private data:
68 * @irq: platform interrupt number; 61 * @irq: platform device interrupt number;
69 * @pdev: platform device; 62 * @pdev: platform device;
70 * @plat: platform data; 63 * @plat: platform data;
64 * @dwork: delayed work template;
65 * @lock: spin lock;
71 * @hwmon: hwmon device; 66 * @hwmon: hwmon device;
72 * @mlxreg_hotplug_attr: sysfs attributes array; 67 * @mlxreg_hotplug_attr: sysfs attributes array;
73 * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; 68 * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
74 * @group: sysfs attribute group; 69 * @group: sysfs attribute group;
75 * @groups: list of sysfs attribute group for hwmon registration; 70 * @groups: list of sysfs attribute group for hwmon registration;
76 * @dwork: delayed work template; 71 * @cell: location of top aggregation interrupt register;
77 * @lock: spin lock; 72 * @mask: top aggregation interrupt common mask;
78 * @aggr_cache: last value of aggregation register status; 73 * @aggr_cache: last value of aggregation register status;
79 * @psu_cache: last value of PSU register status;
80 * @pwr_cache: last value of power register status;
81 * @fan_cache: last value of FAN register status;
82 */ 74 */
83struct mlxreg_hotplug_priv_data { 75struct mlxreg_hotplug_priv_data {
84 int irq; 76 int irq;
77 struct device *dev;
85 struct platform_device *pdev; 78 struct platform_device *pdev;
86 struct mlxreg_hotplug_platform_data *plat; 79 struct mlxreg_hotplug_platform_data *plat;
80 struct regmap *regmap;
81 struct delayed_work dwork_irq;
82 struct delayed_work dwork;
83 spinlock_t lock; /* sync with interrupt */
87 struct device *hwmon; 84 struct device *hwmon;
88 struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_NUM + 1]; 85 struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
89 struct sensor_device_attribute_2 86 struct sensor_device_attribute_2
90 mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_NUM]; 87 mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
91 struct attribute_group group; 88 struct attribute_group group;
92 const struct attribute_group *groups[2]; 89 const struct attribute_group *groups[2];
93 struct delayed_work dwork; 90 u32 cell;
94 spinlock_t lock; 91 u32 mask;
95 u8 aggr_cache; 92 u32 aggr_cache;
96 u8 psu_cache; 93 bool after_probe;
97 u8 pwr_cache;
98 u8 fan_cache;
99}; 94};
100 95
101static int mlxreg_hotplug_device_create(struct device *dev, 96static int mlxreg_hotplug_device_create(struct device *dev,
102 struct mlxreg_hotplug_device *item) 97 struct mlxreg_core_data *data)
103{ 98{
104 item->adapter = i2c_get_adapter(item->nr); 99 data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
105 if (!item->adapter) { 100 if (!data->hpdev.adapter) {
106 dev_err(dev, "Failed to get adapter for bus %d\n", 101 dev_err(dev, "Failed to get adapter for bus %d\n",
107 item->nr); 102 data->hpdev.nr);
108 return -EFAULT; 103 return -EFAULT;
109 } 104 }
110 105
111 item->client = i2c_new_device(item->adapter, &item->brdinfo); 106 data->hpdev.client = i2c_new_device(data->hpdev.adapter,
112 if (!item->client) { 107 data->hpdev.brdinfo);
108 if (!data->hpdev.client) {
113 dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 109 dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
114 item->brdinfo.type, item->nr, item->brdinfo.addr); 110 data->hpdev.brdinfo->type, data->hpdev.nr,
115 i2c_put_adapter(item->adapter); 111 data->hpdev.brdinfo->addr);
116 item->adapter = NULL; 112
113 i2c_put_adapter(data->hpdev.adapter);
114 data->hpdev.adapter = NULL;
117 return -EFAULT; 115 return -EFAULT;
118 } 116 }
119 117
120 return 0; 118 return 0;
121} 119}
122 120
123static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item) 121static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
124{ 122{
125 if (item->client) { 123 if (data->hpdev.client) {
126 i2c_unregister_device(item->client); 124 i2c_unregister_device(data->hpdev.client);
127 item->client = NULL; 125 data->hpdev.client = NULL;
128 } 126 }
129 127
130 if (item->adapter) { 128 if (data->hpdev.adapter) {
131 i2c_put_adapter(item->adapter); 129 i2c_put_adapter(data->hpdev.adapter);
132 item->adapter = NULL; 130 data->hpdev.adapter = NULL;
133 } 131 }
134} 132}
135 133
@@ -137,41 +135,76 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
137 struct device_attribute *attr, 135 struct device_attribute *attr,
138 char *buf) 136 char *buf)
139{ 137{
140 struct platform_device *pdev = to_platform_device(dev); 138 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
141 struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); 139 struct mlxreg_core_hotplug_platform_data *pdata;
142 int index = to_sensor_dev_attr_2(attr)->index; 140 int index = to_sensor_dev_attr_2(attr)->index;
143 int nr = to_sensor_dev_attr_2(attr)->nr; 141 int nr = to_sensor_dev_attr_2(attr)->nr;
144 u8 reg_val = 0; 142 struct mlxreg_core_item *item;
145 143 struct mlxreg_core_data *data;
146 switch (nr) { 144 u32 regval;
147 case MLXREG_HOTPLUG_ATTR_TYPE_PSU: 145 int ret;
148 /* Bit = 0 : PSU is present. */ 146
149 reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); 147 pdata = dev_get_platdata(&priv->pdev->dev);
150 break; 148 item = pdata->items + nr;
151 149 data = item->data + index;
152 case MLXREG_HOTPLUG_ATTR_TYPE_PWR: 150
153 /* Bit = 1 : power cable is attached. */ 151 ret = regmap_read(priv->regmap, data->reg, &regval);
154 reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % 152 if (ret)
155 priv->plat->pwr_count)); 153 return ret;
156 break; 154
157 155 if (item->health) {
158 case MLXREG_HOTPLUG_ATTR_TYPE_FAN: 156 regval &= data->mask;
159 /* Bit = 0 : FAN is present. */ 157 } else {
160 reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % 158 /* Bit = 0 : functional if item->inversed is true. */
161 priv->plat->fan_count)); 159 if (item->inversed)
162 break; 160 regval = !(regval & data->mask);
161 else
162 regval = !!(regval & data->mask);
163 } 163 }
164 164
165 return sprintf(buf, "%u\n", reg_val); 165 return sprintf(buf, "%u\n", regval);
166} 166}
167 167
168#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] 168#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
169#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] 169#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
170
170static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) 171static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
171{ 172{
172 int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + 173 struct mlxreg_core_hotplug_platform_data *pdata;
173 priv->plat->fan_count; 174 struct mlxreg_core_item *item;
174 int i; 175 struct mlxreg_core_data *data;
176 int num_attrs = 0, id = 0, i, j;
177
178 pdata = dev_get_platdata(&priv->pdev->dev);
179 item = pdata->items;
180
181 /* Go over all kinds of items - psu, pwr, fan. */
182 for (i = 0; i < pdata->counter; i++, item++) {
183 num_attrs += item->count;
184 data = item->data;
185 /* Go over all units within the item. */
186 for (j = 0; j < item->count; j++, data++, id++) {
187 PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
188 PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
189 GFP_KERNEL,
190 data->label);
191
192 if (!PRIV_ATTR(id)->name) {
193 dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
194 id);
195 return -ENOMEM;
196 }
197
198 PRIV_DEV_ATTR(id).dev_attr.attr.name =
199 PRIV_ATTR(id)->name;
200 PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
201 PRIV_DEV_ATTR(id).dev_attr.show =
202 mlxreg_hotplug_attr_show;
203 PRIV_DEV_ATTR(id).nr = i;
204 PRIV_DEV_ATTR(id).index = j;
205 sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
206 }
207 }
175 208
176 priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * 209 priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
177 sizeof(struct attribute *), 210 sizeof(struct attribute *),
@@ -179,38 +212,6 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
179 if (!priv->group.attrs) 212 if (!priv->group.attrs)
180 return -ENOMEM; 213 return -ENOMEM;
181 214
182 for (i = 0; i < num_attrs; i++) {
183 PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr;
184
185 if (i < priv->plat->psu_count) {
186 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
187 GFP_KERNEL, "psu%u", i + 1);
188 PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PSU;
189 } else if (i < priv->plat->psu_count + priv->plat->pwr_count) {
190 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
191 GFP_KERNEL, "pwr%u", i %
192 priv->plat->pwr_count + 1);
193 PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PWR;
194 } else {
195 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
196 GFP_KERNEL, "fan%u", i %
197 priv->plat->fan_count + 1);
198 PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_FAN;
199 }
200
201 if (!PRIV_ATTR(i)->name) {
202 dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
203 i + 1);
204 return -ENOMEM;
205 }
206
207 PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name;
208 PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO;
209 PRIV_DEV_ATTR(i).dev_attr.show = mlxreg_hotplug_attr_show;
210 PRIV_DEV_ATTR(i).index = i;
211 sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr);
212 }
213
214 priv->group.attrs = priv->mlxreg_hotplug_attr; 215 priv->group.attrs = priv->mlxreg_hotplug_attr;
215 priv->groups[0] = &priv->group; 216 priv->groups[0] = &priv->group;
216 priv->groups[1] = NULL; 217 priv->groups[1] = NULL;
@@ -218,20 +219,13 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
218 return 0; 219 return 0;
219} 220}
220 221
221static inline void 222static void
222mlxreg_hotplug_work_helper(struct device *dev, 223mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
223 struct mlxreg_hotplug_device *item, u8 is_inverse, 224 struct mlxreg_core_item *item)
224 u16 offset, u8 mask, u8 *cache)
225{ 225{
226 u8 val, asserted; 226 struct mlxreg_core_data *data;
227 int bit; 227 u32 asserted, regval, bit;
228 228 int ret;
229 /* Mask event. */
230 outb(0, offset + MLXREG_HOTPLUG_MASK_OFF);
231 /* Read status. */
232 val = inb(offset) & mask;
233 asserted = *cache ^ val;
234 *cache = val;
235 229
236 /* 230 /*
237 * Validate if item related to received signal type is valid. 231 * Validate if item related to received signal type is valid.
@@ -241,86 +235,177 @@ mlxreg_hotplug_work_helper(struct device *dev,
241 * signals from other devices if any. 235 * signals from other devices if any.
242 */ 236 */
243 if (unlikely(!item)) { 237 if (unlikely(!item)) {
244 dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", 238 dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
245 offset, mask); 239 item->reg, item->mask);
240
246 return; 241 return;
247 } 242 }
248 243
244 /* Mask event. */
245 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
246 0);
247 if (ret)
248 goto out;
249
250 /* Read status. */
251 ret = regmap_read(priv->regmap, item->reg, &regval);
252 if (ret)
253 goto out;
254
255 /* Set asserted bits and save last status. */
256 regval &= item->mask;
257 asserted = item->cache ^ regval;
258 item->cache = regval;
259
249 for_each_set_bit(bit, (unsigned long *)&asserted, 8) { 260 for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
250 if (val & BIT(bit)) { 261 data = item->data + bit;
251 if (is_inverse) 262 if (regval & BIT(bit)) {
252 mlxreg_hotplug_device_destroy(item + bit); 263 if (item->inversed)
264 mlxreg_hotplug_device_destroy(data);
253 else 265 else
254 mlxreg_hotplug_device_create(dev, item + bit); 266 mlxreg_hotplug_device_create(priv->dev, data);
255 } else { 267 } else {
256 if (is_inverse) 268 if (item->inversed)
257 mlxreg_hotplug_device_create(dev, item + bit); 269 mlxreg_hotplug_device_create(priv->dev, data);
258 else 270 else
259 mlxreg_hotplug_device_destroy(item + bit); 271 mlxreg_hotplug_device_destroy(data);
260 } 272 }
261 } 273 }
262 274
263 /* Acknowledge event. */ 275 /* Acknowledge event. */
264 outb(0, offset + MLXREG_HOTPLUG_EVENT_OFF); 276 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
277 0);
278 if (ret)
279 goto out;
280
265 /* Unmask event. */ 281 /* Unmask event. */
266 outb(mask, offset + MLXREG_HOTPLUG_MASK_OFF); 282 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
283 item->mask);
284
285 out:
286 if (ret)
287 dev_err(priv->dev, "Failed to complete workqueue.\n");
288}
289
290static void
291mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
292 struct mlxreg_core_item *item)
293{
294 struct mlxreg_core_data *data = item->data;
295 u32 regval;
296 int i, ret;
297
298 for (i = 0; i < item->count; i++, data++) {
299 /* Mask event. */
300 ret = regmap_write(priv->regmap, data->reg +
301 MLXREG_HOTPLUG_MASK_OFF, 0);
302 if (ret)
303 goto out;
304
305 /* Read status. */
306 ret = regmap_read(priv->regmap, data->reg, &regval);
307 if (ret)
308 goto out;
309
310 regval &= data->mask;
311 item->cache = regval;
312 if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
313 if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
314 !priv->after_probe) {
315 mlxreg_hotplug_device_create(priv->dev, data);
316 data->attached = true;
317 }
318 } else {
319 if (data->attached) {
320 mlxreg_hotplug_device_destroy(data);
321 data->attached = false;
322 data->health_cntr = 0;
323 }
324 }
325
326 /* Acknowledge event. */
327 ret = regmap_write(priv->regmap, data->reg +
328 MLXREG_HOTPLUG_EVENT_OFF, 0);
329 if (ret)
330 goto out;
331
332 /* Unmask event. */
333 ret = regmap_write(priv->regmap, data->reg +
334 MLXREG_HOTPLUG_MASK_OFF, data->mask);
335 if (ret)
336 goto out;
337 }
338
339 out:
340 if (ret)
341 dev_err(priv->dev, "Failed to complete workqueue.\n");
267} 342}
268 343
269/* 344/*
270 * mlxreg_hotplug_work_handler - performs traversing of CPLD interrupt 345 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
271 * registers according to the below hierarchy schema: 346 * registers according to the below hierarchy schema:
272 * 347 *
273 * Aggregation registers (status/mask) 348 * Aggregation registers (status/mask)
274 * PSU registers: *---* 349 * PSU registers: *---*
275 * *-----------------* | | 350 * *-----------------* | |
276 * |status/event/mask|----->| * | 351 * |status/event/mask|-----> | * |
277 * *-----------------* | | 352 * *-----------------* | |
278 * Power registers: | | 353 * Power registers: | |
279 * *-----------------* | | 354 * *-----------------* | |
280 * |status/event/mask|----->| * |---> CPU 355 * |status/event/mask|-----> | * |
281 * *-----------------* | | 356 * *-----------------* | |
282 * FAN registers: 357 * FAN registers: | |--> CPU
283 * *-----------------* | | 358 * *-----------------* | |
284 * |status/event/mask|----->| * | 359 * |status/event/mask|-----> | * |
285 * *-----------------* | | 360 * *-----------------* | |
286 * *---* 361 * ASIC registers: | |
362 * *-----------------* | |
363 * |status/event/mask|-----> | * |
364 * *-----------------* | |
365 * *---*
366 *
287 * In case some system changed are detected: FAN in/out, PSU in/out, power 367 * In case some system changed are detected: FAN in/out, PSU in/out, power
288 * cable attached/detached, relevant device is created or destroyed. 368 * cable attached/detached, ASIC health good/bad, relevant device is created
369 * or destroyed.
289 */ 370 */
290static void mlxreg_hotplug_work_handler(struct work_struct *work) 371static void mlxreg_hotplug_work_handler(struct work_struct *work)
291{ 372{
292 struct mlxreg_hotplug_priv_data *priv = container_of(work, 373 struct mlxreg_core_hotplug_platform_data *pdata;
293 struct mlxreg_hotplug_priv_data, dwork.work); 374 struct mlxreg_hotplug_priv_data *priv;
294 u8 val, aggr_asserted; 375 struct mlxreg_core_item *item;
376 u32 regval, aggr_asserted;
295 unsigned long flags; 377 unsigned long flags;
378 int i, ret;
379
380 priv = container_of(work, struct mlxreg_hotplug_priv_data,
381 dwork_irq.work);
382 pdata = dev_get_platdata(&priv->pdev->dev);
383 item = pdata->items;
296 384
297 /* Mask aggregation event. */ 385 /* Mask aggregation event. */
298 outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF); 386 ret = regmap_write(priv->regmap, pdata->cell +
387 MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
388 if (ret < 0)
389 goto out;
390
299 /* Read aggregation status. */ 391 /* Read aggregation status. */
300 val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; 392 ret = regmap_read(priv->regmap, pdata->cell, &regval);
301 aggr_asserted = priv->aggr_cache ^ val; 393 if (ret)
302 priv->aggr_cache = val; 394 goto out;
303 395
304 /* Handle PSU configuration changes. */ 396 regval &= pdata->mask;
305 if (aggr_asserted & priv->plat->top_aggr_psu_mask) 397 aggr_asserted = priv->aggr_cache ^ regval;
306 mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, 398 priv->aggr_cache = regval;
307 1, priv->plat->psu_reg_offset, 399
308 priv->plat->psu_mask, 400 /* Handle topology and health configuration changes. */
309 &priv->psu_cache); 401 for (i = 0; i < pdata->counter; i++, item++) {
310 402 if (aggr_asserted & item->aggr_mask) {
311 /* Handle power cable configuration changes. */ 403 if (item->health)
312 if (aggr_asserted & priv->plat->top_aggr_pwr_mask) 404 mlxreg_hotplug_health_work_helper(priv, item);
313 mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, 405 else
314 0, priv->plat->pwr_reg_offset, 406 mlxreg_hotplug_work_helper(priv, item);
315 priv->plat->pwr_mask, 407 }
316 &priv->pwr_cache); 408 }
317
318 /* Handle FAN configuration changes. */
319 if (aggr_asserted & priv->plat->top_aggr_fan_mask)
320 mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan,
321 1, priv->plat->fan_reg_offset,
322 priv->plat->fan_mask,
323 &priv->fan_cache);
324 409
325 if (aggr_asserted) { 410 if (aggr_asserted) {
326 spin_lock_irqsave(&priv->lock, flags); 411 spin_lock_irqsave(&priv->lock, flags);
@@ -335,8 +420,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
335 * validates that no new signals have been received during 420 * validates that no new signals have been received during
336 * masking. 421 * masking.
337 */ 422 */
338 cancel_delayed_work(&priv->dwork); 423 cancel_delayed_work(&priv->dwork_irq);
339 schedule_delayed_work(&priv->dwork, 0); 424 schedule_delayed_work(&priv->dwork_irq, 0);
340 425
341 spin_unlock_irqrestore(&priv->lock, flags); 426 spin_unlock_irqrestore(&priv->lock, flags);
342 427
@@ -344,92 +429,119 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
344 } 429 }
345 430
346 /* Unmask aggregation event (no need acknowledge). */ 431 /* Unmask aggregation event (no need acknowledge). */
347 outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + 432 ret = regmap_write(priv->regmap, pdata->cell +
348 MLXREG_HOTPLUG_AGGR_MASK_OFF); 433 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
434
435 out:
436 if (ret)
437 dev_err(priv->dev, "Failed to complete workqueue.\n");
349} 438}
350 439
351static void mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) 440static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
352{ 441{
353 /* Clear psu presense event. */ 442 struct mlxreg_core_hotplug_platform_data *pdata;
354 outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); 443 struct mlxreg_core_item *item;
355 /* Set psu initial status as mask and unmask psu event. */ 444 int i, ret;
356 priv->psu_cache = priv->plat->psu_mask; 445
357 outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + 446 pdata = dev_get_platdata(&priv->pdev->dev);
358 MLXREG_HOTPLUG_MASK_OFF); 447 item = pdata->items;
359 448
360 /* Clear power cable event. */ 449 for (i = 0; i < pdata->counter; i++, item++) {
361 outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); 450 /* Clear group presense event. */
362 /* Keep power initial status as zero and unmask power event. */ 451 ret = regmap_write(priv->regmap, item->reg +
363 outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + 452 MLXREG_HOTPLUG_EVENT_OFF, 0);
364 MLXREG_HOTPLUG_MASK_OFF); 453 if (ret)
365 454 goto out;
366 /* Clear fan presense event. */ 455
367 outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF); 456 /* Set group initial status as mask and unmask group event. */
368 /* Set fan initial status as mask and unmask fan event. */ 457 if (item->inversed) {
369 priv->fan_cache = priv->plat->fan_mask; 458 item->cache = item->mask;
370 outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + 459 ret = regmap_write(priv->regmap, item->reg +
371 MLXREG_HOTPLUG_MASK_OFF); 460 MLXREG_HOTPLUG_MASK_OFF,
461 item->mask);
462 if (ret)
463 goto out;
464 }
465 }
372 466
373 /* Keep aggregation initial status as zero and unmask events. */ 467 /* Keep aggregation initial status as zero and unmask events. */
374 outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + 468 ret = regmap_write(priv->regmap, pdata->cell +
375 MLXREG_HOTPLUG_AGGR_MASK_OFF); 469 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
470 if (ret)
471 goto out;
472
473 /* Keep low aggregation initial status as zero and unmask events. */
474 if (pdata->cell_low) {
475 ret = regmap_write(priv->regmap, pdata->cell_low +
476 MLXREG_HOTPLUG_AGGR_MASK_OFF,
477 pdata->mask_low);
478 if (ret)
479 goto out;
480 }
376 481
377 /* Invoke work handler for initializing hot plug devices setting. */ 482 /* Invoke work handler for initializing hot plug devices setting. */
378 mlxreg_hotplug_work_handler(&priv->dwork.work); 483 mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
379 484
485 out:
486 if (ret)
487 dev_err(priv->dev, "Failed to set interrupts.\n");
380 enable_irq(priv->irq); 488 enable_irq(priv->irq);
489 return ret;
381} 490}
382 491
383static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) 492static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
384{ 493{
385 int i; 494 struct mlxreg_core_hotplug_platform_data *pdata;
495 struct mlxreg_core_item *item;
496 struct mlxreg_core_data *data;
497 int count, i, j;
386 498
499 pdata = dev_get_platdata(&priv->pdev->dev);
500 item = pdata->items;
387 disable_irq(priv->irq); 501 disable_irq(priv->irq);
388 cancel_delayed_work_sync(&priv->dwork); 502 cancel_delayed_work_sync(&priv->dwork_irq);
389
390 /* Mask aggregation event. */
391 outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF);
392
393 /* Mask psu presense event. */
394 outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
395 /* Clear psu presense event. */
396 outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
397
398 /* Mask power cable event. */
399 outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
400 /* Clear power cable event. */
401 outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
402
403 /* Mask fan presense event. */
404 outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
405 /* Clear fan presense event. */
406 outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
407
408 /* Remove all the attached devices. */
409 for (i = 0; i < priv->plat->psu_count; i++)
410 mlxreg_hotplug_device_destroy(priv->plat->psu + i);
411 503
412 for (i = 0; i < priv->plat->pwr_count; i++) 504 /* Mask low aggregation event, if defined. */
413 mlxreg_hotplug_device_destroy(priv->plat->pwr + i); 505 if (pdata->cell_low)
506 regmap_write(priv->regmap, pdata->cell_low +
507 MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
414 508
415 for (i = 0; i < priv->plat->fan_count; i++) 509 /* Mask aggregation event. */
416 mlxreg_hotplug_device_destroy(priv->plat->fan + i); 510 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
511 0);
512
513 /* Clear topology configurations. */
514 for (i = 0; i < pdata->counter; i++, item++) {
515 data = item->data;
516 /* Mask group presense event. */
517 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
518 0);
519 /* Clear group presense event. */
520 regmap_write(priv->regmap, data->reg +
521 MLXREG_HOTPLUG_EVENT_OFF, 0);
522
523 /* Remove all the attached devices in group. */
524 count = item->count;
525 for (j = 0; j < count; j++, data++)
526 mlxreg_hotplug_device_destroy(data);
527 }
417} 528}
418 529
419static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) 530static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
420{ 531{
421 struct mlxreg_hotplug_priv_data *priv = 532 struct mlxreg_hotplug_priv_data *priv;
422 (struct mlxreg_hotplug_priv_data *)dev; 533
534 priv = (struct mlxreg_hotplug_priv_data *)dev;
423 535
424 /* Schedule work task for immediate execution.*/ 536 /* Schedule work task for immediate execution.*/
425 schedule_delayed_work(&priv->dwork, 0); 537 schedule_delayed_work(&priv->dwork_irq, 0);
426 538
427 return IRQ_HANDLED; 539 return IRQ_HANDLED;
428} 540}
429 541
430static int mlxreg_hotplug_probe(struct platform_device *pdev) 542static int mlxreg_hotplug_probe(struct platform_device *pdev)
431{ 543{
432 struct mlxreg_hotplug_platform_data *pdata; 544 struct mlxreg_core_hotplug_platform_data *pdata;
433 struct mlxreg_hotplug_priv_data *priv; 545 struct mlxreg_hotplug_priv_data *priv;
434 int err; 546 int err;
435 547
@@ -443,31 +555,42 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
443 if (!priv) 555 if (!priv)
444 return -ENOMEM; 556 return -ENOMEM;
445 557
446 priv->pdev = pdev; 558 if (pdata->irq) {
447 priv->plat = pdata; 559 priv->irq = pdata->irq;
448 560 } else {
449 priv->irq = platform_get_irq(pdev, 0); 561 priv->irq = platform_get_irq(pdev, 0);
450 if (priv->irq < 0) { 562 if (priv->irq < 0) {
451 dev_err(&pdev->dev, "Failed to get platform irq: %d\n", 563 dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
452 priv->irq); 564 priv->irq);
453 return priv->irq; 565 return priv->irq;
566 }
454 } 567 }
455 568
569 priv->regmap = pdata->regmap;
570 priv->dev = pdev->dev.parent;
571 priv->pdev = pdev;
572
456 err = devm_request_irq(&pdev->dev, priv->irq, 573 err = devm_request_irq(&pdev->dev, priv->irq,
457 mlxreg_hotplug_irq_handler, 0, pdev->name, 574 mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
458 priv); 575 | IRQF_SHARED, "mlxreg-hotplug", priv);
459 if (err) { 576 if (err) {
460 dev_err(&pdev->dev, "Failed to request irq: %d\n", err); 577 dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
461 return err; 578 return err;
462 } 579 }
463 disable_irq(priv->irq);
464 580
465 INIT_DELAYED_WORK(&priv->dwork, mlxreg_hotplug_work_handler); 581 disable_irq(priv->irq);
466 spin_lock_init(&priv->lock); 582 spin_lock_init(&priv->lock);
583 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
584 /* Perform initial interrupts setup. */
585 mlxreg_hotplug_set_irq(priv);
586
587 priv->after_probe = true;
588 dev_set_drvdata(&pdev->dev, priv);
467 589
468 err = mlxreg_hotplug_attr_init(priv); 590 err = mlxreg_hotplug_attr_init(priv);
469 if (err) { 591 if (err) {
470 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); 592 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
593 err);
471 return err; 594 return err;
472 } 595 }
473 596
@@ -479,17 +602,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
479 return PTR_ERR(priv->hwmon); 602 return PTR_ERR(priv->hwmon);
480 } 603 }
481 604
482 platform_set_drvdata(pdev, priv);
483
484 /* Perform initial interrupts setup. */
485 mlxreg_hotplug_set_irq(priv);
486
487 return 0; 605 return 0;
488} 606}
489 607
490static int mlxreg_hotplug_remove(struct platform_device *pdev) 608static int mlxreg_hotplug_remove(struct platform_device *pdev)
491{ 609{
492 struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev); 610 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
493 611
494 /* Clean interrupts setup. */ 612 /* Clean interrupts setup. */
495 mlxreg_hotplug_unset_irq(priv); 613 mlxreg_hotplug_unset_irq(priv);
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 56017143d6a9..03c9e7a76d89 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -35,20 +35,22 @@
35#include <linux/dmi.h> 35#include <linux/dmi.h>
36#include <linux/i2c.h> 36#include <linux/i2c.h>
37#include <linux/i2c-mux.h> 37#include <linux/i2c-mux.h>
38#include <linux/io.h>
38#include <linux/module.h> 39#include <linux/module.h>
39#include <linux/platform_device.h> 40#include <linux/platform_device.h>
40#include <linux/platform_data/i2c-mux-reg.h> 41#include <linux/platform_data/i2c-mux-reg.h>
41#include <linux/platform_data/mlxreg.h> 42#include <linux/platform_data/mlxreg.h>
43#include <linux/regmap.h>
42 44
43#define MLX_PLAT_DEVICE_NAME "mlxplat" 45#define MLX_PLAT_DEVICE_NAME "mlxplat"
44 46
45/* LPC bus IO offsets */ 47/* LPC bus IO offsets */
46#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 48#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
47#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 49#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
48#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a 50#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
49#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 51#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
50#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 52#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
51#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 53#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
52#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 54#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
53#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 55#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
54#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda 56#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -138,78 +140,194 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
138}; 140};
139 141
140/* Platform hotplug devices */ 142/* Platform hotplug devices */
141static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = { 143static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
142 { 144 {
143 .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, 145 I2C_BOARD_INFO("24c02", 0x51),
144 .nr = 10,
145 }, 146 },
146 { 147 {
147 .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, 148 I2C_BOARD_INFO("24c02", 0x50),
148 .nr = 10,
149 }, 149 },
150}; 150};
151 151
152static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = { 152static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
153 { 153 {
154 .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, 154 I2C_BOARD_INFO("dps460", 0x59),
155 .nr = 10,
156 }, 155 },
157 { 156 {
158 .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, 157 I2C_BOARD_INFO("dps460", 0x58),
159 .nr = 10,
160 }, 158 },
161}; 159};
162 160
163static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = { 161static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
164 { 162 {
165 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 163 I2C_BOARD_INFO("24c32", 0x50),
166 .nr = 11,
167 }, 164 },
168 { 165 {
169 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 166 I2C_BOARD_INFO("24c32", 0x50),
170 .nr = 12,
171 }, 167 },
172 { 168 {
173 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 169 I2C_BOARD_INFO("24c32", 0x50),
174 .nr = 13,
175 }, 170 },
176 { 171 {
177 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 172 I2C_BOARD_INFO("24c32", 0x50),
178 .nr = 14,
179 }, 173 },
180}; 174};
181 175
182/* Platform hotplug default data */ 176/* Platform hotplug default data */
177static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
178 {
179 .label = "psu1",
180 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
181 .mask = BIT(0),
182 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
183 .hpdev.nr = 10,
184 },
185 {
186 .label = "psu2",
187 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
188 .mask = BIT(1),
189 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
190 .hpdev.nr = 10,
191 },
192};
193
194static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
195 {
196 .label = "pwr1",
197 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
198 .mask = BIT(0),
199 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
200 .hpdev.nr = 10,
201 },
202 {
203 .label = "pwr2",
204 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
205 .mask = BIT(1),
206 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
207 .hpdev.nr = 10,
208 },
209};
210
211static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
212 {
213 .label = "fan1",
214 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
215 .mask = BIT(0),
216 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
217 .hpdev.nr = 11,
218 },
219 {
220 .label = "fan2",
221 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
222 .mask = BIT(1),
223 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
224 .hpdev.nr = 12,
225 },
226 {
227 .label = "fan3",
228 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
229 .mask = BIT(2),
230 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
231 .hpdev.nr = 13,
232 },
233 {
234 .label = "fan4",
235 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
236 .mask = BIT(3),
237 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
238 .hpdev.nr = 14,
239 },
240};
241
242static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
243 {
244 .data = mlxplat_mlxcpld_default_psu_items_data,
245 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
246 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
247 .mask = MLXPLAT_CPLD_PSU_MASK,
248 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
249 .inversed = 1,
250 .health = false,
251 },
252 {
253 .data = mlxplat_mlxcpld_default_pwr_items_data,
254 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
255 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
256 .mask = MLXPLAT_CPLD_PWR_MASK,
257 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
258 .inversed = 0,
259 .health = false,
260 },
261 {
262 .data = mlxplat_mlxcpld_default_fan_items_data,
263 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
264 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
265 .mask = MLXPLAT_CPLD_FAN_MASK,
266 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
267 .inversed = 1,
268 .health = false,
269 },
270};
271
183static 272static
184struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_default_data = { 273struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
185 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 274 .items = mlxplat_mlxcpld_default_items,
186 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 275 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
187 .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 276 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
188 .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, 277 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
189 .psu_mask = MLXPLAT_CPLD_PSU_MASK,
190 .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
191 .psu = mlxplat_mlxcpld_psu,
192 .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
193 .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
194 .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
195 .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
196 .pwr = mlxplat_mlxcpld_pwr,
197 .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
198 .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
199 .fan_mask = MLXPLAT_CPLD_FAN_MASK,
200 .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
201 .fan = mlxplat_mlxcpld_fan,
202}; 278};
203 279
204/* Platform hotplug MSN21xx system family data */ 280/* Platform hotplug MSN21xx system family data */
281static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
282 {
283 .data = mlxplat_mlxcpld_default_pwr_items_data,
284 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
285 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
286 .mask = MLXPLAT_CPLD_PWR_MASK,
287 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
288 .inversed = 0,
289 .health = false,
290 },
291};
292
205static 293static
206struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 294struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
207 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 295 .items = mlxplat_mlxcpld_msn21xx_items,
208 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 296 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
209 .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 297 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
210 .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 298 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
211 .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 299};
212 .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 300
301struct mlxplat_mlxcpld_regmap_context {
302 void __iomem *base;
303};
304
305static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
306
307static int
308mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
309{
310 struct mlxplat_mlxcpld_regmap_context *ctx = context;
311
312 *val = ioread8(ctx->base + reg);
313 return 0;
314}
315
316static int
317mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
318{
319 struct mlxplat_mlxcpld_regmap_context *ctx = context;
320
321 iowrite8(val, ctx->base + reg);
322 return 0;
323}
324
325static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
326 .reg_bits = 8,
327 .val_bits = 8,
328 .max_register = 255,
329 .reg_read = mlxplat_mlxcpld_reg_read,
330 .reg_write = mlxplat_mlxcpld_reg_write,
213}; 331};
214 332
215static struct resource mlxplat_mlxcpld_resources[] = { 333static struct resource mlxplat_mlxcpld_resources[] = {
@@ -217,7 +335,7 @@ static struct resource mlxplat_mlxcpld_resources[] = {
217}; 335};
218 336
219static struct platform_device *mlxplat_dev; 337static struct platform_device *mlxplat_dev;
220static struct mlxreg_hotplug_platform_data *mlxplat_hotplug; 338static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
221 339
222static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 340static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
223{ 341{
@@ -328,6 +446,21 @@ static int __init mlxplat_init(void)
328 } 446 }
329 } 447 }
330 448
449 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
450 mlxplat_lpc_resources[1].start, 1);
451 if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) {
452 err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base);
453 goto fail_platform_mux_register;
454 }
455
456 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
457 &mlxplat_mlxcpld_regmap_ctx,
458 &mlxplat_mlxcpld_regmap_config);
459 if (IS_ERR(mlxplat_hotplug->regmap)) {
460 err = PTR_ERR(mlxplat_hotplug->regmap);
461 goto fail_platform_mux_register;
462 }
463
331 priv->pdev_hotplug = platform_device_register_resndata( 464 priv->pdev_hotplug = platform_device_register_resndata(
332 &mlxplat_dev->dev, "mlxreg-hotplug", 465 &mlxplat_dev->dev, "mlxreg-hotplug",
333 PLATFORM_DEVID_NONE, 466 PLATFORM_DEVID_NONE,
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index ffbcb7886c62..fcdc707eab99 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -34,8 +34,11 @@
34#ifndef __LINUX_PLATFORM_DATA_MLXREG_H 34#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
35#define __LINUX_PLATFORM_DATA_MLXREG_H 35#define __LINUX_PLATFORM_DATA_MLXREG_H
36 36
37#define MLXREG_CORE_LABEL_MAX_SIZE 32
38
37/** 39/**
38 * struct mlxreg_hotplug_device - I2C device data: 40 * struct mlxreg_hotplug_device - I2C device data:
41 *
39 * @adapter: I2C device adapter; 42 * @adapter: I2C device adapter;
40 * @client: I2C device client; 43 * @client: I2C device client;
41 * @brdinfo: device board information; 44 * @brdinfo: device board information;
@@ -47,52 +50,95 @@
47struct mlxreg_hotplug_device { 50struct mlxreg_hotplug_device {
48 struct i2c_adapter *adapter; 51 struct i2c_adapter *adapter;
49 struct i2c_client *client; 52 struct i2c_client *client;
50 struct i2c_board_info brdinfo; 53 struct i2c_board_info *brdinfo;
51 int nr; 54 int nr;
52}; 55};
53 56
54/** 57/**
55 * struct mlxreg_hotplug_platform_data - device platform data: 58 * struct mlxreg_core_data - attributes control data:
56 * @top_aggr_offset: offset of top aggregation interrupt register; 59 *
57 * @top_aggr_mask: top aggregation interrupt common mask; 60 * @label: attribute label;
58 * @top_aggr_psu_mask: top aggregation interrupt PSU mask; 61 * @label: attribute register offset;
59 * @psu_reg_offset: offset of PSU interrupt register; 62 * @reg: attribute register;
60 * @psu_mask: PSU interrupt mask; 63 * @mask: attribute access mask;
61 * @psu_count: number of equipped replaceable PSUs; 64 * @mode: access mode;
62 * @psu: pointer to PSU devices data array; 65 * @bit: attribute effective bit;
63 * @top_aggr_pwr_mask: top aggregation interrupt power mask; 66 * @np - pointer to node platform associated with attribute;
64 * @pwr_reg_offset: offset of power interrupt register 67 * @hpdev - hotplug device data;
65 * @pwr_mask: power interrupt mask; 68 * @health_cntr: dynamic device health indication counter;
66 * @pwr_count: number of power sources; 69 * @attached: true if device has been attached after good health indication;
67 * @pwr: pointer to power devices data array; 70 */
68 * @top_aggr_fan_mask: top aggregation interrupt FAN mask; 71struct mlxreg_core_data {
69 * @fan_reg_offset: offset of FAN interrupt register; 72 char label[MLXREG_CORE_LABEL_MAX_SIZE];
70 * @fan_mask: FAN interrupt mask; 73 u32 reg;
71 * @fan_count: number of equipped replaceable FANs; 74 u32 mask;
72 * @fan: pointer to FAN devices data array; 75 u32 bit;
76 umode_t mode;
77 struct device_node *np;
78 struct mlxreg_hotplug_device hpdev;
79 u8 health_cntr;
80 bool attached;
81};
82
83/**
84 * struct mlxreg_core_item - same type components controlled by the driver:
85 *
86 * @data: component data;
87 * @aggr_mask: group aggregation mask;
88 * @reg: group interrupt status register;
89 * @mask: group interrupt mask;
90 * @cache: last status value for elements fro the same group;
91 * @count: number of available elements in the group;
92 * @ind: element's index inside the group;
93 * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
94 * @health: true if device has health indication, false in other case;
95 */
96struct mlxreg_core_item {
97 struct mlxreg_core_data *data;
98 u32 aggr_mask;
99 u32 reg;
100 u32 mask;
101 u32 cache;
102 u8 count;
103 u8 ind;
104 u8 inversed;
105 u8 health;
106};
107
108/**
109 * struct mlxreg_core_platform_data - platform data:
110 *
111 * @led_data: led private data;
112 * @regmap: register map of parent device;
113 * @counter: number of led instances;
114 */
115struct mlxreg_core_platform_data {
116 struct mlxreg_core_data *data;
117 void *regmap;
118 int counter;
119};
120
121/**
122 * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
73 * 123 *
74 * Structure represents board platform data, related to system hotplug events, 124 * @items: same type components with the hotplug capability;
75 * like FAN, PSU, power cable insertion and removing. This data provides the 125 * @irq: platform interrupt number;
76 * number of hot-pluggable devices and hardware description for event handling. 126 * @regmap: register map of parent device;
127 * @counter: number of the components with the hotplug capability;
128 * @cell: location of top aggregation interrupt register;
129 * @mask: top aggregation interrupt common mask;
130 * @cell_low: location of low aggregation interrupt register;
131 * @mask_low: low aggregation interrupt common mask;
77 */ 132 */
78struct mlxreg_hotplug_platform_data { 133struct mlxreg_core_hotplug_platform_data {
79 u16 top_aggr_offset; 134 struct mlxreg_core_item *items;
80 u8 top_aggr_mask; 135 int irq;
81 u8 top_aggr_psu_mask; 136 void *regmap;
82 u16 psu_reg_offset; 137 int counter;
83 u8 psu_mask; 138 u32 cell;
84 u8 psu_count; 139 u32 mask;
85 struct mlxreg_hotplug_device *psu; 140 u32 cell_low;
86 u8 top_aggr_pwr_mask; 141 u32 mask_low;
87 u16 pwr_reg_offset;
88 u8 pwr_mask;
89 u8 pwr_count;
90 struct mlxreg_hotplug_device *pwr;
91 u8 top_aggr_fan_mask;
92 u16 fan_reg_offset;
93 u8 fan_mask;
94 u8 fan_count;
95 struct mlxreg_hotplug_device *fan;
96}; 142};
97 143
98#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ 144#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */