0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/err.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irq.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/of_device.h>
0015 #include <linux/regmap.h>
0016 #include <linux/sysfs.h>
0017
0018 #include <linux/mfd/core.h>
0019 #include <linux/mfd/motorola-cpcap.h>
0020 #include <linux/spi/spi.h>
0021
0022 #define CPCAP_NR_IRQ_REG_BANKS 6
0023 #define CPCAP_NR_IRQ_CHIPS 3
0024 #define CPCAP_REGISTER_SIZE 4
0025 #define CPCAP_REGISTER_BITS 16
0026
0027 struct cpcap_ddata {
0028 struct spi_device *spi;
0029 struct regmap_irq *irqs;
0030 struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
0031 const struct regmap_config *regmap_conf;
0032 struct regmap *regmap;
0033 };
0034
0035 static int cpcap_sense_irq(struct regmap *regmap, int irq)
0036 {
0037 int regnum = irq / CPCAP_REGISTER_BITS;
0038 int mask = BIT(irq % CPCAP_REGISTER_BITS);
0039 int reg = CPCAP_REG_INTS1 + (regnum * CPCAP_REGISTER_SIZE);
0040 int err, val;
0041
0042 if (reg < CPCAP_REG_INTS1 || reg > CPCAP_REG_INTS4)
0043 return -EINVAL;
0044
0045 err = regmap_read(regmap, reg, &val);
0046 if (err)
0047 return err;
0048
0049 return !!(val & mask);
0050 }
0051
0052 int cpcap_sense_virq(struct regmap *regmap, int virq)
0053 {
0054 struct regmap_irq_chip_data *d = irq_get_chip_data(virq);
0055 int irq_base = regmap_irq_chip_get_base(d);
0056
0057 return cpcap_sense_irq(regmap, virq - irq_base);
0058 }
0059 EXPORT_SYMBOL_GPL(cpcap_sense_virq);
0060
0061 static int cpcap_check_revision(struct cpcap_ddata *cpcap)
0062 {
0063 u16 vendor, rev;
0064 int ret;
0065
0066 ret = cpcap_get_vendor(&cpcap->spi->dev, cpcap->regmap, &vendor);
0067 if (ret)
0068 return ret;
0069
0070 ret = cpcap_get_revision(&cpcap->spi->dev, cpcap->regmap, &rev);
0071 if (ret)
0072 return ret;
0073
0074 dev_info(&cpcap->spi->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n",
0075 vendor == CPCAP_VENDOR_ST ? "ST" : "TI",
0076 CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
0077 rev);
0078
0079 if (rev < CPCAP_REVISION_2_1) {
0080 dev_info(&cpcap->spi->dev,
0081 "Please add old CPCAP revision support as needed\n");
0082 return -ENODEV;
0083 }
0084
0085 return 0;
0086 }
0087
0088
0089
0090
0091
0092 static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
0093 {
0094 .name = "cpcap-m2",
0095 .num_regs = 1,
0096 .status_base = CPCAP_REG_MI1,
0097 .ack_base = CPCAP_REG_MI1,
0098 .mask_base = CPCAP_REG_MIM1,
0099 .use_ack = true,
0100 .clear_ack = true,
0101 },
0102 {
0103 .name = "cpcap-m2",
0104 .num_regs = 1,
0105 .status_base = CPCAP_REG_MI2,
0106 .ack_base = CPCAP_REG_MI2,
0107 .mask_base = CPCAP_REG_MIM2,
0108 .use_ack = true,
0109 .clear_ack = true,
0110 },
0111 {
0112 .name = "cpcap1-4",
0113 .num_regs = 4,
0114 .status_base = CPCAP_REG_INT1,
0115 .ack_base = CPCAP_REG_INT1,
0116 .mask_base = CPCAP_REG_INTM1,
0117 .use_ack = true,
0118 .clear_ack = true,
0119 },
0120 };
0121
0122 static void cpcap_init_one_regmap_irq(struct cpcap_ddata *cpcap,
0123 struct regmap_irq *rirq,
0124 int irq_base, int irq)
0125 {
0126 unsigned int reg_offset;
0127 unsigned int bit, mask;
0128
0129 reg_offset = irq - irq_base;
0130 reg_offset /= cpcap->regmap_conf->val_bits;
0131 reg_offset *= cpcap->regmap_conf->reg_stride;
0132
0133 bit = irq % cpcap->regmap_conf->val_bits;
0134 mask = (1 << bit);
0135
0136 rirq->reg_offset = reg_offset;
0137 rirq->mask = mask;
0138 }
0139
0140 static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
0141 int irq_start, int nr_irqs)
0142 {
0143 struct regmap_irq_chip *chip = &cpcap_irq_chip[irq_chip];
0144 int i, ret;
0145
0146 for (i = irq_start; i < irq_start + nr_irqs; i++) {
0147 struct regmap_irq *rirq = &cpcap->irqs[i];
0148
0149 cpcap_init_one_regmap_irq(cpcap, rirq, irq_start, i);
0150 }
0151 chip->irqs = &cpcap->irqs[irq_start];
0152 chip->num_irqs = nr_irqs;
0153 chip->irq_drv_data = cpcap;
0154
0155 ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
0156 cpcap->spi->irq,
0157 irq_get_trigger_type(cpcap->spi->irq) |
0158 IRQF_SHARED, -1,
0159 chip, &cpcap->irqdata[irq_chip]);
0160 if (ret) {
0161 dev_err(&cpcap->spi->dev, "could not add irq chip %i: %i\n",
0162 irq_chip, ret);
0163 return ret;
0164 }
0165
0166 return 0;
0167 }
0168
0169 static int cpcap_init_irq(struct cpcap_ddata *cpcap)
0170 {
0171 int ret;
0172
0173 cpcap->irqs = devm_kzalloc(&cpcap->spi->dev,
0174 array3_size(sizeof(*cpcap->irqs),
0175 CPCAP_NR_IRQ_REG_BANKS,
0176 cpcap->regmap_conf->val_bits),
0177 GFP_KERNEL);
0178 if (!cpcap->irqs)
0179 return -ENOMEM;
0180
0181 ret = cpcap_init_irq_chip(cpcap, 0, 0, 16);
0182 if (ret)
0183 return ret;
0184
0185 ret = cpcap_init_irq_chip(cpcap, 1, 16, 16);
0186 if (ret)
0187 return ret;
0188
0189 ret = cpcap_init_irq_chip(cpcap, 2, 32, 64);
0190 if (ret)
0191 return ret;
0192
0193 enable_irq_wake(cpcap->spi->irq);
0194
0195 return 0;
0196 }
0197
0198 static const struct of_device_id cpcap_of_match[] = {
0199 { .compatible = "motorola,cpcap", },
0200 { .compatible = "st,6556002", },
0201 {},
0202 };
0203 MODULE_DEVICE_TABLE(of, cpcap_of_match);
0204
0205 static const struct spi_device_id cpcap_spi_ids[] = {
0206 { .name = "cpcap", },
0207 { .name = "6556002", },
0208 {},
0209 };
0210 MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
0211
0212 static const struct regmap_config cpcap_regmap_config = {
0213 .reg_bits = 16,
0214 .reg_stride = 4,
0215 .pad_bits = 0,
0216 .val_bits = 16,
0217 .write_flag_mask = 0x8000,
0218 .max_register = CPCAP_REG_ST_TEST2,
0219 .cache_type = REGCACHE_NONE,
0220 .reg_format_endian = REGMAP_ENDIAN_LITTLE,
0221 .val_format_endian = REGMAP_ENDIAN_LITTLE,
0222 };
0223
0224 #ifdef CONFIG_PM_SLEEP
0225 static int cpcap_suspend(struct device *dev)
0226 {
0227 struct spi_device *spi = to_spi_device(dev);
0228
0229 disable_irq(spi->irq);
0230
0231 return 0;
0232 }
0233
0234 static int cpcap_resume(struct device *dev)
0235 {
0236 struct spi_device *spi = to_spi_device(dev);
0237
0238 enable_irq(spi->irq);
0239
0240 return 0;
0241 }
0242 #endif
0243
0244 static SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
0245
0246 static const struct mfd_cell cpcap_mfd_devices[] = {
0247 {
0248 .name = "cpcap_adc",
0249 .of_compatible = "motorola,mapphone-cpcap-adc",
0250 }, {
0251 .name = "cpcap_battery",
0252 .of_compatible = "motorola,cpcap-battery",
0253 }, {
0254 .name = "cpcap-charger",
0255 .of_compatible = "motorola,mapphone-cpcap-charger",
0256 }, {
0257 .name = "cpcap-regulator",
0258 .of_compatible = "motorola,mapphone-cpcap-regulator",
0259 }, {
0260 .name = "cpcap-rtc",
0261 .of_compatible = "motorola,cpcap-rtc",
0262 }, {
0263 .name = "cpcap-pwrbutton",
0264 .of_compatible = "motorola,cpcap-pwrbutton",
0265 }, {
0266 .name = "cpcap-usb-phy",
0267 .of_compatible = "motorola,mapphone-cpcap-usb-phy",
0268 }, {
0269 .name = "cpcap-led",
0270 .id = 0,
0271 .of_compatible = "motorola,cpcap-led-red",
0272 }, {
0273 .name = "cpcap-led",
0274 .id = 1,
0275 .of_compatible = "motorola,cpcap-led-green",
0276 }, {
0277 .name = "cpcap-led",
0278 .id = 2,
0279 .of_compatible = "motorola,cpcap-led-blue",
0280 }, {
0281 .name = "cpcap-led",
0282 .id = 3,
0283 .of_compatible = "motorola,cpcap-led-adl",
0284 }, {
0285 .name = "cpcap-led",
0286 .id = 4,
0287 .of_compatible = "motorola,cpcap-led-cp",
0288 }, {
0289 .name = "cpcap-codec",
0290 }
0291 };
0292
0293 static int cpcap_probe(struct spi_device *spi)
0294 {
0295 const struct of_device_id *match;
0296 struct cpcap_ddata *cpcap;
0297 int ret;
0298
0299 match = of_match_device(of_match_ptr(cpcap_of_match), &spi->dev);
0300 if (!match)
0301 return -ENODEV;
0302
0303 cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
0304 if (!cpcap)
0305 return -ENOMEM;
0306
0307 cpcap->spi = spi;
0308 spi_set_drvdata(spi, cpcap);
0309
0310 spi->bits_per_word = 16;
0311 spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
0312
0313 ret = spi_setup(spi);
0314 if (ret)
0315 return ret;
0316
0317 cpcap->regmap_conf = &cpcap_regmap_config;
0318 cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config);
0319 if (IS_ERR(cpcap->regmap)) {
0320 ret = PTR_ERR(cpcap->regmap);
0321 dev_err(&cpcap->spi->dev, "Failed to initialize regmap: %d\n",
0322 ret);
0323
0324 return ret;
0325 }
0326
0327 ret = cpcap_check_revision(cpcap);
0328 if (ret) {
0329 dev_err(&cpcap->spi->dev, "Failed to detect CPCAP: %i\n", ret);
0330 return ret;
0331 }
0332
0333 ret = cpcap_init_irq(cpcap);
0334 if (ret)
0335 return ret;
0336
0337
0338 spi->dev.coherent_dma_mask = 0;
0339 spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
0340
0341 return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
0342 ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
0343 }
0344
0345 static struct spi_driver cpcap_driver = {
0346 .driver = {
0347 .name = "cpcap-core",
0348 .of_match_table = cpcap_of_match,
0349 .pm = &cpcap_pm,
0350 },
0351 .probe = cpcap_probe,
0352 .id_table = cpcap_spi_ids,
0353 };
0354 module_spi_driver(cpcap_driver);
0355
0356 MODULE_ALIAS("platform:cpcap");
0357 MODULE_DESCRIPTION("CPCAP driver");
0358 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
0359 MODULE_LICENSE("GPL v2");