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