19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 225ca4ae4SBaolin Wang /* 325ca4ae4SBaolin Wang * Copyright (C) 2017 Spreadtrum Communications Inc. 425ca4ae4SBaolin Wang */ 525ca4ae4SBaolin Wang 625ca4ae4SBaolin Wang #include <linux/interrupt.h> 725ca4ae4SBaolin Wang #include <linux/kernel.h> 825ca4ae4SBaolin Wang #include <linux/module.h> 925ca4ae4SBaolin Wang #include <linux/mfd/core.h> 103d4a8757SLee Jones #include <linux/mfd/sc27xx-pmic.h> 1125ca4ae4SBaolin Wang #include <linux/of_device.h> 12c61e1658SChunyan Zhang #include <linux/of_platform.h> 1325ca4ae4SBaolin Wang #include <linux/regmap.h> 1425ca4ae4SBaolin Wang #include <linux/spi/spi.h> 152a7e7274SBaolin Wang #include <uapi/linux/usb/charger.h> 1625ca4ae4SBaolin Wang 1725ca4ae4SBaolin Wang #define SPRD_PMIC_INT_MASK_STATUS 0x0 1825ca4ae4SBaolin Wang #define SPRD_PMIC_INT_RAW_STATUS 0x4 1925ca4ae4SBaolin Wang #define SPRD_PMIC_INT_EN 0x8 2025ca4ae4SBaolin Wang 21fcd8d92fSChunyan Zhang #define SPRD_SC2730_IRQ_BASE 0x80 22fcd8d92fSChunyan Zhang #define SPRD_SC2730_IRQ_NUMS 10 23fcd8d92fSChunyan Zhang #define SPRD_SC2730_CHG_DET 0x1b9c 2425ca4ae4SBaolin Wang #define SPRD_SC2731_IRQ_BASE 0x140 2525ca4ae4SBaolin Wang #define SPRD_SC2731_IRQ_NUMS 16 262a7e7274SBaolin Wang #define SPRD_SC2731_CHG_DET 0xedc 272a7e7274SBaolin Wang 282a7e7274SBaolin Wang /* PMIC charger detection definition */ 292a7e7274SBaolin Wang #define SPRD_PMIC_CHG_DET_DELAY_US 200000 302a7e7274SBaolin Wang #define SPRD_PMIC_CHG_DET_TIMEOUT 2000000 312a7e7274SBaolin Wang #define SPRD_PMIC_CHG_DET_DONE BIT(11) 322a7e7274SBaolin Wang #define SPRD_PMIC_SDP_TYPE BIT(7) 332a7e7274SBaolin Wang #define SPRD_PMIC_DCP_TYPE BIT(6) 342a7e7274SBaolin Wang #define SPRD_PMIC_CDP_TYPE BIT(5) 352a7e7274SBaolin Wang #define SPRD_PMIC_CHG_TYPE_MASK GENMASK(7, 5) 3625ca4ae4SBaolin Wang 3725ca4ae4SBaolin Wang struct sprd_pmic { 3825ca4ae4SBaolin Wang struct regmap *regmap; 3925ca4ae4SBaolin Wang struct device *dev; 4025ca4ae4SBaolin Wang struct regmap_irq *irqs; 4125ca4ae4SBaolin Wang struct regmap_irq_chip irq_chip; 4225ca4ae4SBaolin Wang struct regmap_irq_chip_data *irq_data; 432a7e7274SBaolin Wang const struct sprd_pmic_data *pdata; 4425ca4ae4SBaolin Wang int irq; 4525ca4ae4SBaolin Wang }; 4625ca4ae4SBaolin Wang 4725ca4ae4SBaolin Wang struct sprd_pmic_data { 4825ca4ae4SBaolin Wang u32 irq_base; 4925ca4ae4SBaolin Wang u32 num_irqs; 502a7e7274SBaolin Wang u32 charger_det; 5125ca4ae4SBaolin Wang }; 5225ca4ae4SBaolin Wang 5325ca4ae4SBaolin Wang /* 5425ca4ae4SBaolin Wang * Since different PMICs of SC27xx series can have different interrupt 5525ca4ae4SBaolin Wang * base address and irq number, we should save irq number and irq base 5625ca4ae4SBaolin Wang * in the device data structure. 5725ca4ae4SBaolin Wang */ 58fcd8d92fSChunyan Zhang static const struct sprd_pmic_data sc2730_data = { 59fcd8d92fSChunyan Zhang .irq_base = SPRD_SC2730_IRQ_BASE, 60fcd8d92fSChunyan Zhang .num_irqs = SPRD_SC2730_IRQ_NUMS, 61fcd8d92fSChunyan Zhang .charger_det = SPRD_SC2730_CHG_DET, 62fcd8d92fSChunyan Zhang }; 63fcd8d92fSChunyan Zhang 6425ca4ae4SBaolin Wang static const struct sprd_pmic_data sc2731_data = { 6525ca4ae4SBaolin Wang .irq_base = SPRD_SC2731_IRQ_BASE, 6625ca4ae4SBaolin Wang .num_irqs = SPRD_SC2731_IRQ_NUMS, 672a7e7274SBaolin Wang .charger_det = SPRD_SC2731_CHG_DET, 6825ca4ae4SBaolin Wang }; 6925ca4ae4SBaolin Wang 702a7e7274SBaolin Wang enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev) 712a7e7274SBaolin Wang { 722a7e7274SBaolin Wang struct spi_device *spi = to_spi_device(dev); 732a7e7274SBaolin Wang struct sprd_pmic *ddata = spi_get_drvdata(spi); 742a7e7274SBaolin Wang const struct sprd_pmic_data *pdata = ddata->pdata; 752a7e7274SBaolin Wang enum usb_charger_type type; 762a7e7274SBaolin Wang u32 val; 772a7e7274SBaolin Wang int ret; 782a7e7274SBaolin Wang 792a7e7274SBaolin Wang ret = regmap_read_poll_timeout(ddata->regmap, pdata->charger_det, val, 802a7e7274SBaolin Wang (val & SPRD_PMIC_CHG_DET_DONE), 812a7e7274SBaolin Wang SPRD_PMIC_CHG_DET_DELAY_US, 822a7e7274SBaolin Wang SPRD_PMIC_CHG_DET_TIMEOUT); 832a7e7274SBaolin Wang if (ret) { 842a7e7274SBaolin Wang dev_err(&spi->dev, "failed to detect charger type\n"); 852a7e7274SBaolin Wang return UNKNOWN_TYPE; 862a7e7274SBaolin Wang } 872a7e7274SBaolin Wang 882a7e7274SBaolin Wang switch (val & SPRD_PMIC_CHG_TYPE_MASK) { 892a7e7274SBaolin Wang case SPRD_PMIC_CDP_TYPE: 902a7e7274SBaolin Wang type = CDP_TYPE; 912a7e7274SBaolin Wang break; 922a7e7274SBaolin Wang case SPRD_PMIC_DCP_TYPE: 932a7e7274SBaolin Wang type = DCP_TYPE; 942a7e7274SBaolin Wang break; 952a7e7274SBaolin Wang case SPRD_PMIC_SDP_TYPE: 962a7e7274SBaolin Wang type = SDP_TYPE; 972a7e7274SBaolin Wang break; 982a7e7274SBaolin Wang default: 992a7e7274SBaolin Wang type = UNKNOWN_TYPE; 1002a7e7274SBaolin Wang break; 1012a7e7274SBaolin Wang } 1022a7e7274SBaolin Wang 1032a7e7274SBaolin Wang return type; 1042a7e7274SBaolin Wang } 1052a7e7274SBaolin Wang EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type); 1062a7e7274SBaolin Wang 10725ca4ae4SBaolin Wang static int sprd_pmic_spi_write(void *context, const void *data, size_t count) 10825ca4ae4SBaolin Wang { 10925ca4ae4SBaolin Wang struct device *dev = context; 11025ca4ae4SBaolin Wang struct spi_device *spi = to_spi_device(dev); 11125ca4ae4SBaolin Wang 11225ca4ae4SBaolin Wang return spi_write(spi, data, count); 11325ca4ae4SBaolin Wang } 11425ca4ae4SBaolin Wang 11525ca4ae4SBaolin Wang static int sprd_pmic_spi_read(void *context, 11625ca4ae4SBaolin Wang const void *reg, size_t reg_size, 11725ca4ae4SBaolin Wang void *val, size_t val_size) 11825ca4ae4SBaolin Wang { 11925ca4ae4SBaolin Wang struct device *dev = context; 12025ca4ae4SBaolin Wang struct spi_device *spi = to_spi_device(dev); 12125ca4ae4SBaolin Wang u32 rx_buf[2] = { 0 }; 12225ca4ae4SBaolin Wang int ret; 12325ca4ae4SBaolin Wang 12425ca4ae4SBaolin Wang /* Now we only support one PMIC register to read every time. */ 12525ca4ae4SBaolin Wang if (reg_size != sizeof(u32) || val_size != sizeof(u32)) 12625ca4ae4SBaolin Wang return -EINVAL; 12725ca4ae4SBaolin Wang 12825ca4ae4SBaolin Wang /* Copy address to read from into first element of SPI buffer. */ 12925ca4ae4SBaolin Wang memcpy(rx_buf, reg, sizeof(u32)); 13025ca4ae4SBaolin Wang ret = spi_read(spi, rx_buf, 1); 13125ca4ae4SBaolin Wang if (ret < 0) 13225ca4ae4SBaolin Wang return ret; 13325ca4ae4SBaolin Wang 13425ca4ae4SBaolin Wang memcpy(val, rx_buf, val_size); 13525ca4ae4SBaolin Wang return 0; 13625ca4ae4SBaolin Wang } 13725ca4ae4SBaolin Wang 13825ca4ae4SBaolin Wang static struct regmap_bus sprd_pmic_regmap = { 13925ca4ae4SBaolin Wang .write = sprd_pmic_spi_write, 14025ca4ae4SBaolin Wang .read = sprd_pmic_spi_read, 14125ca4ae4SBaolin Wang .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 14225ca4ae4SBaolin Wang .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 14325ca4ae4SBaolin Wang }; 14425ca4ae4SBaolin Wang 14525ca4ae4SBaolin Wang static const struct regmap_config sprd_pmic_config = { 14625ca4ae4SBaolin Wang .reg_bits = 32, 14725ca4ae4SBaolin Wang .val_bits = 32, 14825ca4ae4SBaolin Wang .reg_stride = 4, 14925ca4ae4SBaolin Wang .max_register = 0xffff, 15025ca4ae4SBaolin Wang }; 15125ca4ae4SBaolin Wang 15225ca4ae4SBaolin Wang static int sprd_pmic_probe(struct spi_device *spi) 15325ca4ae4SBaolin Wang { 15425ca4ae4SBaolin Wang struct sprd_pmic *ddata; 15525ca4ae4SBaolin Wang const struct sprd_pmic_data *pdata; 15625ca4ae4SBaolin Wang int ret, i; 15725ca4ae4SBaolin Wang 15825ca4ae4SBaolin Wang pdata = of_device_get_match_data(&spi->dev); 15925ca4ae4SBaolin Wang if (!pdata) { 16025ca4ae4SBaolin Wang dev_err(&spi->dev, "No matching driver data found\n"); 16125ca4ae4SBaolin Wang return -EINVAL; 16225ca4ae4SBaolin Wang } 16325ca4ae4SBaolin Wang 16425ca4ae4SBaolin Wang ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); 16525ca4ae4SBaolin Wang if (!ddata) 16625ca4ae4SBaolin Wang return -ENOMEM; 16725ca4ae4SBaolin Wang 16825ca4ae4SBaolin Wang ddata->regmap = devm_regmap_init(&spi->dev, &sprd_pmic_regmap, 16925ca4ae4SBaolin Wang &spi->dev, &sprd_pmic_config); 17025ca4ae4SBaolin Wang if (IS_ERR(ddata->regmap)) { 17125ca4ae4SBaolin Wang ret = PTR_ERR(ddata->regmap); 17225ca4ae4SBaolin Wang dev_err(&spi->dev, "Failed to allocate register map %d\n", ret); 17325ca4ae4SBaolin Wang return ret; 17425ca4ae4SBaolin Wang } 17525ca4ae4SBaolin Wang 17625ca4ae4SBaolin Wang spi_set_drvdata(spi, ddata); 17725ca4ae4SBaolin Wang ddata->dev = &spi->dev; 17825ca4ae4SBaolin Wang ddata->irq = spi->irq; 1792a7e7274SBaolin Wang ddata->pdata = pdata; 18025ca4ae4SBaolin Wang 18125ca4ae4SBaolin Wang ddata->irq_chip.name = dev_name(&spi->dev); 18225ca4ae4SBaolin Wang ddata->irq_chip.status_base = 18325ca4ae4SBaolin Wang pdata->irq_base + SPRD_PMIC_INT_MASK_STATUS; 18425ca4ae4SBaolin Wang ddata->irq_chip.mask_base = pdata->irq_base + SPRD_PMIC_INT_EN; 18525ca4ae4SBaolin Wang ddata->irq_chip.ack_base = 0; 18625ca4ae4SBaolin Wang ddata->irq_chip.num_regs = 1; 18725ca4ae4SBaolin Wang ddata->irq_chip.num_irqs = pdata->num_irqs; 18825ca4ae4SBaolin Wang ddata->irq_chip.mask_invert = true; 18925ca4ae4SBaolin Wang 190a86854d0SKees Cook ddata->irqs = devm_kcalloc(&spi->dev, 191a86854d0SKees Cook pdata->num_irqs, sizeof(struct regmap_irq), 192a86854d0SKees Cook GFP_KERNEL); 19325ca4ae4SBaolin Wang if (!ddata->irqs) 19425ca4ae4SBaolin Wang return -ENOMEM; 19525ca4ae4SBaolin Wang 19625ca4ae4SBaolin Wang ddata->irq_chip.irqs = ddata->irqs; 197ec46855dSLee Jones for (i = 0; i < pdata->num_irqs; i++) 198ec46855dSLee Jones ddata->irqs[i].mask = BIT(i); 19925ca4ae4SBaolin Wang 20025ca4ae4SBaolin Wang ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq, 201a75bfc82SBaolin Wang IRQF_ONESHOT, 0, 20225ca4ae4SBaolin Wang &ddata->irq_chip, &ddata->irq_data); 20325ca4ae4SBaolin Wang if (ret) { 20425ca4ae4SBaolin Wang dev_err(&spi->dev, "Failed to add PMIC irq chip %d\n", ret); 20525ca4ae4SBaolin Wang return ret; 20625ca4ae4SBaolin Wang } 20725ca4ae4SBaolin Wang 208c61e1658SChunyan Zhang ret = devm_of_platform_populate(&spi->dev); 20925ca4ae4SBaolin Wang if (ret) { 210c61e1658SChunyan Zhang dev_err(&spi->dev, "Failed to populate sub-devices %d\n", ret); 21125ca4ae4SBaolin Wang return ret; 21225ca4ae4SBaolin Wang } 21325ca4ae4SBaolin Wang 214a75bfc82SBaolin Wang device_init_wakeup(&spi->dev, true); 21525ca4ae4SBaolin Wang return 0; 21625ca4ae4SBaolin Wang } 21725ca4ae4SBaolin Wang 218a75bfc82SBaolin Wang #ifdef CONFIG_PM_SLEEP 219a75bfc82SBaolin Wang static int sprd_pmic_suspend(struct device *dev) 220a75bfc82SBaolin Wang { 221a75bfc82SBaolin Wang struct sprd_pmic *ddata = dev_get_drvdata(dev); 222a75bfc82SBaolin Wang 223a75bfc82SBaolin Wang if (device_may_wakeup(dev)) 224a75bfc82SBaolin Wang enable_irq_wake(ddata->irq); 225a75bfc82SBaolin Wang 226a75bfc82SBaolin Wang return 0; 227a75bfc82SBaolin Wang } 228a75bfc82SBaolin Wang 229a75bfc82SBaolin Wang static int sprd_pmic_resume(struct device *dev) 230a75bfc82SBaolin Wang { 231a75bfc82SBaolin Wang struct sprd_pmic *ddata = dev_get_drvdata(dev); 232a75bfc82SBaolin Wang 233a75bfc82SBaolin Wang if (device_may_wakeup(dev)) 234a75bfc82SBaolin Wang disable_irq_wake(ddata->irq); 235a75bfc82SBaolin Wang 236a75bfc82SBaolin Wang return 0; 237a75bfc82SBaolin Wang } 238a75bfc82SBaolin Wang #endif 239a75bfc82SBaolin Wang 240a75bfc82SBaolin Wang static SIMPLE_DEV_PM_OPS(sprd_pmic_pm_ops, sprd_pmic_suspend, sprd_pmic_resume); 241a75bfc82SBaolin Wang 24225ca4ae4SBaolin Wang static const struct of_device_id sprd_pmic_match[] = { 24325ca4ae4SBaolin Wang { .compatible = "sprd,sc2731", .data = &sc2731_data }, 244fcd8d92fSChunyan Zhang { .compatible = "sprd,sc2730", .data = &sc2730_data }, 24525ca4ae4SBaolin Wang {}, 24625ca4ae4SBaolin Wang }; 24725ca4ae4SBaolin Wang MODULE_DEVICE_TABLE(of, sprd_pmic_match); 24825ca4ae4SBaolin Wang 249*c5c7f067SMark Brown static const struct spi_device_id sprd_pmic_spi_ids[] = { 250*c5c7f067SMark Brown { .name = "sc2731", .driver_data = (unsigned long)&sc2731_data }, 251*c5c7f067SMark Brown {}, 252*c5c7f067SMark Brown }; 253*c5c7f067SMark Brown MODULE_DEVICE_TABLE(spi, sprd_pmic_spi_ids); 254*c5c7f067SMark Brown 25525ca4ae4SBaolin Wang static struct spi_driver sprd_pmic_driver = { 25625ca4ae4SBaolin Wang .driver = { 25725ca4ae4SBaolin Wang .name = "sc27xx-pmic", 25825ca4ae4SBaolin Wang .of_match_table = sprd_pmic_match, 259a75bfc82SBaolin Wang .pm = &sprd_pmic_pm_ops, 26025ca4ae4SBaolin Wang }, 26125ca4ae4SBaolin Wang .probe = sprd_pmic_probe, 262*c5c7f067SMark Brown .id_table = sprd_pmic_spi_ids, 26325ca4ae4SBaolin Wang }; 26425ca4ae4SBaolin Wang 26525ca4ae4SBaolin Wang static int __init sprd_pmic_init(void) 26625ca4ae4SBaolin Wang { 26725ca4ae4SBaolin Wang return spi_register_driver(&sprd_pmic_driver); 26825ca4ae4SBaolin Wang } 26925ca4ae4SBaolin Wang subsys_initcall(sprd_pmic_init); 27025ca4ae4SBaolin Wang 27125ca4ae4SBaolin Wang static void __exit sprd_pmic_exit(void) 27225ca4ae4SBaolin Wang { 27325ca4ae4SBaolin Wang spi_unregister_driver(&sprd_pmic_driver); 27425ca4ae4SBaolin Wang } 27525ca4ae4SBaolin Wang module_exit(sprd_pmic_exit); 27625ca4ae4SBaolin Wang 27725ca4ae4SBaolin Wang MODULE_LICENSE("GPL v2"); 27825ca4ae4SBaolin Wang MODULE_DESCRIPTION("Spreadtrum SC27xx PMICs driver"); 27925ca4ae4SBaolin Wang MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); 280