Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Motorola CPCAP PMIC core driver
  4 *
  5 * Copyright (C) 2016 Tony Lindgren <tony@atomide.com>
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/err.h>
 10#include <linux/interrupt.h>
 11#include <linux/irq.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/of_device.h>
 15#include <linux/regmap.h>
 16#include <linux/sysfs.h>
 17
 18#include <linux/mfd/core.h>
 19#include <linux/mfd/motorola-cpcap.h>
 20#include <linux/spi/spi.h>
 21
 22#define CPCAP_NR_IRQ_REG_BANKS	6
 23#define CPCAP_NR_IRQ_CHIPS	3
 24#define CPCAP_REGISTER_SIZE	4
 25#define CPCAP_REGISTER_BITS	16
 26
 27struct cpcap_ddata {
 28	struct spi_device *spi;
 29	struct regmap_irq *irqs;
 30	struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
 31	const struct regmap_config *regmap_conf;
 32	struct regmap *regmap;
 33};
 34
 35static int cpcap_sense_irq(struct regmap *regmap, int irq)
 36{
 37	int regnum = irq / CPCAP_REGISTER_BITS;
 38	int mask = BIT(irq % CPCAP_REGISTER_BITS);
 39	int reg = CPCAP_REG_INTS1 + (regnum * CPCAP_REGISTER_SIZE);
 40	int err, val;
 41
 42	if (reg < CPCAP_REG_INTS1 || reg > CPCAP_REG_INTS4)
 43		return -EINVAL;
 44
 45	err = regmap_read(regmap, reg, &val);
 46	if (err)
 47		return err;
 48
 49	return !!(val & mask);
 50}
 51
 52int cpcap_sense_virq(struct regmap *regmap, int virq)
 53{
 54	struct regmap_irq_chip_data *d = irq_get_chip_data(virq);
 55	int irq_base = regmap_irq_chip_get_base(d);
 56
 57	return cpcap_sense_irq(regmap, virq - irq_base);
 58}
 59EXPORT_SYMBOL_GPL(cpcap_sense_virq);
 60
 61static int cpcap_check_revision(struct cpcap_ddata *cpcap)
 62{
 63	u16 vendor, rev;
 64	int ret;
 65
 66	ret = cpcap_get_vendor(&cpcap->spi->dev, cpcap->regmap, &vendor);
 67	if (ret)
 68		return ret;
 69
 70	ret = cpcap_get_revision(&cpcap->spi->dev, cpcap->regmap, &rev);
 71	if (ret)
 72		return ret;
 73
 74	dev_info(&cpcap->spi->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n",
 75		 vendor == CPCAP_VENDOR_ST ? "ST" : "TI",
 76		 CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
 77		 rev);
 78
 79	if (rev < CPCAP_REVISION_2_1) {
 80		dev_info(&cpcap->spi->dev,
 81			 "Please add old CPCAP revision support as needed\n");
 82		return -ENODEV;
 83	}
 84
 85	return 0;
 86}
 87
 88/*
 89 * First two irq chips are the two private macro interrupt chips, the third
 90 * irq chip is for register banks 1 - 4 and is available for drivers to use.
 91 */
 92static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
 93	{
 94		.name = "cpcap-m2",
 95		.num_regs = 1,
 96		.status_base = CPCAP_REG_MI1,
 97		.ack_base = CPCAP_REG_MI1,
 98		.mask_base = CPCAP_REG_MIM1,
 99		.use_ack = true,
100		.ack_invert = true,
101	},
102	{
103		.name = "cpcap-m2",
104		.num_regs = 1,
105		.status_base = CPCAP_REG_MI2,
106		.ack_base = CPCAP_REG_MI2,
107		.mask_base = CPCAP_REG_MIM2,
108		.use_ack = true,
109		.ack_invert = true,
110	},
111	{
112		.name = "cpcap1-4",
113		.num_regs = 4,
114		.status_base = CPCAP_REG_INT1,
115		.ack_base = CPCAP_REG_INT1,
116		.mask_base = CPCAP_REG_INTM1,
117		.use_ack = true,
118		.ack_invert = true,
119	},
120};
121
122static void cpcap_init_one_regmap_irq(struct cpcap_ddata *cpcap,
123				      struct regmap_irq *rirq,
124				      int irq_base, int irq)
125{
126	unsigned int reg_offset;
127	unsigned int bit, mask;
128
129	reg_offset = irq - irq_base;
130	reg_offset /= cpcap->regmap_conf->val_bits;
131	reg_offset *= cpcap->regmap_conf->reg_stride;
132
133	bit = irq % cpcap->regmap_conf->val_bits;
134	mask = (1 << bit);
135
136	rirq->reg_offset = reg_offset;
137	rirq->mask = mask;
138}
139
140static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
141			       int irq_start, int nr_irqs)
142{
143	struct regmap_irq_chip *chip = &cpcap_irq_chip[irq_chip];
144	int i, ret;
145
146	for (i = irq_start; i < irq_start + nr_irqs; i++) {
147		struct regmap_irq *rirq = &cpcap->irqs[i];
148
149		cpcap_init_one_regmap_irq(cpcap, rirq, irq_start, i);
150	}
151	chip->irqs = &cpcap->irqs[irq_start];
152	chip->num_irqs = nr_irqs;
153	chip->irq_drv_data = cpcap;
154
155	ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
156				       cpcap->spi->irq,
157				       irq_get_trigger_type(cpcap->spi->irq) |
158				       IRQF_SHARED, -1,
159				       chip, &cpcap->irqdata[irq_chip]);
160	if (ret) {
161		dev_err(&cpcap->spi->dev, "could not add irq chip %i: %i\n",
162			irq_chip, ret);
163		return ret;
164	}
165
166	return 0;
167}
168
169static int cpcap_init_irq(struct cpcap_ddata *cpcap)
170{
171	int ret;
172
173	cpcap->irqs = devm_kzalloc(&cpcap->spi->dev,
174				   array3_size(sizeof(*cpcap->irqs),
175					       CPCAP_NR_IRQ_REG_BANKS,
176					       cpcap->regmap_conf->val_bits),
177				   GFP_KERNEL);
178	if (!cpcap->irqs)
179		return -ENOMEM;
180
181	ret = cpcap_init_irq_chip(cpcap, 0, 0, 16);
182	if (ret)
183		return ret;
184
185	ret = cpcap_init_irq_chip(cpcap, 1, 16, 16);
186	if (ret)
187		return ret;
188
189	ret = cpcap_init_irq_chip(cpcap, 2, 32, 64);
190	if (ret)
191		return ret;
192
193	enable_irq_wake(cpcap->spi->irq);
194
195	return 0;
196}
197
198static const struct of_device_id cpcap_of_match[] = {
199	{ .compatible = "motorola,cpcap", },
200	{ .compatible = "st,6556002", },
201	{},
202};
203MODULE_DEVICE_TABLE(of, cpcap_of_match);
204
 
 
 
 
 
 
 
