Blame view

drivers/mfd/sta2x11-mfd.c 15.5 KB
450515395   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
35bdd2909   Alessandro Rubini   mfd: Add driver f...
2
  /*
cf090914d   Paul Gortmaker   mfd: sta2x11: Dro...
3
4
   * STA2x11 mfd for GPIO, SCTL and APBREG
   *
35bdd2909   Alessandro Rubini   mfd: Add driver f...
5
   * Copyright (c) 2009-2011 Wind River Systems, Inc.
b73df6986   Davide Ciminaghi   mfd: sta2x11-mfd:...
6
   * Copyright (c) 2011 ST Microelectronics (Alessandro Rubini, Davide Ciminaghi)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
7
8
9
   */
  
  #include <linux/kernel.h>
cf090914d   Paul Gortmaker   mfd: sta2x11: Dro...
10
11
  #include <linux/init.h>
  #include <linux/export.h>
35bdd2909   Alessandro Rubini   mfd: Add driver f...
12
13
14
15
16
17
18
19
  #include <linux/spinlock.h>
  #include <linux/errno.h>
  #include <linux/device.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/io.h>
  #include <linux/ioport.h>
  #include <linux/pci.h>
35bdd2909   Alessandro Rubini   mfd: Add driver f...
20
21
22
23
  #include <linux/seq_file.h>
  #include <linux/platform_device.h>
  #include <linux/mfd/core.h>
  #include <linux/mfd/sta2x11-mfd.h>
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
24
  #include <linux/regmap.h>
35bdd2909   Alessandro Rubini   mfd: Add driver f...
25
26
  
  #include <asm/sta2x11.h>
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
27
28
29
30
31
32
  static inline int __reg_within_range(unsigned int r,
  				     unsigned int start,
  				     unsigned int end)
  {
  	return ((r >= start) && (r <= end));
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
33
34
35
  /* This describes STA2X11 MFD chip for us, we may have several */
  struct sta2x11_mfd {
  	struct sta2x11_instance *instance;
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
36
  	struct regmap *regmap[sta2x11_n_mfd_plat_devs];
e885ba298   Davide Ciminaghi   mfd: sta2x11-mfd:...
37
  	spinlock_t lock[sta2x11_n_mfd_plat_devs];
35bdd2909   Alessandro Rubini   mfd: Add driver f...
38
  	struct list_head list;
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
39
  	void __iomem *regs[sta2x11_n_mfd_plat_devs];
35bdd2909   Alessandro Rubini   mfd: Add driver f...
40
41
42
43
44
45
46
47
48
49
50
  };
  
  static LIST_HEAD(sta2x11_mfd_list);
  
  /* Three functions to act on the list */
  static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev)
  {
  	struct sta2x11_instance *instance;
  	struct sta2x11_mfd *mfd;
  
  	if (!pdev && !list_empty(&sta2x11_mfd_list)) {
81d30eda9   Joe Perches   mfd: Convert rema...
51
52
53
  		pr_warn("%s: Unspecified device, using first instance
  ",
  			__func__);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
54
55
56
57
58
59
60
61
62
63
64
65
66
  		return list_entry(sta2x11_mfd_list.next,
  				  struct sta2x11_mfd, list);
  	}
  
  	instance = sta2x11_get_instance(pdev);
  	if (!instance)
  		return NULL;
  	list_for_each_entry(mfd, &sta2x11_mfd_list, list) {
  		if (mfd->instance == instance)
  			return mfd;
  	}
  	return NULL;
  }
f791be492   Bill Pemberton   mfd: remove use o...
67
  static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
