313 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2022 Richtek Technology Corp.4 *5 * Author: ChiYuan Huang <cy_huang@richtek.com>6 */7 8#include <linux/bits.h>9#include <linux/bitfield.h>10#include <linux/i2c.h>11#include <linux/interrupt.h>12#include <linux/kernel.h>13#include <linux/mfd/core.h>14#include <linux/module.h>15#include <linux/regmap.h>16 17#include "mt6370.h"18 19#define MT6370_REG_DEV_INFO 0x10020#define MT6370_REG_CHG_IRQ1 0x1C021#define MT6370_REG_CHG_MASK1 0x1E022#define MT6370_REG_MAXADDR 0x1FF23 24#define MT6370_VENID_MASK GENMASK(7, 4)25 26#define MT6370_NUM_IRQREGS 1627#define MT6370_USBC_I2CADDR 0x4E28#define MT6370_MAX_ADDRLEN 229 30#define MT6370_VENID_RT5081 0x831#define MT6370_VENID_RT5081A 0xA32#define MT6370_VENID_MT6370 0xE33#define MT6370_VENID_MT6371 0xF34#define MT6370_VENID_MT6372P 0x935#define MT6370_VENID_MT6372CP 0xB36 37static const struct regmap_irq mt6370_irqs[] = {38 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8),39 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8),40 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8),41 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8),42 REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8),43 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8),44 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8),45 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8),46 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8),47 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8),48 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8),49 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8),50 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8),51 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8),52 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8),53 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8),54 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8),55 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8),56 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8),57 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8),58 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8),59 REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8),60 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8),61 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8),62 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8),63 REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8),64 REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8),65 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8),66 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8),67 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8),68 REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8),69 REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8),70 REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8),71 REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8),72 REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8),73 REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8),74 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8),75 REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8),76 REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8),77 REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8),78 REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8),79 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8),80 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8),81 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8),82 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8),83 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8),84 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8),85 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8),86 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8),87 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8),88 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8),89 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8),90 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8),91 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8),92 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8),93 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8),94 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8),95 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8),96 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8),97 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8),98 REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8),99 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8),100 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8),101 REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8),102 REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8),103 REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8),104 REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8),105 REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8),106 REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8),107 REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8),108 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8),109 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8),110 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8),111 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8),112 REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8),113};114 115static const struct regmap_irq_chip mt6370_irq_chip = {116 .name = "mt6370-irqs",117 .status_base = MT6370_REG_CHG_IRQ1,118 .mask_base = MT6370_REG_CHG_MASK1,119 .num_regs = MT6370_NUM_IRQREGS,120 .irqs = mt6370_irqs,121 .num_irqs = ARRAY_SIZE(mt6370_irqs),122};123 124static const struct resource mt6370_regulator_irqs[] = {125 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"),126 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"),127 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"),128 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"),129 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"),130 DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"),131};132 133static const struct mfd_cell mt6370_devices[] = {134 MFD_CELL_OF("mt6370-adc",135 NULL, NULL, 0, 0, "mediatek,mt6370-adc"),136 MFD_CELL_OF("mt6370-charger",137 NULL, NULL, 0, 0, "mediatek,mt6370-charger"),138 MFD_CELL_OF("mt6370-flashlight",139 NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"),140 MFD_CELL_OF("mt6370-indicator",141 NULL, NULL, 0, 0, "mediatek,mt6370-indicator"),142 MFD_CELL_OF("mt6370-tcpc",143 NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"),144 MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs),145};146 147static const struct mfd_cell mt6370_exclusive_devices[] = {148 MFD_CELL_OF("mt6370-backlight",149 NULL, NULL, 0, 0, "mediatek,mt6370-backlight"),150};151 152static const struct mfd_cell mt6372_exclusive_devices[] = {153 MFD_CELL_OF("mt6370-backlight",154 NULL, NULL, 0, 0, "mediatek,mt6372-backlight"),155};156 157static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap,158 int *vid)159{160 unsigned int devinfo;161 int ret;162 163 ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo);164 if (ret)165 return ret;166 167 *vid = FIELD_GET(MT6370_VENID_MASK, devinfo);168 switch (*vid) {169 case MT6370_VENID_RT5081:170 case MT6370_VENID_RT5081A:171 case MT6370_VENID_MT6370:172 case MT6370_VENID_MT6371:173 case MT6370_VENID_MT6372P:174 case MT6370_VENID_MT6372CP:175 return 0;176 default:177 dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo);178 return -ENODEV;179 }180}181 182static int mt6370_regmap_read(void *context, const void *reg_buf,183 size_t reg_size, void *val_buf, size_t val_size)184{185 struct mt6370_info *info = context;186 const u8 *u8_buf = reg_buf;187 u8 bank_idx, bank_addr;188 int ret;189 190 bank_idx = u8_buf[0];191 bank_addr = u8_buf[1];192 193 ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr,194 val_size, val_buf);195 if (ret < 0)196 return ret;197 198 if (ret != val_size)199 return -EIO;200 201 return 0;202}203 204static int mt6370_regmap_write(void *context, const void *data, size_t count)205{206 struct mt6370_info *info = context;207 const u8 *u8_buf = data;208 u8 bank_idx, bank_addr;209 int len = count - MT6370_MAX_ADDRLEN;210 211 bank_idx = u8_buf[0];212 bank_addr = u8_buf[1];213 214 return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr,215 len, data + MT6370_MAX_ADDRLEN);216}217 218static const struct regmap_bus mt6370_regmap_bus = {219 .read = mt6370_regmap_read,220 .write = mt6370_regmap_write,221};222 223static const struct regmap_config mt6370_regmap_config = {224 .reg_bits = 16,225 .val_bits = 8,226 .reg_format_endian = REGMAP_ENDIAN_BIG,227 .max_register = MT6370_REG_MAXADDR,228};229 230static int mt6370_probe(struct i2c_client *i2c)231{232 struct mt6370_info *info;233 struct i2c_client *usbc_i2c;234 struct regmap *regmap;235 struct device *dev = &i2c->dev;236 int ret, vid;237 238 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);239 if (!info)240 return -ENOMEM;241 242 usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter,243 MT6370_USBC_I2CADDR);244 if (IS_ERR(usbc_i2c))245 return dev_err_probe(dev, PTR_ERR(usbc_i2c),246 "Failed to register USBC I2C client\n");247 248 /* Assign I2C client for PMU and TypeC */249 info->i2c[MT6370_PMU_I2C] = i2c;250 info->i2c[MT6370_USBC_I2C] = usbc_i2c;251 252 regmap = devm_regmap_init(dev, &mt6370_regmap_bus,253 info, &mt6370_regmap_config);254 if (IS_ERR(regmap))255 return dev_err_probe(dev, PTR_ERR(regmap),256 "Failed to init regmap\n");257 258 ret = mt6370_check_vendor_info(dev, regmap, &vid);259 if (ret)260 return dev_err_probe(dev, ret, "Failed to check vendor info\n");261 262 ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,263 IRQF_ONESHOT, -1, &mt6370_irq_chip,264 &info->irq_data);265 if (ret)266 return dev_err_probe(dev, ret, "Failed to add irq chip\n");267 268 switch (vid) {269 case MT6370_VENID_MT6372P:270 case MT6370_VENID_MT6372CP:271 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,272 mt6372_exclusive_devices,273 ARRAY_SIZE(mt6372_exclusive_devices),274 NULL, 0,275 regmap_irq_get_domain(info->irq_data));276 break;277 default:278 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,279 mt6370_exclusive_devices,280 ARRAY_SIZE(mt6370_exclusive_devices),281 NULL, 0,282 regmap_irq_get_domain(info->irq_data));283 break;284 }285 286 if (ret)287 return dev_err_probe(dev, ret, "Failed to add the exclusive devices\n");288 289 return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,290 mt6370_devices, ARRAY_SIZE(mt6370_devices),291 NULL, 0,292 regmap_irq_get_domain(info->irq_data));293}294 295static const struct of_device_id mt6370_match_table[] = {296 { .compatible = "mediatek,mt6370" },297 {}298};299MODULE_DEVICE_TABLE(of, mt6370_match_table);300 301static struct i2c_driver mt6370_driver = {302 .driver = {303 .name = "mt6370",304 .of_match_table = mt6370_match_table,305 },306 .probe = mt6370_probe,307};308module_i2c_driver(mt6370_driver);309 310MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");311MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver");312MODULE_LICENSE("GPL v2");313