205static const struct regmap_config cpcap_regmap_config = {
206	.reg_bits = 16,
207	.reg_stride = 4,
208	.pad_bits = 0,
209	.val_bits = 16,
210	.write_flag_mask = 0x8000,
211	.max_register = CPCAP_REG_ST_TEST2,
212	.cache_type = REGCACHE_NONE,
213	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
214	.val_format_endian = REGMAP_ENDIAN_LITTLE,
215};
216
217#ifdef CONFIG_PM_SLEEP
218static int cpcap_suspend(struct device *dev)
219{
220	struct spi_device *spi = to_spi_device(dev);
221
222	disable_irq(spi->irq);
223
224	return 0;
225}
226
227static int cpcap_resume(struct device *dev)
228{
229	struct spi_device *spi = to_spi_device(dev);
230
231	enable_irq(spi->irq);
232
233	return 0;
234}
235#endif
236
237static SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
238
239static const struct mfd_cell cpcap_mfd_devices[] = {
240	{
241		.name          = "cpcap_adc",
242		.of_compatible = "motorola,mapphone-cpcap-adc",
243	}, {
244		.name          = "cpcap_battery",
245		.of_compatible = "motorola,cpcap-battery",
246	}, {
247		.name          = "cpcap-charger",
248		.of_compatible = "motorola,mapphone-cpcap-charger",
249	}, {
250		.name          = "cpcap-regulator",
251		.of_compatible = "motorola,mapphone-cpcap-regulator",
252	}, {
253		.name          = "cpcap-rtc",
254		.of_compatible = "motorola,cpcap-rtc",
255	}, {
256		.name          = "cpcap-pwrbutton",
257		.of_compatible = "motorola,cpcap-pwrbutton",
258	}, {
259		.name          = "cpcap-usb-phy",
260		.of_compatible = "motorola,mapphone-cpcap-usb-phy",
261	}, {
262		.name          = "cpcap-led",
263		.id            = 0,
264		.of_compatible = "motorola,cpcap-led-red",
265	}, {
266		.name          = "cpcap-led",
267		.id            = 1,
268		.of_compatible = "motorola,cpcap-led-green",
269	}, {
270		.name          = "cpcap-led",
271		.id            = 2,
272		.of_compatible = "motorola,cpcap-led-blue",
273	}, {
274		.name          = "cpcap-led",
275		.id            = 3,
276		.of_compatible = "motorola,cpcap-led-adl",
277	}, {
278		.name          = "cpcap-led",
279		.id            = 4,
280		.of_compatible = "motorola,cpcap-led-cp",
281	}, {
282		.name          = "cpcap-codec",
283	}
284};
285
286static int cpcap_probe(struct spi_device *spi)
287{
288	const struct of_device_id *match;
289	struct cpcap_ddata *cpcap;
290	int ret;
291
292	match = of_match_device(of_match_ptr(cpcap_of_match), &spi->dev);
293	if (!match)
294		return -ENODEV;
295
296	cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
297	if (!cpcap)
298		return -ENOMEM;
299
300	cpcap->spi = spi;
301	spi_set_drvdata(spi, cpcap);
302
303	spi->bits_per_word = 16;
304	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
305
306	ret = spi_setup(spi);
307	if (ret)
308		return ret;
309
310	cpcap->regmap_conf = &cpcap_regmap_config;
311	cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config);
312	if (IS_ERR(cpcap->regmap)) {
313		ret = PTR_ERR(cpcap->regmap);
314		dev_err(&cpcap->spi->dev, "Failed to initialize regmap: %d\n",
315			ret);
316
317		return ret;
318	}
319
320	ret = cpcap_check_revision(cpcap);
321	if (ret) {
322		dev_err(&cpcap->spi->dev, "Failed to detect CPCAP: %i\n", ret);
323		return ret;
324	}
325
326	ret = cpcap_init_irq(cpcap);
327	if (ret)
328		return ret;
329
 
 
 
 
330	return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
331				    ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
332}
333
334static struct spi_driver cpcap_driver = {
335	.driver = {
336		.name = "cpcap-core",
337		.of_match_table = cpcap_of_match,
338		.pm = &cpcap_pm,
339	},
340	.probe = cpcap_probe,
 
341};
342module_spi_driver(cpcap_driver);
343
344MODULE_ALIAS("platform:cpcap");
345MODULE_DESCRIPTION("CPCAP driver");
346MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
347MODULE_LICENSE("GPL v2");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Motorola CPCAP PMIC core driver
  4 *
  5 * Copyright (C) 2016 Tony Lindgren <tony@atomide.com>
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/err.h>
 10#include <linux/interrupt.h>
 11#include <linux/irq.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/of_device.h>
 15#include <linux/regmap.h>
 16#include <linux/sysfs.h>
 17
 18#include <linux/mfd/core.h>
 19#include <linux/mfd/motorola-cpcap.h>
 20#include <linux/spi/spi.h>
 21
 22#define CPCAP_NR_IRQ_REG_BANKS	6
 23#define CPCAP_NR_IRQ_CHIPS	3
 24#define CPCAP_REGISTER_SIZE	4
 25#define CPCAP_REGISTER_BITS	16
 26
 27struct cpcap_ddata {
 28	struct spi_device *spi;
 29	struct regmap_irq *irqs;
 30	struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
 31	const struct regmap_config *regmap_conf;
 32	struct regmap *regmap;
 33};
 34
 35static int cpcap_sense_irq(struct regmap *regmap, int irq)
 36{
 37	int regnum = irq / CPCAP_REGISTER_BITS;
 38	int mask = BIT(irq % CPCAP_REGISTER_BITS);
 39	int reg = CPCAP_REG_INTS1 + (regnum * CPCAP_REGISTER_SIZE);
 40	int err, val;
 41
 42	if (reg < CPCAP_REG_INTS1 || reg > CPCAP_REG_INTS4)
 43		return -EINVAL;
 44
 45	err = regmap_read(regmap, reg, &val);
 46	if (err)
 47		return err;
 48
 49	return !!(val & mask);
 50}
 51
 52int cpcap_sense_virq(struct regmap *regmap, int virq)
 53{
 54	struct regmap_irq_chip_data *d = irq_get_chip_data(virq);
 55	int irq_base = regmap_irq_chip_get_base(d);
 56
 57	return cpcap_sense_irq(regmap, virq - irq_base);
 58}
 59EXPORT_SYMBOL_GPL(cpcap_sense_virq);
 60
 61static int cpcap_check_revision(struct cpcap_ddata *cpcap)
 62{
 63	u16 vendor, rev;
 64	int ret;
 65
 66	ret = cpcap_get_vendor(&cpcap->spi->dev, cpcap->regmap, &vendor);
 67	if (ret)
 68		return ret;
 69
 70	ret = cpcap_get_revision(&cpcap->spi->dev, cpcap->regmap, &rev);
 71	if (ret)
 72		return ret;
 73
 74	dev_info(&cpcap->spi->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n",
 75		 vendor == CPCAP_VENDOR_ST ? "ST" : "TI",
 76		 CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
 77		 rev);
 78
 79	if (rev < CPCAP_REVISION_2_1) {
 80		dev_info(&cpcap->spi->dev,
 81			 "Please add old CPCAP revision support as needed\n");
 82		return -ENODEV;
 83	}
 84
 85	return 0;
 86}
 87
 88/*
 89 * First two irq chips are the two private macro interrupt chips, the third
 90 * irq chip is for register banks 1 - 4 and is available for drivers to use.
 91 */
 92static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
 93	{
 94		.name = "cpcap-m2",
 95		.num_regs = 1,
 96		.status_base = CPCAP_REG_MI1,
 97		.ack_base = CPCAP_REG_MI1,
 98		.mask_base = CPCAP_REG_MIM1,
 99		.use_ack = true,
100		.clear_ack = true,
101	},
102	{
103		.name = "cpcap-m2",
104		.num_regs = 1,
105		.status_base = CPCAP_REG_MI2,
106		.ack_base = CPCAP_REG_MI2,
107		.mask_base = CPCAP_REG_MIM2,
108		.use_ack = true,
109		.clear_ack = true,
110	},
111	{
112		.name = "cpcap1-4",
113		.num_regs = 4,
114		.status_base = CPCAP_REG_INT1,
115		.ack_base = CPCAP_REG_INT1,
116		.mask_base = CPCAP_REG_INTM1,
117		.use_ack = true,
118		.clear_ack = true,
119	},
120};
121
122static void cpcap_init_one_regmap_irq(struct cpcap_ddata *cpcap,
123				      struct regmap_irq *rirq,
124				      int irq_base, int irq)
125{
126	unsigned int reg_offset;
127	unsigned int bit, mask;
128
129	reg_offset = irq - irq_base;
130	reg_offset /= cpcap->regmap_conf->val_bits;
131	reg_offset *= cpcap->regmap_conf->reg_stride;
132
133	bit = irq % cpcap->regmap_conf->val_bits;
134	mask = (1 << bit);
135
136	rirq->reg_offset = reg_offset;
137	rirq->mask = mask;
138}
139
140static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
141			       int irq_start, int nr_irqs)
142{
143	struct regmap_irq_chip *chip = &cpcap_irq_chip[irq_chip];
144	int i, ret;
145
146	for (i = irq_start; i < irq_start + nr_irqs; i++) {
147		struct regmap_irq *rirq = &cpcap->irqs[i];
148
149		cpcap_init_one_regmap_irq(cpcap, rirq, irq_start, i);
150	}
151	chip->irqs = &cpcap->irqs[irq_start];
152	chip->num_irqs = nr_irqs;
153	chip->irq_drv_data = cpcap;
154
155	ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
156				       cpcap->spi->irq,
157				       irq_get_trigger_type(cpcap->spi->irq) |
158				       IRQF_SHARED, -1,
159				       chip, &cpcap->irqdata[irq_chip]);
160	if (ret) {
161		dev_err(&cpcap->spi->dev, "could not add irq chip %i: %i\n",
162			irq_chip, ret);
163		return ret;
164	}
165
166	return 0;
167}
168
169static int cpcap_init_irq(struct cpcap_ddata *cpcap)
170{
171	int ret;
172
173	cpcap->irqs = devm_kzalloc(&cpcap->spi->dev,
174				   array3_size(sizeof(*cpcap->irqs),
175					       CPCAP_NR_IRQ_REG_BANKS,
176					       cpcap->regmap_conf->val_bits),
177				   GFP_KERNEL);
178	if (!cpcap->irqs)
179		return -ENOMEM;
180
181	ret = cpcap_init_irq_chip(cpcap, 0, 0, 16);
182	if (ret)
183		return ret;
184
185	ret = cpcap_init_irq_chip(cpcap, 1, 16, 16);
186	if (ret)
187		return ret;
188
189	ret = cpcap_init_irq_chip(cpcap, 2, 32, 64);
190	if (ret)
191		return ret;
192
193	enable_irq_wake(cpcap->spi->irq);
194
195	return 0;
196}
197
198static const struct of_device_id cpcap_of_match[] = {
199	{ .compatible = "motorola,cpcap", },
200	{ .compatible = "st,6556002", },
201	{},
202};
203MODULE_DEVICE_TABLE(of, cpcap_of_match);
204
205static const struct spi_device_id cpcap_spi_ids[] = {
206	{ .name = "cpcap", },
207	{ .name = "6556002", },
208	{},
209};
210MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
211
212static const struct regmap_config cpcap_regmap_config = {
213	.reg_bits = 16,
214	.reg_stride = 4,
215	.pad_bits = 0,
216	.val_bits = 16,
217	.write_flag_mask = 0x8000,
218	.max_register = CPCAP_REG_ST_TEST2,
219	.cache_type = REGCACHE_NONE,
220	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
221	.val_format_endian = REGMAP_ENDIAN_LITTLE,
222};
223
 
