125ca4ae4SBaolin Wang /* 225ca4ae4SBaolin Wang * Copyright (C) 2017 Spreadtrum Communications Inc. 325ca4ae4SBaolin Wang * 425ca4ae4SBaolin Wang * This software is licensed under the terms of the GNU General Public 525ca4ae4SBaolin Wang * License version 2, as published by the Free Software Foundation, and 625ca4ae4SBaolin Wang * may be copied, distributed, and modified under those terms. 725ca4ae4SBaolin Wang * 825ca4ae4SBaolin Wang * This program is distributed in the hope that it will be useful, 925ca4ae4SBaolin Wang * but WITHOUT ANY WARRANTY; without even the implied warranty of 1025ca4ae4SBaolin Wang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1125ca4ae4SBaolin Wang * GNU General Public License for more details. 1225ca4ae4SBaolin Wang */ 1325ca4ae4SBaolin Wang 1425ca4ae4SBaolin Wang #include <linux/interrupt.h> 1525ca4ae4SBaolin Wang #include <linux/kernel.h> 1625ca4ae4SBaolin Wang #include <linux/module.h> 1725ca4ae4SBaolin Wang #include <linux/mfd/core.h> 1825ca4ae4SBaolin Wang #include <linux/of_device.h> 1925ca4ae4SBaolin Wang #include <linux/regmap.h> 2025ca4ae4SBaolin Wang #include <linux/spi/spi.h> 2125ca4ae4SBaolin Wang 2225ca4ae4SBaolin Wang #define SPRD_PMIC_INT_MASK_STATUS 0x0 2325ca4ae4SBaolin Wang #define SPRD_PMIC_INT_RAW_STATUS 0x4 2425ca4ae4SBaolin Wang #define SPRD_PMIC_INT_EN 0x8 2525ca4ae4SBaolin Wang 2625ca4ae4SBaolin Wang #define SPRD_SC2731_IRQ_BASE 0x140 2725ca4ae4SBaolin Wang #define SPRD_SC2731_IRQ_NUMS 16 2825ca4ae4SBaolin Wang 2925ca4ae4SBaolin Wang struct sprd_pmic { 3025ca4ae4SBaolin Wang struct regmap *regmap; 3125ca4ae4SBaolin Wang struct device *dev; 3225ca4ae4SBaolin Wang struct regmap_irq *irqs; 3325ca4ae4SBaolin Wang struct regmap_irq_chip irq_chip; 3425ca4ae4SBaolin Wang struct regmap_irq_chip_data *irq_data; 3525ca4ae4SBaolin Wang int irq; 3625ca4ae4SBaolin Wang }; 3725ca4ae4SBaolin Wang 3825ca4ae4SBaolin Wang struct sprd_pmic_data { 3925ca4ae4SBaolin Wang u32 irq_base; 4025ca4ae4SBaolin Wang u32 num_irqs; 4125ca4ae4SBaolin Wang }; 4225ca4ae4SBaolin Wang 4325ca4ae4SBaolin Wang /* 4425ca4ae4SBaolin Wang * Since different PMICs of SC27xx series can have different interrupt 4525ca4ae4SBaolin Wang * base address and irq number, we should save irq number and irq base 4625ca4ae4SBaolin Wang * in the device data structure. 4725ca4ae4SBaolin Wang */ 4825ca4ae4SBaolin Wang static const struct sprd_pmic_data sc2731_data = { 4925ca4ae4SBaolin Wang .irq_base = SPRD_SC2731_IRQ_BASE, 5025ca4ae4SBaolin Wang .num_irqs = SPRD_SC2731_IRQ_NUMS, 5125ca4ae4SBaolin Wang }; 5225ca4ae4SBaolin Wang 5325ca4ae4SBaolin Wang static const struct mfd_cell sprd_pmic_devs[] = { 5425ca4ae4SBaolin Wang { 5525ca4ae4SBaolin Wang .name = "sc27xx-wdt", 5625ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-wdt", 5725ca4ae4SBaolin Wang }, { 5825ca4ae4SBaolin Wang .name = "sc27xx-rtc", 5925ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-rtc", 6025ca4ae4SBaolin Wang }, { 6125ca4ae4SBaolin Wang .name = "sc27xx-charger", 6225ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-charger", 6325ca4ae4SBaolin Wang }, { 6425ca4ae4SBaolin Wang .name = "sc27xx-chg-timer", 6525ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-chg-timer", 6625ca4ae4SBaolin Wang }, { 6725ca4ae4SBaolin Wang .name = "sc27xx-fast-chg", 6825ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-fast-chg", 6925ca4ae4SBaolin Wang }, { 7025ca4ae4SBaolin Wang .name = "sc27xx-chg-wdt", 7125ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-chg-wdt", 7225ca4ae4SBaolin Wang }, { 7325ca4ae4SBaolin Wang .name = "sc27xx-typec", 7425ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-typec", 7525ca4ae4SBaolin Wang }, { 7625ca4ae4SBaolin Wang .name = "sc27xx-flash", 7725ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-flash", 7825ca4ae4SBaolin Wang }, { 7925ca4ae4SBaolin Wang .name = "sc27xx-eic", 8025ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-eic", 8125ca4ae4SBaolin Wang }, { 8225ca4ae4SBaolin Wang .name = "sc27xx-efuse", 8325ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-efuse", 8425ca4ae4SBaolin Wang }, { 8525ca4ae4SBaolin Wang .name = "sc27xx-thermal", 8625ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-thermal", 8725ca4ae4SBaolin Wang }, { 8825ca4ae4SBaolin Wang .name = "sc27xx-adc", 8925ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-adc", 9025ca4ae4SBaolin Wang }, { 9125ca4ae4SBaolin Wang .name = "sc27xx-audio-codec", 9225ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-audio-codec", 9325ca4ae4SBaolin Wang }, { 9425ca4ae4SBaolin Wang .name = "sc27xx-regulator", 9525ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-regulator", 9625ca4ae4SBaolin Wang }, { 9725ca4ae4SBaolin Wang .name = "sc27xx-vibrator", 9825ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-vibrator", 9925ca4ae4SBaolin Wang }, { 10025ca4ae4SBaolin Wang .name = "sc27xx-keypad-led", 10125ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-keypad-led", 10225ca4ae4SBaolin Wang }, { 10325ca4ae4SBaolin Wang .name = "sc27xx-bltc", 10425ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-bltc", 10525ca4ae4SBaolin Wang }, { 10625ca4ae4SBaolin Wang .name = "sc27xx-fgu", 10725ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-fgu", 10825ca4ae4SBaolin Wang }, { 10925ca4ae4SBaolin Wang .name = "sc27xx-7sreset", 11025ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-7sreset", 11125ca4ae4SBaolin Wang }, { 11225ca4ae4SBaolin Wang .name = "sc27xx-poweroff", 11325ca4ae4SBaolin Wang .of_compatible = "sprd,sc27xx-poweroff", 11425ca4ae4SBaolin Wang }, 11525ca4ae4SBaolin Wang }; 11625ca4ae4SBaolin Wang 11725ca4ae4SBaolin Wang static int sprd_pmic_spi_write(void *context, const void *data, size_t count) 11825ca4ae4SBaolin Wang { 11925ca4ae4SBaolin Wang struct device *dev = context; 12025ca4ae4SBaolin Wang struct spi_device *spi = to_spi_device(dev); 12125ca4ae4SBaolin Wang 12225ca4ae4SBaolin Wang return spi_write(spi, data, count); 12325ca4ae4SBaolin Wang } 12425ca4ae4SBaolin Wang 12525ca4ae4SBaolin Wang static int sprd_pmic_spi_read(void *context, 12625ca4ae4SBaolin Wang const void *reg, size_t reg_size, 12725ca4ae4SBaolin Wang void *val, size_t val_size) 12825ca4ae4SBaolin Wang { 12925ca4ae4SBaolin Wang struct device *dev = context; 13025ca4ae4SBaolin Wang struct spi_device *spi = to_spi_device(dev); 13125ca4ae4SBaolin Wang u32 rx_buf[2] = { 0 }; 13225ca4ae4SBaolin Wang int ret; 13325ca4ae4SBaolin Wang 13425ca4ae4SBaolin Wang /* Now we only support one PMIC register to read every time. */ 13525ca4ae4SBaolin Wang if (reg_size != sizeof(u32) || val_size != sizeof(u32)) 13625ca4ae4SBaolin Wang return -EINVAL; 13725ca4ae4SBaolin Wang 13825ca4ae4SBaolin Wang /* Copy address to read from into first element of SPI buffer. */ 13925ca4ae4SBaolin Wang memcpy(rx_buf, reg, sizeof(u32)); 14025ca4ae4SBaolin Wang ret = spi_read(spi, rx_buf, 1); 14125ca4ae4SBaolin Wang if (ret < 0) 14225ca4ae4SBaolin Wang return ret; 14325ca4ae4SBaolin Wang 14425ca4ae4SBaolin Wang memcpy(val, rx_buf, val_size); 14525ca4ae4SBaolin Wang return 0; 14625ca4ae4SBaolin Wang } 14725ca4ae4SBaolin Wang 14825ca4ae4SBaolin Wang static struct regmap_bus sprd_pmic_regmap = { 14925ca4ae4SBaolin Wang .write = sprd_pmic_spi_write, 15025ca4ae4SBaolin Wang .read = sprd_pmic_spi_read, 15125ca4ae4SBaolin Wang .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 15225ca4ae4SBaolin Wang .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 15325ca4ae4SBaolin Wang }; 15425ca4ae4SBaolin Wang 15525ca4ae4SBaolin Wang static const struct regmap_config sprd_pmic_config = { 15625ca4ae4SBaolin Wang .reg_bits = 32, 15725ca4ae4SBaolin Wang .val_bits = 32, 15825ca4ae4SBaolin Wang .reg_stride = 4, 15925ca4ae4SBaolin Wang .max_register = 0xffff, 16025ca4ae4SBaolin Wang }; 16125ca4ae4SBaolin Wang 16225ca4ae4SBaolin Wang static int sprd_pmic_probe(struct spi_device *spi) 16325ca4ae4SBaolin Wang { 16425ca4ae4SBaolin Wang struct sprd_pmic *ddata; 16525ca4ae4SBaolin Wang const struct sprd_pmic_data *pdata; 16625ca4ae4SBaolin Wang int ret, i; 16725ca4ae4SBaolin Wang 16825ca4ae4SBaolin Wang pdata = of_device_get_match_data(&spi->dev); 16925ca4ae4SBaolin Wang if (!pdata) { 17025ca4ae4SBaolin Wang dev_err(&spi->dev, "No matching driver data found\n"); 17125ca4ae4SBaolin Wang return -EINVAL; 17225ca4ae4SBaolin Wang } 17325ca4ae4SBaolin Wang 17425ca4ae4SBaolin Wang ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); 17525ca4ae4SBaolin Wang if (!ddata) 17625ca4ae4SBaolin Wang return -ENOMEM; 17725ca4ae4SBaolin Wang 17825ca4ae4SBaolin Wang ddata->regmap = devm_regmap_init(&spi->dev, &sprd_pmic_regmap, 17925ca4ae4SBaolin Wang &spi->dev, &sprd_pmic_config); 18025ca4ae4SBaolin Wang if (IS_ERR(ddata->regmap)) { 18125ca4ae4SBaolin Wang ret = PTR_ERR(ddata->regmap); 18225ca4ae4SBaolin Wang dev_err(&spi->dev, "Failed to allocate register map %d\n", ret); 18325ca4ae4SBaolin Wang return ret; 18425ca4ae4SBaolin Wang } 18525ca4ae4SBaolin Wang 18625ca4ae4SBaolin Wang spi_set_drvdata(spi, ddata); 18725ca4ae4SBaolin Wang ddata->dev = &spi->dev; 18825ca4ae4SBaolin Wang ddata->irq = spi->irq; 18925ca4ae4SBaolin Wang 19025ca4ae4SBaolin Wang ddata->irq_chip.name = dev_name(&spi->dev); 19125ca4ae4SBaolin Wang ddata->irq_chip.status_base = 19225ca4ae4SBaolin Wang pdata->irq_base + SPRD_PMIC_INT_MASK_STATUS; 19325ca4ae4SBaolin Wang ddata->irq_chip.mask_base = pdata->irq_base + SPRD_PMIC_INT_EN; 19425ca4ae4SBaolin Wang ddata->irq_chip.ack_base = 0; 19525ca4ae4SBaolin Wang ddata->irq_chip.num_regs = 1; 19625ca4ae4SBaolin Wang ddata->irq_chip.num_irqs = pdata->num_irqs; 19725ca4ae4SBaolin Wang ddata->irq_chip.mask_invert = true; 19825ca4ae4SBaolin Wang 19925ca4ae4SBaolin Wang ddata->irqs = devm_kzalloc(&spi->dev, sizeof(struct regmap_irq) * 20025ca4ae4SBaolin Wang pdata->num_irqs, GFP_KERNEL); 20125ca4ae4SBaolin Wang if (!ddata->irqs) 20225ca4ae4SBaolin Wang return -ENOMEM; 20325ca4ae4SBaolin Wang 20425ca4ae4SBaolin Wang ddata->irq_chip.irqs = ddata->irqs; 20525ca4ae4SBaolin Wang for (i = 0; i < pdata->num_irqs; i++) { 20625ca4ae4SBaolin Wang ddata->irqs[i].reg_offset = i / pdata->num_irqs; 20725ca4ae4SBaolin Wang ddata->irqs[i].mask = BIT(i % pdata->num_irqs); 20825ca4ae4SBaolin Wang } 20925ca4ae4SBaolin Wang 21025ca4ae4SBaolin Wang ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq, 21125ca4ae4SBaolin Wang IRQF_ONESHOT | IRQF_NO_SUSPEND, 0, 21225ca4ae4SBaolin Wang &ddata->irq_chip, &ddata->irq_data); 21325ca4ae4SBaolin Wang if (ret) { 21425ca4ae4SBaolin Wang dev_err(&spi->dev, "Failed to add PMIC irq chip %d\n", ret); 21525ca4ae4SBaolin Wang return ret; 21625ca4ae4SBaolin Wang } 21725ca4ae4SBaolin Wang 21825ca4ae4SBaolin Wang ret = devm_mfd_add_devices(&spi->dev, PLATFORM_DEVID_AUTO, 21925ca4ae4SBaolin Wang sprd_pmic_devs, ARRAY_SIZE(sprd_pmic_devs), 22025ca4ae4SBaolin Wang NULL, 0, 22125ca4ae4SBaolin Wang regmap_irq_get_domain(ddata->irq_data)); 22225ca4ae4SBaolin Wang if (ret) { 22325ca4ae4SBaolin Wang dev_err(&spi->dev, "Failed to register device %d\n", ret); 22425ca4ae4SBaolin Wang return ret; 22525ca4ae4SBaolin Wang } 22625ca4ae4SBaolin Wang 22725ca4ae4SBaolin Wang return 0; 22825ca4ae4SBaolin Wang } 22925ca4ae4SBaolin Wang 23025ca4ae4SBaolin Wang static const struct of_device_id sprd_pmic_match[] = { 23125ca4ae4SBaolin Wang { .compatible = "sprd,sc2731", .data = &sc2731_data }, 23225ca4ae4SBaolin Wang {}, 23325ca4ae4SBaolin Wang }; 23425ca4ae4SBaolin Wang MODULE_DEVICE_TABLE(of, sprd_pmic_match); 23525ca4ae4SBaolin Wang 23625ca4ae4SBaolin Wang static struct spi_driver sprd_pmic_driver = { 23725ca4ae4SBaolin Wang .driver = { 23825ca4ae4SBaolin Wang .name = "sc27xx-pmic", 23925ca4ae4SBaolin Wang .bus = &spi_bus_type, 24025ca4ae4SBaolin Wang .of_match_table = sprd_pmic_match, 24125ca4ae4SBaolin Wang }, 24225ca4ae4SBaolin Wang .probe = sprd_pmic_probe, 24325ca4ae4SBaolin Wang }; 24425ca4ae4SBaolin Wang 24525ca4ae4SBaolin Wang static int __init sprd_pmic_init(void) 24625ca4ae4SBaolin Wang { 24725ca4ae4SBaolin Wang return spi_register_driver(&sprd_pmic_driver); 24825ca4ae4SBaolin Wang } 24925ca4ae4SBaolin Wang subsys_initcall(sprd_pmic_init); 25025ca4ae4SBaolin Wang 25125ca4ae4SBaolin Wang static void __exit sprd_pmic_exit(void) 25225ca4ae4SBaolin Wang { 25325ca4ae4SBaolin Wang spi_unregister_driver(&sprd_pmic_driver); 25425ca4ae4SBaolin Wang } 25525ca4ae4SBaolin Wang module_exit(sprd_pmic_exit); 25625ca4ae4SBaolin Wang 25725ca4ae4SBaolin Wang MODULE_LICENSE("GPL v2"); 25825ca4ae4SBaolin Wang MODULE_DESCRIPTION("Spreadtrum SC27xx PMICs driver"); 25925ca4ae4SBaolin Wang MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>"); 260