68
  {
e885ba298   Davide Ciminaghi   mfd: sta2x11-mfd:...
69
  	int i;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
70
71
72
73
74
75
76
77
78
79
80
81
  	struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
  	struct sta2x11_instance *instance;
  
  	if (mfd)
  		return -EBUSY;
  	instance = sta2x11_get_instance(pdev);
  	if (!instance)
  		return -EINVAL;
  	mfd = kzalloc(sizeof(*mfd), flags);
  	if (!mfd)
  		return -ENOMEM;
  	INIT_LIST_HEAD(&mfd->list);
e885ba298   Davide Ciminaghi   mfd: sta2x11-mfd:...
82
83
  	for (i = 0; i < ARRAY_SIZE(mfd->lock); i++)
  		spin_lock_init(&mfd->lock[i]);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
84
85
86
87
  	mfd->instance = instance;
  	list_add(&mfd->list, &sta2x11_mfd_list);
  	return 0;
  }
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
88
89
90
  /* This function is exported and is not expected to fail */
  u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val,
  		       enum sta2x11_mfd_plat_dev index)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
91
92
93
94
  {
  	struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
  	u32 r;
  	unsigned long flags;
709edecd4   Wei Yongjun   mfd: sta2x11: Fix...
95
  	void __iomem *regs;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
96
97
98
99
100
101
  
  	if (!mfd) {
  		dev_warn(&pdev->dev, ": can't access sctl regs
  ");
  		return 0;
  	}
709edecd4   Wei Yongjun   mfd: sta2x11: Fix...
102
103
  
  	regs = mfd->regs[index];
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
104
  	if (!regs) {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
105
106
107
108
  		dev_warn(&pdev->dev, ": system ctl not initialized
  ");
  		return 0;
  	}
e885ba298   Davide Ciminaghi   mfd: sta2x11-mfd:...
109
  	spin_lock_irqsave(&mfd->lock[index], flags);
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
110
  	r = readl(regs + reg);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
111
112
113
  	r &= ~mask;
  	r |= val;
  	if (mask)
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
114
  		writel(r, regs + reg);
e885ba298   Davide Ciminaghi   mfd: sta2x11-mfd:...
115
  	spin_unlock_irqrestore(&mfd->lock[index], flags);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
116
117
  	return r;
  }
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
118
  EXPORT_SYMBOL(__sta2x11_mfd_mask);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
119

29f5b5a32   Davide Ciminaghi   mfd: sta2x11-mfd:...
120
121
122
123
  int sta2x11_mfd_get_regs_data(struct platform_device *dev,
  			      enum sta2x11_mfd_plat_dev index,
  			      void __iomem **regs,
  			      spinlock_t **lock)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
124
  {
334a41ce9   Jingoo Han   mfd: Use dev_get_...
125
  	struct pci_dev *pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
29f5b5a32   Davide Ciminaghi   mfd: sta2x11-mfd:...
126
  	struct sta2x11_mfd *mfd;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
127

29f5b5a32   Davide Ciminaghi   mfd: sta2x11-mfd:...
128
129
130
131
132
133
134
135
136
137
138
139
  	if (!pdev)
  		return -ENODEV;
  	mfd = sta2x11_mfd_find(pdev);
  	if (!mfd)
  		return -ENODEV;
  	if (index >= sta2x11_n_mfd_plat_devs)
  		return -ENODEV;
  	*regs = mfd->regs[index];
  	*lock = &mfd->lock[index];
  	pr_debug("%s %d *regs = %p
  ", __func__, __LINE__, *regs);
  	return *regs ? 0 : -ENODEV;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
140
  }
29f5b5a32   Davide Ciminaghi   mfd: sta2x11-mfd:...
141
  EXPORT_SYMBOL(sta2x11_mfd_get_regs_data);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
142

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
143
144
145
  /*
   * Special sta2x11-mfd regmap lock/unlock functions
   */
35bdd2909   Alessandro Rubini   mfd: Add driver f...
146

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
147
148
149
150
151
  static void sta2x11_regmap_lock(void *__lock)
  {
  	spinlock_t *lock = __lock;
  	spin_lock(lock);
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
152

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
153
154
155
156
157
  static void sta2x11_regmap_unlock(void *__lock)
  {
  	spinlock_t *lock = __lock;
  	spin_unlock(lock);
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
158

dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
159
160
161
162
  /* OTP (one time programmable registers do not require locking */
  static void sta2x11_regmap_nolock(void *__lock)
  {
  }
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
163
  static const char *sta2x11_mfd_names[sta2x11_n_mfd_plat_devs] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
164
165
166
  	[sta2x11_sctl] = STA2X11_MFD_SCTL_NAME,
  	[sta2x11_apbreg] = STA2X11_MFD_APBREG_NAME,
  	[sta2x11_apb_soc_regs] = STA2X11_MFD_APB_SOC_REGS_NAME,
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
167
  	[sta2x11_scr] = STA2X11_MFD_SCR_NAME,
35bdd2909   Alessandro Rubini   mfd: Add driver f...
168
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
169

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
170
171
172
173
174
175
176
177
178
179
180
181
182
  static bool sta2x11_sctl_writeable_reg(struct device *dev, unsigned int reg)
  {
  	return !__reg_within_range(reg, SCTL_SCPCIECSBRST, SCTL_SCRSTSTA);
  }
  
  static struct regmap_config sta2x11_sctl_regmap_config = {
  	.reg_bits = 32,
  	.reg_stride = 4,
  	.val_bits = 32,
  	.lock = sta2x11_regmap_lock,
  	.unlock = sta2x11_regmap_unlock,
  	.max_register = SCTL_SCRSTSTA,
  	.writeable_reg = sta2x11_sctl_writeable_reg,
35bdd2909   Alessandro Rubini   mfd: Add driver f...
183
  };
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
184
185
186
187
188
  static bool sta2x11_scr_readable_reg(struct device *dev, unsigned int reg)
  {
  	return (reg == STA2X11_SECR_CR) ||
  		__reg_within_range(reg, STA2X11_SECR_FVR0, STA2X11_SECR_FVR1);
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
189

dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
190
  static bool sta2x11_scr_writeable_reg(struct device *dev, unsigned int reg)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
191
  {
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
192
193
  	return false;
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
194

dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
195
196
197
198
199
200
201
202
203
204
  static struct regmap_config sta2x11_scr_regmap_config = {
  	.reg_bits = 32,
  	.reg_stride = 4,
  	.val_bits = 32,
  	.lock = sta2x11_regmap_nolock,
  	.unlock = sta2x11_regmap_nolock,
  	.max_register = STA2X11_SECR_FVR1,
  	.readable_reg = sta2x11_scr_readable_reg,
  	.writeable_reg = sta2x11_scr_writeable_reg,
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
205

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  static bool sta2x11_apbreg_readable_reg(struct device *dev, unsigned int reg)
  {
  	/* Two blocks (CAN and MLB, SARAC) 0x100 bytes apart */
  	if (reg >= APBREG_BSR_SARAC)
  		reg -= APBREG_BSR_SARAC;
  	switch (reg) {
  	case APBREG_BSR:
  	case APBREG_PAER:
  	case APBREG_PWAC:
  	case APBREG_PRAC:
  	case APBREG_PCG:
  	case APBREG_PUR:
  	case APBREG_EMU_PCG:
  		return true;
  	default:
  		return false;
  	}
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
224

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
225
226
227
228
229
230
231
232
  static bool sta2x11_apbreg_writeable_reg(struct device *dev, unsigned int reg)
  {
  	if (reg >= APBREG_BSR_SARAC)
  		reg -= APBREG_BSR_SARAC;
  	if (!sta2x11_apbreg_readable_reg(dev, reg))
  		return false;
  	return reg != APBREG_PAER;
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
233

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
234
235
236
237
238
239
240
241
242
  static struct regmap_config sta2x11_apbreg_regmap_config = {
  	.reg_bits = 32,
  	.reg_stride = 4,
  	.val_bits = 32,
  	.lock = sta2x11_regmap_lock,
  	.unlock = sta2x11_regmap_unlock,
  	.max_register = APBREG_EMU_PCG_SARAC,
  	.readable_reg = sta2x11_apbreg_readable_reg,
  	.writeable_reg = sta2x11_apbreg_writeable_reg,
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
243
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
244

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
245
246
247
248
249
250
251
252
253
254
  static bool sta2x11_apb_soc_regs_readable_reg(struct device *dev,
  					      unsigned int reg)
  {
  	return reg <= PCIE_SoC_INT_ROUTER_STATUS3_REG ||
  		__reg_within_range(reg, DMA_IP_CTRL_REG, SPARE3_RESERVED) ||
  		__reg_within_range(reg, MASTER_LOCK_REG,
  				   SYSTEM_CONFIG_STATUS_REG) ||
  		reg == MSP_CLK_CTRL_REG ||
  		__reg_within_range(reg, COMPENSATION_REG1, TEST_CTL_REG);
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
255

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  static bool sta2x11_apb_soc_regs_writeable_reg(struct device *dev,
  					       unsigned int reg)
  {
  	if (!sta2x11_apb_soc_regs_readable_reg(dev, reg))
  		return false;
  	switch (reg) {
  	case PCIE_COMMON_CLOCK_CONFIG_0_4_0:
  	case SYSTEM_CONFIG_STATUS_REG:
  	case COMPENSATION_REG1:
  	case PCIE_SoC_INT_ROUTER_STATUS0_REG...PCIE_SoC_INT_ROUTER_STATUS3_REG:
  	case PCIE_PM_STATUS_0_PORT_0_4...PCIE_PM_STATUS_7_0_EP4:
  		return false;
  	default:
  		return true;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
270
  	}
35bdd2909   Alessandro Rubini   mfd: Add driver f...
271
  }
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
272
273
274
275
276
277
278
279
280
  static struct regmap_config sta2x11_apb_soc_regs_regmap_config = {
  	.reg_bits = 32,
  	.reg_stride = 4,
  	.val_bits = 32,
  	.lock = sta2x11_regmap_lock,
  	.unlock = sta2x11_regmap_unlock,
  	.max_register = TEST_CTL_REG,
  	.readable_reg = sta2x11_apb_soc_regs_readable_reg,
  	.writeable_reg = sta2x11_apb_soc_regs_writeable_reg,
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
281
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
282

d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
283
284
285
286
287
  static struct regmap_config *
  sta2x11_mfd_regmap_configs[sta2x11_n_mfd_plat_devs] = {
  	[sta2x11_sctl] = &sta2x11_sctl_regmap_config,
  	[sta2x11_apbreg] = &sta2x11_apbreg_regmap_config,
  	[sta2x11_apb_soc_regs] = &sta2x11_apb_soc_regs_regmap_config,
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
288
  	[sta2x11_scr] = &sta2x11_scr_regmap_config,
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
289
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
290

dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
291
  /* Probe for the four platform devices */
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
292
293
294
  
  static int sta2x11_mfd_platform_probe(struct platform_device *dev,
  				      enum sta2x11_mfd_plat_dev index)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
295
296
297
298
  {
  	struct pci_dev **pdev;
  	struct sta2x11_mfd *mfd;
  	struct resource *res;
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
299
  	const char *name = sta2x11_mfd_names[index];
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
300
  	struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index];
35bdd2909   Alessandro Rubini   mfd: Add driver f...
301

334a41ce9   Jingoo Han   mfd: Use dev_get_...
302
  	pdev = dev_get_platdata(&dev->dev);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
303
304
305
  	mfd = sta2x11_mfd_find(*pdev);
  	if (!mfd)
  		return -ENODEV;
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
306
307
  	if (!regmap_config)
  		return -ENODEV;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
308
309
310
311
  
  	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -ENOMEM;
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
312
  	if (!request_mem_region(res->start, resource_size(res), name))
35bdd2909   Alessandro Rubini   mfd: Add driver f...
313
  		return -EBUSY;
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
314
315
  	mfd->regs[index] = ioremap(res->start, resource_size(res));
  	if (!mfd->regs[index]) {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
316
317
318
  		release_mem_region(res->start, resource_size(res));
  		return -ENOMEM;
  	}
d94e25535   Davide Ciminaghi   mfd: sta2x11-mfd:...
319
320
321
322
323
324
325
326
  	regmap_config->lock_arg = &mfd->lock;
  	/*
  	   No caching, registers could be reached both via regmap and via
  	   void __iomem *
  	*/
  	regmap_config->cache_type = REGCACHE_NONE;
  	mfd->regmap[index] = devm_regmap_init_mmio(&dev->dev, mfd->regs[index],
  						   regmap_config);
ec9e4ba67   Wei Yongjun   mfd: sta2x11-mfd:...
327
  	WARN_ON(IS_ERR(mfd->regmap[index]));
35bdd2909   Alessandro Rubini   mfd: Add driver f...
328

35bdd2909   Alessandro Rubini   mfd: Add driver f...
329
330
  	return 0;
  }
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  static int sta2x11_sctl_probe(struct platform_device *dev)
  {
  	return sta2x11_mfd_platform_probe(dev, sta2x11_sctl);
  }
  
  static int sta2x11_apbreg_probe(struct platform_device *dev)
  {
  	return sta2x11_mfd_platform_probe(dev, sta2x11_apbreg);
  }
  
  static int sta2x11_apb_soc_regs_probe(struct platform_device *dev)
  {
  	return sta2x11_mfd_platform_probe(dev, sta2x11_apb_soc_regs);
  }
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
345
346
347
348
  static int sta2x11_scr_probe(struct platform_device *dev)
  {
  	return sta2x11_mfd_platform_probe(dev, sta2x11_scr);
  }
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
349
  /* The three platform drivers */
35bdd2909   Alessandro Rubini   mfd: Add driver f...
350
351
  static struct platform_driver sta2x11_sctl_platform_driver = {
  	.driver = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
352
  		.name	= STA2X11_MFD_SCTL_NAME,
35bdd2909   Alessandro Rubini   mfd: Add driver f...
353
354
355
  	},
  	.probe		= sta2x11_sctl_probe,
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
356
357
  static struct platform_driver sta2x11_platform_driver = {
  	.driver = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
358
  		.name	= STA2X11_MFD_APBREG_NAME,
35bdd2909   Alessandro Rubini   mfd: Add driver f...
359
360
361
  	},
  	.probe		= sta2x11_apbreg_probe,
  };
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
362
363
  static struct platform_driver sta2x11_apb_soc_regs_platform_driver = {
  	.driver = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
364
  		.name	= STA2X11_MFD_APB_SOC_REGS_NAME,
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
365
366
367
  	},
  	.probe		= sta2x11_apb_soc_regs_probe,
  };
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
368
369
370
  static struct platform_driver sta2x11_scr_platform_driver = {
  	.driver = {
  		.name = STA2X11_MFD_SCR_NAME,
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
371
372
373
  	},
  	.probe = sta2x11_scr_probe,
  };
d91d76d84   Thierry Reding   mfd: sta2x11: Use...
374
375
376
377
378
379
380
381
  static struct platform_driver * const drivers[] = {
  	&sta2x11_platform_driver,
  	&sta2x11_sctl_platform_driver,
  	&sta2x11_apb_soc_regs_platform_driver,
  	&sta2x11_scr_platform_driver,
  };
  
  static int __init sta2x11_drivers_init(void)
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
382
  {
d91d76d84   Thierry Reding   mfd: sta2x11: Use...
383
  	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
dba6c1aee   Davide Ciminaghi   mfd: sta2x11-mfd:...
384
  }
35bdd2909   Alessandro Rubini   mfd: Add driver f...
385
  /*
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
386
   * What follows are the PCI devices that host the above pdevs.
35bdd2909   Alessandro Rubini   mfd: Add driver f...
387
388
   * Each logic block is 4kB and they are all consecutive: we use this info.
   */
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
389
390
391
392
  /* Mfd 0 device */
  
  /* Mfd 0, Bar 0 */
  enum mfd0_bar0_cells {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
393
394
395
396
397
398
399
400
  	STA2X11_GPIO_0 = 0,
  	STA2X11_GPIO_1,
  	STA2X11_GPIO_2,
  	STA2X11_GPIO_3,
  	STA2X11_SCTL,
  	STA2X11_SCR,
  	STA2X11_TIME,
  };
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
401
402
  /* Mfd 0 , Bar 1 */
  enum mfd0_bar1_cells {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
403
404
405
406
407
408
409
  	STA2X11_APBREG = 0,
  };
  #define CELL_4K(_name, _cell) { \
  		.name = _name, \
  		.start = _cell * 4096, .end = _cell * 4096 + 4095, \
  		.flags = IORESOURCE_MEM, \
  		}
a73e5df16   Bill Pemberton   mfd: remove use o...
410
  static const struct resource gpio_resources[] = {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
411
  	{
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
412
413
  		/* 4 consecutive cells, 1 driver */
  		.name = STA2X11_MFD_GPIO_NAME,
35bdd2909   Alessandro Rubini   mfd: Add driver f...
414
415
416
417
418
  		.start = 0,
  		.end = (4 * 4096) - 1,
  		.flags = IORESOURCE_MEM,
  	}
  };
a73e5df16   Bill Pemberton   mfd: remove use o...
419
  static const struct resource sctl_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
420
  	CELL_4K(STA2X11_MFD_SCTL_NAME, STA2X11_SCTL),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
421
  };
a73e5df16   Bill Pemberton   mfd: remove use o...
422
  static const struct resource scr_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
423
  	CELL_4K(STA2X11_MFD_SCR_NAME, STA2X11_SCR),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
424
  };
a73e5df16   Bill Pemberton   mfd: remove use o...
425
  static const struct resource time_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
426
  	CELL_4K(STA2X11_MFD_TIME_NAME, STA2X11_TIME),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
427
  };
a73e5df16   Bill Pemberton   mfd: remove use o...
428
  static const struct resource apbreg_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
429
  	CELL_4K(STA2X11_MFD_APBREG_NAME, STA2X11_APBREG),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
430
431
432
433
  };
  
  #define DEV(_name, _r) \
  	{ .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, }
2dfea3803   Linus Torvalds   Merge tag 'mfd-3....
434
  static struct mfd_cell sta2x11_mfd0_bar0[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
435
436
437
438
439
  	/* offset 0: we add pdata later */
  	DEV(STA2X11_MFD_GPIO_NAME, gpio_resources),
  	DEV(STA2X11_MFD_SCTL_NAME, sctl_resources),
  	DEV(STA2X11_MFD_SCR_NAME,  scr_resources),
  	DEV(STA2X11_MFD_TIME_NAME, time_resources),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
440
  };
2dfea3803   Linus Torvalds   Merge tag 'mfd-3....
441
  static struct mfd_cell sta2x11_mfd0_bar1[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
442
  	DEV(STA2X11_MFD_APBREG_NAME, apbreg_resources),
35bdd2909   Alessandro Rubini   mfd: Add driver f...
443
  };
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
444
445
446
447
448
449
450
451
452
453
454
  /* Mfd 1 devices */
  
  /* Mfd 1, Bar 0 */
  enum mfd1_bar0_cells {
  	STA2X11_VIC = 0,
  };
  
  /* Mfd 1, Bar 1 */
  enum mfd1_bar1_cells {
  	STA2X11_APB_SOC_REGS = 0,
  };
612b95cd7   Greg Kroah-Hartman   Drivers: mfd: rem...
455
  static const struct resource vic_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
456
  	CELL_4K(STA2X11_MFD_VIC_NAME, STA2X11_VIC),
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
457
  };
612b95cd7   Greg Kroah-Hartman   Drivers: mfd: rem...
458
  static const struct resource apb_soc_regs_resources[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
459
  	CELL_4K(STA2X11_MFD_APB_SOC_REGS_NAME, STA2X11_APB_SOC_REGS),
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
460
  };
612b95cd7   Greg Kroah-Hartman   Drivers: mfd: rem...
461
  static struct mfd_cell sta2x11_mfd1_bar0[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
462
  	DEV(STA2X11_MFD_VIC_NAME, vic_resources),
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
463
  };
612b95cd7   Greg Kroah-Hartman   Drivers: mfd: rem...
464
  static struct mfd_cell sta2x11_mfd1_bar1[] = {
b18adafcc   Davide Ciminaghi   mfd: sta2x11-mfd:...
465
  	DEV(STA2X11_MFD_APB_SOC_REGS_NAME, apb_soc_regs_resources),
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
466
  };
35bdd2909   Alessandro Rubini   mfd: Add driver f...
467
468
469
470
471
472
473
474
475
476
477
478
  static int sta2x11_mfd_suspend(struct pci_dev *pdev, pm_message_t state)
  {
  	pci_save_state(pdev);
  	pci_disable_device(pdev);
  	pci_set_power_state(pdev, pci_choose_state(pdev, state));
  
  	return 0;
  }
  
  static int sta2x11_mfd_resume(struct pci_dev *pdev)
  {
  	int err;
4d1d99807   Julia Lawall   mfd: sta2x11-mfd:...
479
  	pci_set_power_state(pdev, PCI_D0);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
480
481
482
483
484
485
486
  	err = pci_enable_device(pdev);
  	if (err)
  		return err;
  	pci_restore_state(pdev);
  
  	return 0;
  }
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  struct sta2x11_mfd_bar_setup_data {
  	struct mfd_cell *cells;
  	int ncells;
  };
  
  struct sta2x11_mfd_setup_data {
  	struct sta2x11_mfd_bar_setup_data bars[2];
  };
  
  #define STA2X11_MFD0 0
  #define STA2X11_MFD1 1
  
  static struct sta2x11_mfd_setup_data mfd_setup_data[] = {
  	/* Mfd 0: gpio, sctl, scr, timers / apbregs */
  	[STA2X11_MFD0] = {
  		.bars = {
  			[0] = {
  				.cells = sta2x11_mfd0_bar0,
  				.ncells = ARRAY_SIZE(sta2x11_mfd0_bar0),
  			},
  			[1] = {
  				.cells = sta2x11_mfd0_bar1,
  				.ncells = ARRAY_SIZE(sta2x11_mfd0_bar1),
  			},
  		},
  	},
  	/* Mfd 1: vic / apb-soc-regs */
  	[STA2X11_MFD1] = {
  		.bars = {
  			[0] = {
  				.cells = sta2x11_mfd1_bar0,
  				.ncells = ARRAY_SIZE(sta2x11_mfd1_bar0),
  			},
  			[1] = {
  				.cells = sta2x11_mfd1_bar1,
  				.ncells = ARRAY_SIZE(sta2x11_mfd1_bar1),
  			},
  		},
  	},
  };
2dfea3803   Linus Torvalds   Merge tag 'mfd-3....
527
528
  static void sta2x11_mfd_setup(struct pci_dev *pdev,
  			      struct sta2x11_mfd_setup_data *sd)
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
529
530
531
532
533
534
535
536
  {
  	int i, j;
  	for (i = 0; i < ARRAY_SIZE(sd->bars); i++)
  		for (j = 0; j < sd->bars[i].ncells; j++) {
  			sd->bars[i].cells[j].pdata_size = sizeof(pdev);
  			sd->bars[i].cells[j].platform_data = &pdev;
  		}
  }
f791be492   Bill Pemberton   mfd: remove use o...
537
  static int sta2x11_mfd_probe(struct pci_dev *pdev,
2dfea3803   Linus Torvalds   Merge tag 'mfd-3....
538
  			     const struct pci_device_id *pci_id)
35bdd2909   Alessandro Rubini   mfd: Add driver f...
539
540
  {
  	int err, i;
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
541
  	struct sta2x11_mfd_setup_data *setup_data;
35bdd2909   Alessandro Rubini   mfd: Add driver f...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  
  	dev_info(&pdev->dev, "%s
  ", __func__);
  
  	err = pci_enable_device(pdev);
  	if (err) {
  		dev_err(&pdev->dev, "Can't enable device.
  ");
  		return err;
  	}
  
  	err = pci_enable_msi(pdev);
  	if (err)
  		dev_info(&pdev->dev, "Enable msi failed
  ");
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
557
558
559
  	setup_data = pci_id->device == PCI_DEVICE_ID_STMICRO_GPIO ?
  		&mfd_setup_data[STA2X11_MFD0] :
  		&mfd_setup_data[STA2X11_MFD1];
35bdd2909   Alessandro Rubini   mfd: Add driver f...
560
561
  
  	/* platform data is the pci device for all of them */
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
562
  	sta2x11_mfd_setup(pdev, setup_data);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
563
564
  
  	/* Record this pdev before mfd_add_devices: their probe looks for it */
8ec86a302   Davide Ciminaghi   mfd: sta2x11-mfd:...
565
566
  	if (!sta2x11_mfd_find(pdev))
  		sta2x11_mfd_add(pdev, GFP_ATOMIC);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
567

1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
568
569
570
571
572
573
574
575
576
577
578
579
580
  	/* Just 2 bars for all mfd's at present */
  	for (i = 0; i < 2; i++) {
  		err = mfd_add_devices(&pdev->dev, -1,
  				      setup_data->bars[i].cells,
  				      setup_data->bars[i].ncells,
  				      &pdev->resource[i],
  				      0, NULL);
  		if (err) {
  			dev_err(&pdev->dev,
  				"mfd_add_devices[%d] failed: %d
  ", i, err);
  			goto err_disable;
  		}
35bdd2909   Alessandro Rubini   mfd: Add driver f...
581
582
583
584
585
586
587
588
589
590
  	}
  
  	return 0;
  
  err_disable:
  	mfd_remove_devices(&pdev->dev);
  	pci_disable_device(pdev);
  	pci_disable_msi(pdev);
  	return err;
  }
36fcd06c4   Jingoo Han   mfd: Remove DEFIN...
591
  static const struct pci_device_id sta2x11_mfd_tbl[] = {
35bdd2909   Alessandro Rubini   mfd: Add driver f...
592
  	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_GPIO)},
1950c7164   Davide Ciminaghi   mfd: sta2x11-mfd:...
593
  	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIC)},
35bdd2909   Alessandro Rubini   mfd: Add driver f...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  	{0,},
  };
  
  static struct pci_driver sta2x11_mfd_driver = {
  	.name =		"sta2x11-mfd",
  	.id_table =	sta2x11_mfd_tbl,
  	.probe =	sta2x11_mfd_probe,
  	.suspend =	sta2x11_mfd_suspend,
  	.resume =	sta2x11_mfd_resume,
  };
  
  static int __init sta2x11_mfd_init(void)
  {
  	pr_info("%s
  ", __func__);
  	return pci_register_driver(&sta2x11_mfd_driver);
  }
  
  /*
   * All of this must be ready before "normal" devices like MMCI appear.
   * But MFD (the pci device) can't be too early. The following choice
   * prepares platform drivers very early and probe the PCI device later,
   * but before other PCI devices.
   */
d91d76d84   Thierry Reding   mfd: sta2x11: Use...
618
  subsys_initcall(sta2x11_drivers_init);
35bdd2909   Alessandro Rubini   mfd: Add driver f...
619
  rootfs_initcall(sta2x11_mfd_init);