224static int cpcap_suspend(struct device *dev)
225{
226	struct spi_device *spi = to_spi_device(dev);
227
228	disable_irq(spi->irq);
229
230	return 0;
231}
232
233static int cpcap_resume(struct device *dev)
234{
235	struct spi_device *spi = to_spi_device(dev);
236
237	enable_irq(spi->irq);
238
239	return 0;
240}
 
241
242static DEFINE_SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
243
244static const struct mfd_cell cpcap_mfd_devices[] = {
245	{
246		.name          = "cpcap_adc",
247		.of_compatible = "motorola,mapphone-cpcap-adc",
248	}, {
249		.name          = "cpcap_battery",
250		.of_compatible = "motorola,cpcap-battery",
251	}, {
252		.name          = "cpcap-charger",
253		.of_compatible = "motorola,mapphone-cpcap-charger",
254	}, {
255		.name          = "cpcap-regulator",
256		.of_compatible = "motorola,mapphone-cpcap-regulator",
257	}, {
258		.name          = "cpcap-rtc",
259		.of_compatible = "motorola,cpcap-rtc",
260	}, {
261		.name          = "cpcap-pwrbutton",
262		.of_compatible = "motorola,cpcap-pwrbutton",
263	}, {
264		.name          = "cpcap-usb-phy",
265		.of_compatible = "motorola,mapphone-cpcap-usb-phy",
266	}, {
267		.name          = "cpcap-led",
268		.id            = 0,
269		.of_compatible = "motorola,cpcap-led-red",
270	}, {
271		.name          = "cpcap-led",
272		.id            = 1,
273		.of_compatible = "motorola,cpcap-led-green",
274	}, {
275		.name          = "cpcap-led",
276		.id            = 2,
277		.of_compatible = "motorola,cpcap-led-blue",
278	}, {
279		.name          = "cpcap-led",
280		.id            = 3,
281		.of_compatible = "motorola,cpcap-led-adl",
282	}, {
283		.name          = "cpcap-led",
284		.id            = 4,
285		.of_compatible = "motorola,cpcap-led-cp",
286	}, {
287		.name          = "cpcap-codec",
288	}
289};
290
291static int cpcap_probe(struct spi_device *spi)
292{
293	const struct of_device_id *match;
294	struct cpcap_ddata *cpcap;
295	int ret;
296
297	match = of_match_device(cpcap_of_match, &spi->dev);
298	if (!match)
299		return -ENODEV;
300
301	cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
302	if (!cpcap)
303		return -ENOMEM;
304
305	cpcap->spi = spi;
306	spi_set_drvdata(spi, cpcap);
307
308	spi->bits_per_word = 16;
309	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
310
311	ret = spi_setup(spi);
312	if (ret)
313		return ret;
314
315	cpcap->regmap_conf = &cpcap_regmap_config;
316	cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config);
317	if (IS_ERR(cpcap->regmap)) {
318		ret = PTR_ERR(cpcap->regmap);
319		dev_err(&cpcap->spi->dev, "Failed to initialize regmap: %d\n",
320			ret);
321
322		return ret;
323	}
324
325	ret = cpcap_check_revision(cpcap);
326	if (ret) {
327		dev_err(&cpcap->spi->dev, "Failed to detect CPCAP: %i\n", ret);
328		return ret;
329	}
330
331	ret = cpcap_init_irq(cpcap);
332	if (ret)
333		return ret;
334
335	/* Parent SPI controller uses DMA, CPCAP and child devices do not */
336	spi->dev.coherent_dma_mask = 0;
337	spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
338
339	return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
340				    ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
341}
342
343static struct spi_driver cpcap_driver = {
344	.driver = {
345		.name = "cpcap-core",
346		.of_match_table = cpcap_of_match,
347		.pm = pm_sleep_ptr(&cpcap_pm),
348	},
349	.probe = cpcap_probe,
350	.id_table = cpcap_spi_ids,
351};
352module_spi_driver(cpcap_driver);
353
354MODULE_ALIAS("platform:cpcap");
355MODULE_DESCRIPTION("CPCAP driver");
356MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
357MODULE_LICENSE("GPL v2");