0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/interrupt.h>
0010 #include <linux/mfd/atc260x/core.h>
0011 #include <linux/mfd/core.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_device.h>
0015 #include <linux/regmap.h>
0016
0017 #define ATC260X_CHIP_REV_MAX 31
0018
0019 struct atc260x_init_regs {
0020 unsigned int cmu_devrst;
0021 unsigned int cmu_devrst_ints;
0022 unsigned int ints_msk;
0023 unsigned int pad_en;
0024 unsigned int pad_en_extirq;
0025 };
0026
0027 static void regmap_lock_mutex(void *__mutex)
0028 {
0029 struct mutex *mutex = __mutex;
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 if (system_state > SYSTEM_RUNNING && irqs_disabled())
0043 mutex_trylock(mutex);
0044 else
0045 mutex_lock(mutex);
0046 }
0047
0048 static void regmap_unlock_mutex(void *__mutex)
0049 {
0050 struct mutex *mutex = __mutex;
0051
0052 mutex_unlock(mutex);
0053 }
0054
0055 static const struct regmap_config atc2603c_regmap_config = {
0056 .reg_bits = 8,
0057 .val_bits = 16,
0058 .max_register = ATC2603C_SADDR,
0059 .cache_type = REGCACHE_NONE,
0060 };
0061
0062 static const struct regmap_config atc2609a_regmap_config = {
0063 .reg_bits = 8,
0064 .val_bits = 16,
0065 .max_register = ATC2609A_SADDR,
0066 .cache_type = REGCACHE_NONE,
0067 };
0068
0069 static const struct regmap_irq atc2603c_regmap_irqs[] = {
0070 REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO, 0, ATC2603C_INTS_MSK_AUDIO),
0071 REGMAP_IRQ_REG(ATC2603C_IRQ_OV, 0, ATC2603C_INTS_MSK_OV),
0072 REGMAP_IRQ_REG(ATC2603C_IRQ_OC, 0, ATC2603C_INTS_MSK_OC),
0073 REGMAP_IRQ_REG(ATC2603C_IRQ_OT, 0, ATC2603C_INTS_MSK_OT),
0074 REGMAP_IRQ_REG(ATC2603C_IRQ_UV, 0, ATC2603C_INTS_MSK_UV),
0075 REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM, 0, ATC2603C_INTS_MSK_ALARM),
0076 REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF, 0, ATC2603C_INTS_MSK_ONOFF),
0077 REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO, 0, ATC2603C_INTS_MSK_SGPIO),
0078 REGMAP_IRQ_REG(ATC2603C_IRQ_IR, 0, ATC2603C_INTS_MSK_IR),
0079 REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON, 0, ATC2603C_INTS_MSK_REMCON),
0080 REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN, 0, ATC2603C_INTS_MSK_POWERIN),
0081 };
0082
0083 static const struct regmap_irq atc2609a_regmap_irqs[] = {
0084 REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO, 0, ATC2609A_INTS_MSK_AUDIO),
0085 REGMAP_IRQ_REG(ATC2609A_IRQ_OV, 0, ATC2609A_INTS_MSK_OV),
0086 REGMAP_IRQ_REG(ATC2609A_IRQ_OC, 0, ATC2609A_INTS_MSK_OC),
0087 REGMAP_IRQ_REG(ATC2609A_IRQ_OT, 0, ATC2609A_INTS_MSK_OT),
0088 REGMAP_IRQ_REG(ATC2609A_IRQ_UV, 0, ATC2609A_INTS_MSK_UV),
0089 REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM, 0, ATC2609A_INTS_MSK_ALARM),
0090 REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF, 0, ATC2609A_INTS_MSK_ONOFF),
0091 REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP, 0, ATC2609A_INTS_MSK_WKUP),
0092 REGMAP_IRQ_REG(ATC2609A_IRQ_IR, 0, ATC2609A_INTS_MSK_IR),
0093 REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON, 0, ATC2609A_INTS_MSK_REMCON),
0094 REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN, 0, ATC2609A_INTS_MSK_POWERIN),
0095 };
0096
0097 static const struct regmap_irq_chip atc2603c_regmap_irq_chip = {
0098 .name = "atc2603c",
0099 .irqs = atc2603c_regmap_irqs,
0100 .num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs),
0101 .num_regs = 1,
0102 .status_base = ATC2603C_INTS_PD,
0103 .mask_base = ATC2603C_INTS_MSK,
0104 .mask_invert = true,
0105 };
0106
0107 static const struct regmap_irq_chip atc2609a_regmap_irq_chip = {
0108 .name = "atc2609a",
0109 .irqs = atc2609a_regmap_irqs,
0110 .num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs),
0111 .num_regs = 1,
0112 .status_base = ATC2609A_INTS_PD,
0113 .mask_base = ATC2609A_INTS_MSK,
0114 .mask_invert = true,
0115 };
0116
0117 static const struct resource atc2603c_onkey_resources[] = {
0118 DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF),
0119 };
0120
0121 static const struct resource atc2609a_onkey_resources[] = {
0122 DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF),
0123 };
0124
0125 static const struct mfd_cell atc2603c_mfd_cells[] = {
0126 { .name = "atc260x-regulator" },
0127 { .name = "atc260x-pwrc" },
0128 {
0129 .name = "atc260x-onkey",
0130 .num_resources = ARRAY_SIZE(atc2603c_onkey_resources),
0131 .resources = atc2603c_onkey_resources,
0132 },
0133 };
0134
0135 static const struct mfd_cell atc2609a_mfd_cells[] = {
0136 { .name = "atc260x-regulator" },
0137 { .name = "atc260x-pwrc" },
0138 {
0139 .name = "atc260x-onkey",
0140 .num_resources = ARRAY_SIZE(atc2609a_onkey_resources),
0141 .resources = atc2609a_onkey_resources,
0142 },
0143 };
0144
0145 static const struct atc260x_init_regs atc2603c_init_regs = {
0146 .cmu_devrst = ATC2603C_CMU_DEVRST,
0147 .cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS,
0148 .ints_msk = ATC2603C_INTS_MSK,
0149 .pad_en = ATC2603C_PAD_EN,
0150 .pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ,
0151 };
0152
0153 static const struct atc260x_init_regs atc2609a_init_regs = {
0154 .cmu_devrst = ATC2609A_CMU_DEVRST,
0155 .cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS,
0156 .ints_msk = ATC2609A_INTS_MSK,
0157 .pad_en = ATC2609A_PAD_EN,
0158 .pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ,
0159 };
0160
0161 static void atc260x_cmu_reset(struct atc260x *atc260x)
0162 {
0163 const struct atc260x_init_regs *regs = atc260x->init_regs;
0164
0165
0166 regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
0167 regs->cmu_devrst_ints, ~regs->cmu_devrst_ints);
0168
0169
0170 regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
0171 regs->cmu_devrst_ints, regs->cmu_devrst_ints);
0172 }
0173
0174 static void atc260x_dev_init(struct atc260x *atc260x)
0175 {
0176 const struct atc260x_init_regs *regs = atc260x->init_regs;
0177
0178
0179 atc260x_cmu_reset(atc260x);
0180
0181
0182 regmap_write(atc260x->regmap, regs->ints_msk, 0);
0183
0184
0185 regmap_update_bits(atc260x->regmap, regs->pad_en,
0186 regs->pad_en_extirq, regs->pad_en_extirq);
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg)
0199 {
0200 struct device *dev = atc260x->dev;
0201 const void *of_data;
0202
0203 of_data = of_device_get_match_data(dev);
0204 if (!of_data)
0205 return -ENODEV;
0206
0207 atc260x->ic_type = (unsigned long)of_data;
0208
0209 switch (atc260x->ic_type) {
0210 case ATC2603C:
0211 *regmap_cfg = atc2603c_regmap_config;
0212 atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip;
0213 atc260x->cells = atc2603c_mfd_cells;
0214 atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells);
0215 atc260x->type_name = "atc2603c";
0216 atc260x->rev_reg = ATC2603C_CHIP_VER;
0217 atc260x->init_regs = &atc2603c_init_regs;
0218 break;
0219 case ATC2609A:
0220 *regmap_cfg = atc2609a_regmap_config;
0221 atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip;
0222 atc260x->cells = atc2609a_mfd_cells;
0223 atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells);
0224 atc260x->type_name = "atc2609a";
0225 atc260x->rev_reg = ATC2609A_CHIP_VER;
0226 atc260x->init_regs = &atc2609a_init_regs;
0227 break;
0228 default:
0229 dev_err(dev, "Unsupported ATC260x device type: %u\n",
0230 atc260x->ic_type);
0231 return -EINVAL;
0232 }
0233
0234 atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex),
0235 GFP_KERNEL);
0236 if (!atc260x->regmap_mutex)
0237 return -ENOMEM;
0238
0239 mutex_init(atc260x->regmap_mutex);
0240
0241 regmap_cfg->lock = regmap_lock_mutex,
0242 regmap_cfg->unlock = regmap_unlock_mutex,
0243 regmap_cfg->lock_arg = atc260x->regmap_mutex;
0244
0245 return 0;
0246 }
0247 EXPORT_SYMBOL_GPL(atc260x_match_device);
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 int atc260x_device_probe(struct atc260x *atc260x)
0259 {
0260 struct device *dev = atc260x->dev;
0261 unsigned int chip_rev;
0262 int ret;
0263
0264 if (!atc260x->irq) {
0265 dev_err(dev, "No interrupt support\n");
0266 return -EINVAL;
0267 }
0268
0269
0270 atc260x_dev_init(atc260x);
0271
0272 ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev);
0273 if (ret) {
0274 dev_err(dev, "Failed to get chip revision\n");
0275 return ret;
0276 }
0277
0278 if (chip_rev > ATC260X_CHIP_REV_MAX) {
0279 dev_err(dev, "Unknown chip revision: %u\n", chip_rev);
0280 return -EINVAL;
0281 }
0282
0283 atc260x->ic_ver = __ffs(chip_rev + 1U);
0284
0285 dev_info(dev, "Detected chip type %s rev.%c\n",
0286 atc260x->type_name, 'A' + atc260x->ic_ver);
0287
0288 ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT,
0289 -1, atc260x->regmap_irq_chip, &atc260x->irq_data);
0290 if (ret) {
0291 dev_err(dev, "Failed to add IRQ chip: %d\n", ret);
0292 return ret;
0293 }
0294
0295 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0296 atc260x->cells, atc260x->nr_cells, NULL, 0,
0297 regmap_irq_get_domain(atc260x->irq_data));
0298 if (ret) {
0299 dev_err(dev, "Failed to add child devices: %d\n", ret);
0300 regmap_del_irq_chip(atc260x->irq, atc260x->irq_data);
0301 }
0302
0303 return ret;
0304 }
0305 EXPORT_SYMBOL_GPL(atc260x_device_probe);
0306
0307 MODULE_DESCRIPTION("ATC260x PMICs Core support");
0308 MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
0309 MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
0310 MODULE_LICENSE("GPL");