From patchwork Fri Mar 14 07:32:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?THUgVGFuZyAo5rGk55KQKQ==?= X-Patchwork-Id: 14016374 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 897718632B; Fri, 14 Mar 2025 07:55:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938926; cv=none; b=fJO5fDuVGHdPJTek0Y0kYo8T7F8e92r80SA3zZk7P4ZVHxMzbyjeFyZECu3vlymFyFCSp8EMyTsFXiZTckf4Ae8c77zlAw5swrZFAqC4QHZvnffXBd3pjwC0ZnM4asavrQL9BFIOw6BFps3sCBVKScTulXlu3Z26y2Hyceubbbs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938926; c=relaxed/simple; bh=ZcZE48jeqmu+HkT/CmNXc+BbjK5FYJcxHBRj0H4RB0Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sk/TKOFKxDCao9LnJZmXKc/jQprJ+8/43kndR/sAFBaaaFFmFdTTSyGExG+/zVGaqOAtZShFyt5ocrN9gvLP0Y9RpLiB5wqUFhe7g10w3LoUSpqwKqULkYntKT5zgbB+IV5OUO1lj4ClFcMV2AH3wnvAv3zFp0C2JzPkm+7UOns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=QD+Qt+mO; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="QD+Qt+mO" X-UUID: a88cafd400a911f0aae1fd9735fae912-20250314 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=zzDRu+hb/QXfno0Yz4OFCqUyJDkPo/hMuBDb0U62RbI=; b=QD+Qt+mOfcYqdd1+e0VLeMwMu4v9koYEFMv39NS/Yy0FmTAt1G3XxePxG2a8VepWL8yONjaJy9FIjSnptSJaLed5T+K++9hg/wwKqIMUzbkmzFeEa9MKlb++t5OQP4qHIED+UK9HqFXIgn3WcspcdfevfJfliuPsVTEegLFirZ4=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:463a3d0c-1353-4a50-9d6e-5a6496ac0222,IP:0,UR L:0,TC:0,Content:-5,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:-5 X-CID-META: VersionHash:0ef645f,CLOUDID:0a575e8c-f5b8-47d5-8cf3-b68fe7530c9a,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: a88cafd400a911f0aae1fd9735fae912-20250314 Received: from mtkmbs11n2.mediatek.inc [(172.21.101.187)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1667442372; Fri, 14 Mar 2025 15:55:12 +0800 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 14 Mar 2025 15:55:11 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 14 Mar 2025 15:55:10 +0800 From: Lu.Tang To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dmitry Torokhov , Lee Jones , Matthias Brugger , AngeloGioacchino Del Regno , Sean Wang , Linus Walleij , Liam Girdwood , Mark Brown , Stephen Boyd , Chen Zhong , Sen Chu CC: , , , , , , , , Lu.Tang Subject: [PATCH 1/5] pmic: mediatek: Add pmic auxadc driver Date: Fri, 14 Mar 2025 15:32:27 +0800 Message-ID: <20250314073307.25092-2-Lu.Tang@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250314073307.25092-1-Lu.Tang@mediatek.com> References: <20250314073307.25092-1-Lu.Tang@mediatek.com> Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Lu.Tang" Add pmic mt6363 and mt6373 auxadc driver Signed-off-by: Lu Tang --- drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mtk-spmi-pmic-adc.c | 576 ++++++++++++++++++++++++++++ 3 files changed, 587 insertions(+) create mode 100644 drivers/iio/adc/mtk-spmi-pmic-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 27413516216c..7c4b5f8f7209 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1039,6 +1039,16 @@ config MEDIATEK_MT6577_AUXADC This driver can also be built as a module. If so, the module will be called mt6577_auxadc. +config MEDIATEK_SPMI_PMIC_ADC + tristate "MediaTek SPMI PMIC ADC Support" + depends on MFD_MTK_SPMI_PMIC + help + Say yes here to enable support for MediaTek SPMI PMIC ADC. + The driver supports multiple channels read. + + This driver can also be built as a module. If so, the module will be + called mtk-spmi-pmic-adc. + config MEN_Z188_ADC tristate "MEN 16z188 ADC IP Core support" depends on MCB diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9f26d5eca822..b3224abea040 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o +obj-$(CONFIG_MEDIATEK_SPMI_PMIC_ADC) += mtk-spmi-pmic-adc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o diff --git a/drivers/iio/adc/mtk-spmi-pmic-adc.c b/drivers/iio/adc/mtk-spmi-pmic-adc.c new file mode 100644 index 000000000000..61e062bc8cf5 --- /dev/null +++ b/drivers/iio/adc/mtk-spmi-pmic-adc.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AUXADC_RDY_BIT BIT(15) + +#define AUXADC_DEF_R_RATIO 1 +#define AUXADC_DEF_AVG_NUM 32 + +#define AUXADC_AVG_TIME_US 10 +#define AUXADC_POLL_DELAY_US 100 +#define AUXADC_TIMEOUT_US 32000 +#define VOLT_FULL 1840 + +#define IMP_VOLT_FULL 18400 +#define IMIX_R_MIN_MOHM 100 +#define IMIX_R_CALI_CNT 2 + +#define EXT_THR_PURES_SHIFT 3 +#define EXT_THR_SEL_MASK 0x1F + +#define DT_CHANNEL_CONVERT(val) ((val) & 0xFF) +#define DT_PURES_CONVERT(val) (((val) & 0xFF00) >> 8) + +struct pmic_adc_device { + struct device *dev; + struct regmap *regmap; + struct mutex lock; + struct iio_chan_spec *iio_chans; + unsigned int nchannels; + const struct auxadc_info *info; + struct regulator *isink_load; + int imix_r; + int imp_curr; + int pre_uisoc; +}; + +static struct pmic_adc_device *imix_r_dev; + +/* + * @ch_name: HW channel name + * @res: ADC resolution + * @r_ratio: resistance ratio, represented by r_ratio[0] / r_ratio[1] + * @avg_num: sampling times of AUXADC measurements then average it + * @regs: request and data output registers for this channel + */ +struct auxadc_channels { + enum iio_chan_type type; + long info_mask; + /* AUXADC channel attribute */ + const char *ch_name; + unsigned char res; + unsigned char r_ratio[2]; + unsigned short avg_num; + const struct auxadc_regs *regs; +}; + +#define AUXADC_CHANNEL(_ch_name, _res) \ + [AUXADC_##_ch_name] = { \ + .type = IIO_VOLTAGE, \ + .info_mask = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED), \ + .ch_name = __stringify(_ch_name), \ + .res = _res, \ + } + +/* + * The array represents all possible AUXADC channels found + * in the supported PMICs. + */ +static struct auxadc_channels auxadc_chans[] = { + AUXADC_CHANNEL(BATADC, 15), + AUXADC_CHANNEL(VCDT, 12), + AUXADC_CHANNEL(BAT_TEMP, 12), + AUXADC_CHANNEL(CHIP_TEMP, 12), + AUXADC_CHANNEL(VCORE_TEMP, 12), + AUXADC_CHANNEL(VPROC_TEMP, 12), + AUXADC_CHANNEL(VGPU_TEMP, 12), + AUXADC_CHANNEL(ACCDET, 12), + AUXADC_CHANNEL(HPOFS_CAL, 15), + AUXADC_CHANNEL(VTREF, 12), + AUXADC_CHANNEL(VBIF, 12), + AUXADC_CHANNEL(IMP, 15), + [AUXADC_IMIX_R] = { + .type = IIO_RESISTANCE, + .info_mask = BIT(IIO_CHAN_INFO_RAW), + .ch_name = "IMIX_R", + }, + AUXADC_CHANNEL(VSYSSNS, 15), + AUXADC_CHANNEL(VIN1, 15), + AUXADC_CHANNEL(VIN2, 15), + AUXADC_CHANNEL(VIN3, 15), + AUXADC_CHANNEL(VIN4, 15), + AUXADC_CHANNEL(VIN5, 15), + AUXADC_CHANNEL(VIN6, 15), + AUXADC_CHANNEL(VIN7, 15), +}; + +struct auxadc_regs { + unsigned int enable_reg; + unsigned int enable_mask; + unsigned int ready_reg; + unsigned int ready_mask; + unsigned int value_reg; + unsigned int ext_thr_sel; + u8 src_sel; +}; + +#define AUXADC_REG(_ch_name, _chip, _enable_reg, _enable_mask, _value_reg) \ + [AUXADC_##_ch_name] = { \ + .enable_reg = _chip##_##_enable_reg, \ + .enable_mask = _enable_mask, \ + .ready_reg = _chip##_##_value_reg, \ + .ready_mask = AUXADC_RDY_BIT, \ + .value_reg = _chip##_##_value_reg, \ + } \ + +#define TIA_ADC_REG(_src_sel, _chip) \ + [AUXADC_VIN##_src_sel] = { \ + .enable_reg = _chip##_AUXADC_RQST1, \ + .enable_mask = BIT(4), \ + .ready_reg = _chip##_AUXADC_ADC_CH12_L, \ + .ready_mask = AUXADC_RDY_BIT, \ + .value_reg = _chip##_AUXADC_ADC_CH12_L, \ + .ext_thr_sel = _chip##_SDMADC_CON0, \ + .src_sel = _src_sel, \ + } \ + +static const struct auxadc_regs mt6363_auxadc_regs_tbl[] = { + AUXADC_REG(BATADC, MT6363, AUXADC_RQST0, BIT(0), AUXADC_ADC0_L), + AUXADC_REG(BAT_TEMP, MT6363, AUXADC_RQST0, BIT(3), AUXADC_ADC3_L), + AUXADC_REG(CHIP_TEMP, MT6363, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L), + AUXADC_REG(VCORE_TEMP, MT6363, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L), + AUXADC_REG(VPROC_TEMP, MT6363, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L), + AUXADC_REG(VGPU_TEMP, MT6363, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L), + AUXADC_REG(VTREF, MT6363, AUXADC_RQST1, BIT(3), AUXADC_ADC11_L), + [AUXADC_IMP] = { + .enable_reg = MT6363_AUXADC_IMP0, + .enable_mask = BIT(0), + .ready_reg = MT6363_AUXADC_IMP1, + .ready_mask = BIT(7), + .value_reg = MT6363_AUXADC_ADC42_L, + }, + AUXADC_REG(VSYSSNS, MT6363, AUXADC_RQST1, BIT(6), AUXADC_ADC_CH14_L), + TIA_ADC_REG(1, MT6363), + TIA_ADC_REG(2, MT6363), + TIA_ADC_REG(3, MT6363), + TIA_ADC_REG(4, MT6363), + TIA_ADC_REG(5, MT6363), + TIA_ADC_REG(6, MT6363), + TIA_ADC_REG(7, MT6363), +}; + +static const struct auxadc_regs mt6373_auxadc_regs_tbl[] = { + AUXADC_REG(CHIP_TEMP, MT6373, AUXADC_RQST0, BIT(4), AUXADC_ADC4_L), + AUXADC_REG(VCORE_TEMP, MT6373, AUXADC_RQST3, BIT(0), AUXADC_ADC38_L), + AUXADC_REG(VPROC_TEMP, MT6373, AUXADC_RQST3, BIT(1), AUXADC_ADC39_L), + AUXADC_REG(VGPU_TEMP, MT6373, AUXADC_RQST3, BIT(2), AUXADC_ADC40_L), + TIA_ADC_REG(1, MT6373), + TIA_ADC_REG(2, MT6373), + TIA_ADC_REG(3, MT6373), + TIA_ADC_REG(4, MT6373), + TIA_ADC_REG(5, MT6373), +}; + +struct auxadc_info { + const struct auxadc_regs *regs_tbl; +}; + +static const struct auxadc_info mt6363_info = { + .regs_tbl = mt6363_auxadc_regs_tbl, +}; + +static const struct auxadc_info mt6373_info = { + .regs_tbl = mt6373_auxadc_regs_tbl, +}; + +#define regmap_bulk_read_poll_timeout(map, addr, val, val_count, cond, sleep_us, timeout_us) \ +({ \ + u64 __timeout_us = (timeout_us); \ + unsigned long __sleep_us = (sleep_us); \ + ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ + int __ret; \ + might_sleep_if(__sleep_us); \ + for (;;) { \ + __ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \ + if (__ret) \ + break; \ + if (cond) \ + break; \ + if ((__timeout_us) && \ + ktime_compare(ktime_get(), __timeout) > 0) { \ + __ret = regmap_bulk_read((map), (addr), (u8 *) &(val), val_count); \ + break; \ + } \ + if (__sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ + } \ + __ret ?: ((cond) ? 0 : -ETIMEDOUT); \ +}) + +/* + * @adc_dev: pointer to the struct pmic_adc_device + * @auxadc_chan: pointer to the struct auxadc_channels, it represents specific + auxadc channel + * @val: pointer to output value + */ +static int get_auxadc_out(struct pmic_adc_device *adc_dev, + int channel, int channel2, int *val) +{ + int ret; + u16 buf = 0; + const struct auxadc_channels *auxadc_chan = &auxadc_chans[channel]; + + if (!auxadc_chan->regs) + return -EINVAL; + + if (auxadc_chan->regs->ext_thr_sel) { + buf = (channel2 << EXT_THR_PURES_SHIFT) + | auxadc_chan->regs->src_sel; + ret = regmap_update_bits(adc_dev->regmap, + auxadc_chan->regs->ext_thr_sel, + EXT_THR_SEL_MASK, buf); + if (ret < 0) + return ret; + } + regmap_write(adc_dev->regmap, + auxadc_chan->regs->enable_reg, + auxadc_chan->regs->enable_mask); + usleep_range(auxadc_chan->avg_num * AUXADC_AVG_TIME_US, + (auxadc_chan->avg_num + 1) * AUXADC_AVG_TIME_US); + + ret = regmap_bulk_read_poll_timeout(adc_dev->regmap, + auxadc_chan->regs->value_reg, + buf, 2, + (buf & AUXADC_RDY_BIT), + AUXADC_POLL_DELAY_US, + AUXADC_TIMEOUT_US); + *val = buf & (BIT(auxadc_chan->res) - 1); + if (ret) + dev_err(adc_dev->dev, "%s ret error code:%d!\n", auxadc_chan->ch_name, ret); + + /* set PURES to OPEN after measuring done */ + if (auxadc_chan->regs->ext_thr_sel) { + buf = (ADC_PURES_OPEN << EXT_THR_PURES_SHIFT) + | auxadc_chan->regs->src_sel; + ret = regmap_update_bits(adc_dev->regmap, + auxadc_chan->regs->ext_thr_sel, + EXT_THR_SEL_MASK, buf); + } + + return ret; +} + +static int gauge_get_imp_ibat(void) +{ + struct power_supply *psy; + union power_supply_propval prop; + int ret; + + psy = power_supply_get_by_name("mtk-gauge"); + if (!psy) + return 0; + + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + if (ret) + return ret; + + power_supply_put(psy); + return prop.intval; +} + +static int get_imp_out(struct pmic_adc_device *adc_dev, int *val) +{ + int ret; + unsigned int buf = 0; + const struct auxadc_channels *auxadc_chan = &auxadc_chans[AUXADC_IMP]; + + if (!auxadc_chan->regs) + return -EINVAL; + + regmap_write(adc_dev->regmap, + auxadc_chan->regs->enable_reg, + auxadc_chan->regs->enable_mask); + ret = regmap_read_poll_timeout(adc_dev->regmap, auxadc_chan->regs->ready_reg, + buf, buf & auxadc_chan->regs->ready_mask, + AUXADC_POLL_DELAY_US, + AUXADC_TIMEOUT_US); + if (ret) { + dev_err(adc_dev->dev, "%s %s ret error code:%d!\n", + __func__, auxadc_chan->ch_name, ret); + return ret; + } + + ret = regmap_bulk_read(adc_dev->regmap, auxadc_chan->regs->value_reg, (u8 *) &buf, 2); + if (ret) + return ret; + *val = buf & (BIT(auxadc_chan->res) - 1); + adc_dev->imp_curr = gauge_get_imp_ibat(); + + regmap_write(adc_dev->regmap, + auxadc_chan->regs->enable_reg, 0); + + return 0; +} + +static int pmic_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct pmic_adc_device *adc_dev = iio_priv(indio_dev); + const struct auxadc_channels *auxadc_chan; + int auxadc_out = 0; + int ret = 0; + + mutex_lock(&adc_dev->lock); + switch (chan->channel) { + case AUXADC_IMP: + ret = get_imp_out(adc_dev, &auxadc_out); + break; + case AUXADC_IMIX_R: + auxadc_out = adc_dev->imix_r; + break; + default: + ret = get_auxadc_out(adc_dev, + chan->channel, chan->channel2, + &auxadc_out); + break; + } + mutex_unlock(&adc_dev->lock); + + if (ret && ret != -ETIMEDOUT) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + auxadc_chan = &auxadc_chans[chan->channel]; + *val = auxadc_out * auxadc_chan->r_ratio[0] * VOLT_FULL; + *val = (*val / auxadc_chan->r_ratio[1]) >> auxadc_chan->res; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_RAW: + *val = auxadc_out; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + } + if (chan->channel == AUXADC_IMP) { + *val2 = adc_dev->imp_curr; + ret = IIO_VAL_INT_MULTIPLE; + } + + return ret; +} + +static int pmic_adc_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + int i; + int channel = DT_CHANNEL_CONVERT(iiospec->args[0]); + int channel2 = DT_PURES_CONVERT(iiospec->args[0]); + + for (i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].channel == channel && + indio_dev->channels[i].channel2 == channel2) + return i; + } + + return -EINVAL; +} + +static const struct iio_info pmic_adc_info = { + .read_raw = &pmic_adc_read_raw, + .fwnode_xlate = &pmic_adc_fwnode_xlate, +}; + +static int auxadc_init_imix_r(struct pmic_adc_device *adc_dev, + struct device_node *imix_r_node) +{ + unsigned int val = 0; + int ret; + + if (!adc_dev) + return -EINVAL; + + adc_dev->isink_load = devm_regulator_get_exclusive(adc_dev->dev, "isink_load"); + if (IS_ERR(adc_dev->isink_load)) { + dev_err(adc_dev->dev, "Failed to get isink_load regulator, ret=%d\n", + (int)PTR_ERR(adc_dev->isink_load)); + return PTR_ERR(adc_dev->isink_load); + } + + imix_r_dev = adc_dev; + if (imix_r_dev->imix_r) + return 0; + + ret = of_property_read_u32(imix_r_node, "val", &val); + if (ret) + dev_notice(imix_r_dev->dev, "no imix_r, ret=%d\n", ret); + imix_r_dev->imix_r = (int)val; + imix_r_dev->pre_uisoc = 101; + return 0; +} + +static int auxadc_get_data_from_dt(struct pmic_adc_device *adc_dev, + struct iio_chan_spec *iio_chan, + struct device_node *node) +{ + struct auxadc_channels *auxadc_chan; + unsigned int channel = 0; + unsigned int value = 0; + unsigned int val_arr[2] = {0}; + int ret; + + ret = of_property_read_u32(node, "channel", &channel); + if (ret) { + dev_err(adc_dev->dev, "invalid channel in node:%s\n", + node->name); + return ret; + } + if (channel > AUXADC_CHAN_MAX) { + dev_err(adc_dev->dev, "invalid channel number %d in node:%s\n", + channel, node->name); + return -EINVAL; + } + if (channel >= ARRAY_SIZE(auxadc_chans)) { + dev_err(adc_dev->dev, "channel number %d in node:%s not exists\n", + channel, node->name); + return -EINVAL; + } + iio_chan->channel = channel; + iio_chan->datasheet_name = auxadc_chans[channel].ch_name; + iio_chan->info_mask_separate = auxadc_chans[channel].info_mask; + iio_chan->type = auxadc_chans[channel].type; + iio_chan->extend_name = node->name; + ret = of_property_read_u32(node, "pures", &value); + if (!ret) + iio_chan->channel2 = value; + + if (channel == AUXADC_IMIX_R) + return auxadc_init_imix_r(adc_dev, node); + + auxadc_chan = &auxadc_chans[channel]; + auxadc_chan->regs = &adc_dev->info->regs_tbl[channel]; + + ret = of_property_read_u32_array(node, "resistance-ratio", val_arr, 2); + if (!ret) { + auxadc_chan->r_ratio[0] = val_arr[0]; + auxadc_chan->r_ratio[1] = val_arr[1]; + } else { + auxadc_chan->r_ratio[0] = AUXADC_DEF_R_RATIO; + auxadc_chan->r_ratio[1] = 1; + } + + ret = of_property_read_u32(node, "avg-num", &value); + if (!ret) + auxadc_chan->avg_num = value; + else + auxadc_chan->avg_num = AUXADC_DEF_AVG_NUM; + + return 0; +} + +static int auxadc_parse_dt(struct pmic_adc_device *adc_dev, + struct device_node *node) +{ + struct iio_chan_spec *iio_chan; + struct device_node *child; + unsigned int index = 0; + int ret; + + adc_dev->nchannels = of_get_available_child_count(node); + if (!adc_dev->nchannels) + return -EINVAL; + + adc_dev->iio_chans = devm_kcalloc(adc_dev->dev, adc_dev->nchannels, + sizeof(*adc_dev->iio_chans), GFP_KERNEL); + if (!adc_dev->iio_chans) + return -ENOMEM; + iio_chan = adc_dev->iio_chans; + + for_each_available_child_of_node(node, child) { + ret = auxadc_get_data_from_dt(adc_dev, iio_chan, child); + if (ret < 0) { + of_node_put(child); + return ret; + } + iio_chan->indexed = 1; + iio_chan->address = index++; + iio_chan++; + } + + return 0; +} + +static int pmic_adc_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct pmic_adc_device *adc_dev; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev)); + if (!indio_dev) + return -ENOMEM; + + adc_dev = iio_priv(indio_dev); + adc_dev->dev = &pdev->dev; + adc_dev->regmap = dev_get_regmap(pdev->dev.parent, NULL); + mutex_init(&adc_dev->lock); + adc_dev->info = of_device_get_match_data(&pdev->dev); + + ret = auxadc_parse_dt(adc_dev, node); + if (ret) { + dev_notice(&pdev->dev, "auxadc_parse_dt fail, ret=%d\n", ret); + return ret; + } + + indio_dev->dev.parent = &pdev->dev; + indio_dev->name = dev_name(&pdev->dev); + indio_dev->info = &pmic_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc_dev->iio_chans; + indio_dev->num_channels = adc_dev->nchannels; + + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret < 0) { + dev_notice(&pdev->dev, "failed to register iio device!\n"); + return ret; + } + + dev_dbg(&pdev->dev, "probe done\n"); + + return 0; +} + +static const struct of_device_id pmic_adc_of_match[] = { + { .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_info, }, + { .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_info, }, + { } +}; +MODULE_DEVICE_TABLE(of, pmic_adc_of_match); + +static struct platform_driver pmic_adc_driver = { + .driver = { + .name = "mtk-spmi-pmic-adc", + .of_match_table = pmic_adc_of_match, + }, + .probe = pmic_adc_probe, +}; +module_platform_driver(pmic_adc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lu Tang "); +MODULE_DESCRIPTION("MediaTek SPMI PMIC ADC Driver"); From patchwork Fri Mar 14 07:32:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?THUgVGFuZyAo5rGk55KQKQ==?= X-Patchwork-Id: 14016375 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F1C7715CD4A; Fri, 14 Mar 2025 07:55:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938931; cv=none; b=an52VNm7Dj3VFMoIDncEQHjJc/MwVOAN08moOIbAtZ61Nw03/nMRKV4XFTSe2zNPaNEPCk9p5Jza2RFukDhEn/8cltFOD6xjrJYpZTc2vTDFvVoJmRFM95KRLnvxt1J87SiIfFeMHa30x5HauHOgnmXgxM6XLMcJKitqZYr6T4s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938931; c=relaxed/simple; bh=x8O+cVQkiIjFxyt9FNr4RI/iEusqLMSqlxE9BTflG+o=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Hq8x0+U0TM6sgq/C17gXz/ASsfXVKOFeiEisbx8LlcqG0w5dsc6veebgKH8toyaX8DNSAfHcRZOCDvGYAElrx9GloyHc9oKtaI05ScXcY71sVjYTwUdNBuu0iNNSSSrZ4w/MqGqe7rINziRyvNn4Gv5fIsHR2zkNmFGnMTFvJEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=YoF5pl4K; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="YoF5pl4K" X-UUID: ab6d747200a911f08eb9c36241bbb6fb-20250314 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=vkkild/Hn3SrCH3OFDvuROaLOzxsZuorcOOQckscz2g=; b=YoF5pl4K64fiIu+tEZ+X+Yj0MZeR/1jx5Hw5lAq1vdMWx7uSPtCINgZdkE0do049rdnia3Xh/eE3SNdlkqaGXfgXNKgrek0RZJw8nH7FNsifjBtWRNe9OhlnlH2+fBJOryPfB/m5dv3VDDj4xhM/yjXlNBCvPqBgIPoUW2yzJ4o=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:5d7d49ad-57ed-4374-b9b9-50d8ad6017c5,IP:0,UR L:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION:r elease,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:5e575e8c-f5b8-47d5-8cf3-b68fe7530c9a,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:1,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,OSH|NGT X-CID-BAS: 2,OSH|NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: ab6d747200a911f08eb9c36241bbb6fb-20250314 Received: from mtkmbs13n2.mediatek.inc [(172.21.101.108)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1800418703; Fri, 14 Mar 2025 15:55:17 +0800 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 14 Mar 2025 15:55:15 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 14 Mar 2025 15:55:14 +0800 From: Lu.Tang To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dmitry Torokhov , Lee Jones , Matthias Brugger , AngeloGioacchino Del Regno , Sean Wang , Linus Walleij , Liam Girdwood , Mark Brown , Stephen Boyd , Chen Zhong , Sen Chu CC: , , , , , , , , Lu.Tang Subject: [PATCH 2/5] pmic: mediatek: Add pmic regulator driver Date: Fri, 14 Mar 2025 15:32:28 +0800 Message-ID: <20250314073307.25092-3-Lu.Tang@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250314073307.25092-1-Lu.Tang@mediatek.com> References: <20250314073307.25092-1-Lu.Tang@mediatek.com> Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Lu.Tang" Add pmic mt6316/mt6373/mt6363 regulator driver Signed-off-by: Lu Tang --- drivers/regulator/Kconfig | 34 + drivers/regulator/Makefile | 3 + drivers/regulator/mt6316-regulator.c | 381 +++++++ drivers/regulator/mt6363-regulator.c | 1106 ++++++++++++++++++++ drivers/regulator/mt6373-regulator.c | 826 +++++++++++++++ include/linux/regulator/mt6316-regulator.h | 48 + include/linux/regulator/mt6363-regulator.h | 424 ++++++++ include/linux/regulator/mt6373-regulator.h | 318 ++++++ 8 files changed, 3140 insertions(+) create mode 100644 drivers/regulator/mt6316-regulator.c create mode 100644 drivers/regulator/mt6363-regulator.c create mode 100644 drivers/regulator/mt6373-regulator.c create mode 100644 include/linux/regulator/mt6316-regulator.h create mode 100644 include/linux/regulator/mt6363-regulator.h create mode 100644 include/linux/regulator/mt6373-regulator.h diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 39297f7d8177..7b2d47fee535 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -853,6 +853,16 @@ config REGULATOR_MT6315 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6316 + tristate "MediaTek MT6316 PMIC" + depends on SPMI + select REGMAP_SPMI + help + Say y here to select this option to enable the power regulator of + MediaTek MT6316 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6323 tristate "MediaTek MT6323 PMIC" depends on MFD_MT6397 @@ -916,6 +926,18 @@ config REGULATOR_MT6360 2-channel buck with Thermal Shutdown and Overload Protection 6-channel High PSRR and Low Dropout LDO. +config REGULATOR_MT6363 + tristate "MT6363 SPMI Regulator driver" + depends on MFD_MTK_SPMI_PMIC + help + Say y here to select this option to enable the power regulator of + MediaTek MT6363 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + + The driver can also be build as a module. + If so, the module will be called mt6363_regulator + config REGULATOR_MT6370 tristate "MT6370 SubPMIC Regulator" depends on MFD_MT6370 @@ -924,6 +946,18 @@ config REGULATOR_MT6370 This driver supports the control for DisplayBias voltages and one general purpose LDO which is commonly used to drive the vibrator. +config REGULATOR_MT6373 + tristate "MT6373 SPMI Regulator driver" + depends on MFD_MTK_SPMI_PMIC + help + Say y here to select this option to enable the power regulator of + MediaTek MT6373 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + + The driver can also be build as a module. + If so, the module will be called mt6373_regulator + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 3d5a803dce8a..b54a64522499 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_REGULATOR_MP886X) += mp886x.o obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o +obj-$(CONFIG_REGULATOR_MT6316) += mt6316-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6331) += mt6331-regulator.o obj-$(CONFIG_REGULATOR_MT6332) += mt6332-regulator.o @@ -109,7 +110,9 @@ obj-$(CONFIG_REGULATOR_MT6357) += mt6357-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o +obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o +obj-$(CONFIG_REGULATOR_MT6373) += mt6373-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o diff --git a/drivers/regulator/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c new file mode 100644 index 000000000000..1c069a0d4cff --- /dev/null +++ b/drivers/regulator/mt6316-regulator.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2024 MediaTek Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SET_OFFSET 0x1 +#define CLR_OFFSET 0x2 + +#define MT6316_REG_WIDTH 8 + +#define MT6316_BUCK_MODE_AUTO 0 +#define MT6316_BUCK_MODE_FORCE_PWM 1 +#define MT6316_BUCK_MODE_NORMAL 0 +#define MT6316_BUCK_MODE_LP 2 + +#define BUCK_PHASE_3 3 +#define BUCK_PHASE_4 4 + +struct mt6316_regulator_info { + struct regulator_desc desc; + u32 da_reg; + u32 qi; + u32 modeset_reg; + u32 modeset_mask; + u32 lp_mode_reg; + u32 lp_mode_mask; + u32 lp_mode_shift; +}; + +struct mt6316_init_data { + u32 id; + u32 size; +}; + +struct mt6316_chip { + struct device *dev; + struct regmap *regmap; + u32 slave_id; +}; + +#define MT_BUCK(match, _name, volt_ranges, _bid, _vsel) \ +[MT6316_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6316_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6316_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = 0x1ff, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges),\ + .vsel_reg = _vsel, \ + .vsel_mask = 0xff, \ + .enable_reg = MT6316_BUCK_TOP_CON0, \ + .enable_mask = BIT(_bid - 1), \ + .of_map_mode = mt6316_map_mode, \ + }, \ + .da_reg = MT6316_VBUCK##_bid##_DBG8, \ + .qi = BIT(0), \ + .lp_mode_reg = MT6316_BUCK_TOP_CON1, \ + .lp_mode_mask = BIT(_bid - 1), \ + .lp_mode_shift = _bid - 1, \ + .modeset_reg = MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0,\ + .modeset_mask = BIT(_bid - 1), \ +} + +static const struct linear_range mt_volt_range1[] = { + REGULATOR_LINEAR_RANGE(0, 0, 0x1fe, 2500), +}; + +static int mt6316_regulator_enable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET, + rdev->desc->enable_mask); +} + +static int mt6316_regulator_disable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET, + rdev->desc->enable_mask); +} + +static unsigned int mt6316_map_mode(u32 mode) +{ + switch (mode) { + case MT6316_BUCK_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + case MT6316_BUCK_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + case MT6316_BUCK_MODE_LP: + return REGULATOR_MODE_IDLE; + default: + return REGULATOR_MODE_INVALID; + } +} + +static int mt6316_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) +{ + unsigned short reg_val = 0; + int ret = 0; + + reg_val = ((selector & 0x1) << 8) | (selector >> 1); + ret = regmap_bulk_write(rdev->regmap, rdev->desc->vsel_reg, (u8 *) ®_val, 2); + + return ret; +} + +static int mt6316_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + int ret = 0; + unsigned int reg_val = 0; + + ret = regmap_bulk_read(rdev->regmap, rdev->desc->vsel_reg, (u8 *) ®_val, 2); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get mt6316 regulator voltage: %d\n", ret); + return ret; + } + ret = ((reg_val >> 8) & 0x1) + ((reg_val & rdev->desc->vsel_mask) << 1); + + return ret; +} + +static unsigned int mt6316_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6316_regulator_info *info; + int ret = 0, regval = 0; + u32 modeset_mask; + + info = container_of(rdev->desc, struct mt6316_regulator_info, desc); + ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get mt6316 buck mode: %d\n", ret); + return ret; + } + + modeset_mask = info->modeset_mask; + + if ((regval & modeset_mask) == modeset_mask) + return REGULATOR_MODE_FAST; + + ret = regmap_read(rdev->regmap, info->lp_mode_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get mt6316 buck lp mode: %d\n", ret); + return ret; + } + + if (regval & info->lp_mode_mask) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; +} + +static int mt6316_regulator_set_mode(struct regulator_dev *rdev, u32 mode) +{ + struct mt6316_regulator_info *info; + int ret = 0, val, curr_mode; + u32 modeset_mask; + + info = container_of(rdev->desc, struct mt6316_regulator_info, desc); + modeset_mask = info->modeset_mask; + + curr_mode = mt6316_regulator_get_mode(rdev); + switch (mode) { + case REGULATOR_MODE_FAST: + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + modeset_mask, modeset_mask); + break; + case REGULATOR_MODE_NORMAL: + if (curr_mode == REGULATOR_MODE_FAST) { + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + modeset_mask, 0); + } else if (curr_mode == REGULATOR_MODE_IDLE) { + ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, + info->lp_mode_mask, 0); + usleep_range(100, 110); + } + break; + case REGULATOR_MODE_IDLE: + val = MT6316_BUCK_MODE_LP >> 1; + val <<= info->lp_mode_shift; + ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, val); + break; + default: + ret = -EINVAL; + goto err_mode; + } + +err_mode: + if (ret != 0) { + dev_err(&rdev->dev, "Failed to set mt6316 buck mode: %d\n", ret); + return ret; + } + + return 0; +} + +static int mt6316_get_status(struct regulator_dev *rdev) +{ + int ret = 0; + u32 regval = 0; + struct mt6316_regulator_info *info; + + info = container_of(rdev->desc, struct mt6316_regulator_info, desc); + ret = regmap_read(rdev->regmap, info->da_reg, ®val); + if (ret != 0) { + dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static void mt6316_buck_phase_init(struct mt6316_chip *chip, unsigned int *s6_buck_phase) +{ + int ret = 0; + u32 val = 0; + + ret = regmap_read(chip->regmap, MT6316_BUCK_TOP_4PHASE_TOP_ELR_0, &val); + if (ret) { + dev_err(chip->dev, "Failed to get mt6316 buck phase: %d\n", ret); + return; + } + + dev_info(chip->dev, "S%d RG_4PH_CONFIG:%d\n", chip->slave_id, val); + if (chip->slave_id == MT6316_SLAVE_ID_6) + *s6_buck_phase = val; +} + +static const struct regulator_ops mt6316_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = mt6316_regulator_set_voltage_sel, + .get_voltage_sel = mt6316_regulator_get_voltage_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = mt6316_regulator_enable, + .disable = mt6316_regulator_disable, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6316_get_status, + .set_mode = mt6316_regulator_set_mode, + .get_mode = mt6316_regulator_get_mode, +}; + +static struct mt6316_regulator_info mt6316_regulators[] = { + MT_BUCK("vbuck1", VBUCK1, mt_volt_range1, 1, MT6316_BUCK_TOP_ELR0), + MT_BUCK("vbuck2", VBUCK2, mt_volt_range1, 2, MT6316_BUCK_TOP_ELR2), + MT_BUCK("vbuck3", VBUCK3, mt_volt_range1, 3, MT6316_BUCK_TOP_ELR4), + MT_BUCK("vbuck4", VBUCK4, mt_volt_range1, 4, MT6316_BUCK_TOP_ELR6), +}; + +static struct mt6316_init_data mt6316_3_init_data = { + .id = MT6316_SLAVE_ID_3, + .size = MT6316_ID_3_MAX, +}; + +static struct mt6316_init_data mt6316_6_init_data = { + .id = MT6316_SLAVE_ID_6, + .size = MT6316_ID_6_MAX, +}; + +static struct mt6316_init_data mt6316_7_init_data = { + .id = MT6316_SLAVE_ID_7, + .size = MT6316_ID_7_MAX, +}; + +static struct mt6316_init_data mt6316_8_init_data = { + .id = MT6316_SLAVE_ID_8, + .size = MT6316_ID_8_MAX, +}; + +static struct mt6316_init_data mt6316_15_init_data = { + .id = MT6316_SLAVE_ID_15, + .size = MT6316_ID_15_MAX, +}; + +static const struct of_device_id mt6316_of_match[] = { + { + .compatible = "mediatek,mt6316-3-regulator", + .data = &mt6316_3_init_data, + }, { + .compatible = "mediatek,mt6316-6-regulator", + .data = &mt6316_6_init_data, + }, { + .compatible = "mediatek,mt6316-7-regulator", + .data = &mt6316_7_init_data, + }, { + .compatible = "mediatek,mt6316-8-regulator", + .data = &mt6316_8_init_data, + }, { + .compatible = "mediatek,mt6316-15-regulator", + .data = &mt6316_15_init_data, + }, { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, mt6316_of_match); + +static int mt6316_regulator_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + struct device *dev = &pdev->dev; + struct regmap *regmap; + struct mt6316_init_data *pdata; + struct mt6316_chip *chip; + struct regulator_config config = {}; + struct regulator_dev *rdev; + struct device_node *node = pdev->dev.of_node; + u32 val = 0; + int i; + unsigned int s6_buck_phase; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENODEV; + + chip = devm_kzalloc(dev, sizeof(struct mt6316_chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + of_id = of_match_device(mt6316_of_match, dev); + if (!of_id || !of_id->data) + return -ENODEV; + + pdata = (struct mt6316_init_data *)of_id->data; + chip->slave_id = pdata->id; + if (!of_property_read_u32(node, "buck-size", &val)) + pdata->size = val; + chip->dev = dev; + chip->regmap = regmap; + dev_set_drvdata(dev, chip); + + dev->fwnode = &(dev->of_node->fwnode); + if (dev->fwnode && !dev->fwnode->dev) + dev->fwnode->dev = dev; + + config.dev = dev; + config.driver_data = pdata; + config.regmap = regmap; + + mt6316_buck_phase_init(chip, &s6_buck_phase); + for (i = 0; i < pdata->size; i++) { + if (pdata->id == MT6316_SLAVE_ID_6 && + s6_buck_phase == BUCK_PHASE_4 && + (mt6316_regulators + i)->desc.id == MT6316_ID_VBUCK3) { + dev_info(dev, "skip registering %s.\n", (mt6316_regulators + i)->desc.name); + continue; + } + + rdev = devm_regulator_register(dev, &(mt6316_regulators + i)->desc, &config); + if (IS_ERR(rdev)) { + dev_err(dev, "failed to register %s\n", (mt6316_regulators + i)->desc.name); + continue; + } + } + + return 0; +} + +static struct platform_driver mt6316_regulator_driver = { + .driver = { + .name = "mt6316-regulator", + .of_match_table = mt6316_of_match, + }, + .probe = mt6316_regulator_probe, +}; + +module_platform_driver(mt6316_regulator_driver); + +MODULE_AUTHOR("Lu Tang "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6316 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c new file mode 100644 index 000000000000..cdb280110a9a --- /dev/null +++ b/drivers/regulator/mt6363-regulator.c @@ -0,0 +1,1106 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2024 MediaTek Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SET_OFFSET 0x1 +#define CLR_OFFSET 0x2 +#define OP_CFG_OFFSET 0x5 +#define NORMAL_OP_CFG 0x10 +#define NORMAL_OP_EN 0x800000 + +#define MT6363_REGULATOR_MODE_NORMAL 0 +#define MT6363_REGULATOR_MODE_FCCM 1 +#define MT6363_REGULATOR_MODE_LP 2 +#define MT6363_REGULATOR_MODE_ULP 3 + +#define DEFAULT_DELAY_MS 10 + +/* + * MT6363 regulator lock register + */ +#define MT6363_TMA_UNLOCK_VALUE 0x9c9c +#define MT6363_BUCK_TOP_UNLOCK_VALUE 0x5543 + +#define MT6363_RG_BUCK_EFUSE_RSV1 0x1447 +#define MT6363_RG_BUCK_EFUSE_RSV1_MASK 0xf0 + +/* + * MT6363 regulators' information + * + * @irq: Interrupt request number of the regulator. + * @oc_irq_enable_delay_ms: delay in milliseconds before enabling overcurrent interrupt. + * @oc_work: Delayed work fields of overcurrent events. + * @desc: standard fields of regulator description. + * @lp_mode_reg: for operating NORMAL/IDLE mode register. + * @lp_mode_mask: MASK for operating lp_mode register. + * @hw_lp_mode_reg: hardware NORMAL/IDLE mode status register. + * @hw_lp_mode_mask: MASK for hardware NORMAL/IDLE mode status register. + * @modeset_reg: for operating AUTO/PWM mode register. + * @modeset_mask: MASK for operating modeset register. + * @vocal_reg: Calibrates output voltage register. + * @vocal_mask: MASK of Calibrates output voltage register. + * @lp_imax_uA: Maximum load current in Low power mode. + * @op_en_reg: for HW control operating mode register. + * @orig_op_en: for HW control original mode register. + * @orig_op_cfg: for HW control original mode register. + */ +struct mt6363_regulator_info { + int irq; + int oc_irq_enable_delay_ms; + struct delayed_work oc_work; + struct regulator_desc desc; + u32 lp_mode_reg; + u32 lp_mode_mask; + u32 hw_lp_mode_reg; + u32 hw_lp_mode_mask; + u32 modeset_reg; + u32 modeset_mask; + u32 vocal_reg; + u32 vocal_mask; + u32 lp_imax_uA; + u32 op_en_reg; + u32 orig_op_en; + u32 orig_op_cfg; +}; + +#define MT6363_BUCK(match, _name, min, max, step, _enable_reg, en_bit, \ + _vsel_reg, _vsel_mask, _lp_mode_reg, lp_bit, \ + _modeset_reg, modeset_bit, _en_delay) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6363_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6363_map_mode, \ + }, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .hw_lp_mode_reg = MT6363_BUCK_##_name##_HW_LP_MODE, \ + .hw_lp_mode_mask = 0xc, \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(modeset_bit), \ + .lp_imax_uA = 100000, \ + .op_en_reg = MT6363_BUCK_##_name##_OP_EN_0, \ +} + +#define MT6363_SSHUB(match, _name, min, max, step, \ + _enable_reg, _vsel_reg, _vsel_mask) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6363_sshub_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(0), \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + }, \ +} + +#define MT6363_LDO_LINEAR1(match, _name, min, max, step, \ + _enable_reg, en_bit, _vsel_reg, \ + _vsel_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6363_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6363_map_mode, \ + }, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE, \ + .hw_lp_mode_mask = 0x4, \ +} + +#define MT6363_LDO_LINEAR2(match, _name, min, max, step, \ + _enable_reg, en_bit, _vsel_reg, \ + _vsel_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6363_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6363_map_mode, \ + }, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE, \ + .hw_lp_mode_mask = 0x4, \ +} + +#define MT6363_LDO(match, _name, _volt_table, _enable_reg, en_bit, \ + _vsel_reg, _vsel_mask, _vocal_reg, \ + _vocal_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6363_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6363_map_mode, \ + }, \ + .vocal_reg = _vocal_reg, \ + .vocal_mask = _vocal_mask, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE, \ + .hw_lp_mode_mask = 0x4, \ + .lp_imax_uA = 10000, \ + .op_en_reg = MT6363_LDO_##_name##_OP_EN0, \ +} + +#define MT6363_LDO_OPS(match, _name, _ops, _volt_table, _enable_reg, en_bit, \ + _vsel_reg, _vsel_mask, _vocal_reg, \ + _vocal_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6363_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6363_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6363_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6363_map_mode, \ + }, \ + .vocal_reg = _vocal_reg, \ + .vocal_mask = _vocal_mask, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .hw_lp_mode_reg = MT6363_LDO_##_name##_HW_LP_MODE, \ + .hw_lp_mode_mask = 0x4, \ + .lp_imax_uA = 10000, \ + .op_en_reg = MT6363_LDO_##_name##_OP_EN0, \ +} + +static const unsigned int ldo_volt_table0[] = { + 1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000, + 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000, +}; + +static const unsigned int ldo_volt_table1[] = { + 900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000, +}; + +static const unsigned int ldo_volt_table2[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, +}; + +static const unsigned int ldo_volt_table3[] = { + 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000, + 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, +}; + +static const unsigned int ldo_volt_table4[] = { + 550000, 600000, 650000, 700000, 750000, 800000, 900000, 950000, + 1000000, 1050000, 1100000, 1150000, 1700000, 1750000, 1800000, 1850000, +}; + +static const unsigned int ldo_volt_table5[] = { + 600000, 650000, 700000, 750000, 800000, +}; + +static int mt6363_buck_enable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET, + rdev->desc->enable_mask); +} + +static int mt6363_buck_disable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET, + rdev->desc->enable_mask); +} + +static inline unsigned int mt6363_map_mode(unsigned int mode) +{ + switch (mode) { + case MT6363_REGULATOR_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case MT6363_REGULATOR_MODE_FCCM: + return REGULATOR_MODE_FAST; + case MT6363_REGULATOR_MODE_LP: + return REGULATOR_MODE_IDLE; + case MT6363_REGULATOR_MODE_ULP: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +static unsigned int mt6363_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6363_regulator_info *info = rdev_get_drvdata(rdev); + unsigned int val = 0; + int ret; + + ret = regmap_read(rdev->regmap, info->modeset_reg, &val); + if (ret) { + dev_err(&rdev->dev, "Failed to get mt6363 mode: %d\n", ret); + return ret; + } + + if (val & info->modeset_mask) + return REGULATOR_MODE_FAST; + + if (info->hw_lp_mode_reg) { + ret = regmap_read(rdev->regmap, info->hw_lp_mode_reg, &val); + val &= info->hw_lp_mode_mask; + } else { + ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val); + val &= info->lp_mode_mask; + } + if (ret) { + dev_err(&rdev->dev, + "Failed to get mt6363 lp mode: %d\n", ret); + return ret; + } + + if (val) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; +} + +static int mt6363_buck_unlock(struct regmap *map, bool unlock) +{ + u16 buf = unlock ? MT6363_BUCK_TOP_UNLOCK_VALUE : 0; + + return regmap_bulk_write(map, MT6363_BUCK_TOP_KEY_PROT_LO, &buf, 2); +} + +static int mt6363_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6363_regulator_info *info = rdev_get_drvdata(rdev); + int ret = 0; + int curr_mode; + + curr_mode = mt6363_regulator_get_mode(rdev); + switch (mode) { + case REGULATOR_MODE_FAST: + ret = mt6363_buck_unlock(rdev->regmap, true); + if (ret) + return ret; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + info->modeset_mask); + ret |= mt6363_buck_unlock(rdev->regmap, false); + break; + case REGULATOR_MODE_NORMAL: + if (curr_mode == REGULATOR_MODE_FAST) { + ret = mt6363_buck_unlock(rdev->regmap, true); + if (ret) + return ret; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + 0); + ret |= mt6363_buck_unlock(rdev->regmap, false); + break; + } else if (curr_mode == REGULATOR_MODE_IDLE) { + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + 0); + udelay(100); + } + break; + case REGULATOR_MODE_IDLE: + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + info->lp_mode_mask); + break; + default: + return -EINVAL; + } + + if (ret) { + dev_err(&rdev->dev, + "Failed to set mt6363 mode(%d): %d\n", mode, ret); + } + return ret; +} + +static int mt6363_regulator_set_load(struct regulator_dev *rdev, int load_uA) +{ + int i, ret; + struct mt6363_regulator_info *info = rdev_get_drvdata(rdev); + + /* not support */ + if (!info->lp_imax_uA) + return 0; + + if (load_uA >= info->lp_imax_uA) { + ret = mt6363_regulator_set_mode(rdev, REGULATOR_MODE_NORMAL); + if (ret) + return ret; + ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, NORMAL_OP_CFG); + for (i = 0; i < 3; i++) { + ret |= regmap_write(rdev->regmap, info->op_en_reg + i, + (NORMAL_OP_EN >> (i * 8)) & 0xff); + } + } else { + ret = regmap_write(rdev->regmap, info->op_en_reg + OP_CFG_OFFSET, + info->orig_op_cfg); + for (i = 0; i < 3; i++) { + ret |= regmap_write(rdev->regmap, info->op_en_reg + i, + (info->orig_op_en >> (i * 8)) & 0xff); + } + } + + return ret; +} + +static int mt6363_vemc_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) +{ + int ret; + u16 buf = MT6363_TMA_UNLOCK_VALUE; + unsigned int val = 0; + + ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2); + if (ret) + return ret; + + ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val); + if (ret) + return ret; + switch (val) { + case 0: + /* If HW trapping is 0, use VEMC_VOSEL_0 */ + ret = regmap_update_bits(rdev->regmap, + rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); + break; + case 1: + /* If HW trapping is 1, use VEMC_VOSEL_1 */ + ret = regmap_update_bits(rdev->regmap, + rdev->desc->vsel_reg, + rdev->desc->vsel_mask << 4, sel << 4); + break; + default: + break; + } + if (ret) + return ret; + + buf = 0; + ret = regmap_bulk_write(rdev->regmap, MT6363_TOP_TMA_KEY_L, &buf, 2); + return ret; +} + +static int mt6363_vemc_get_voltage_sel(struct regulator_dev *rdev) +{ + int ret; + unsigned int val = 0, sel = 0; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &sel); + if (ret) + return ret; + ret = regmap_read(rdev->regmap, MT6363_TOP_TRAP, &val); + if (ret) + return ret; + switch (val) { + case 0: + /* If HW trapping is 0, use VEMC_VOSEL_0 */ + sel &= rdev->desc->vsel_mask; + break; + case 1: + /* If HW trapping is 1, use VEMC_VOSEL_1 */ + sel = (sel >> 4) & rdev->desc->vsel_mask; + break; + default: + return -EINVAL; + } + + return sel; +} + +static int mt6363_va15_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) +{ + int ret; + + ret = mt6363_buck_unlock(rdev->regmap, true); + if (ret) + return ret; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel); + if (ret) + goto va15_unlock; + ret = regmap_update_bits(rdev->regmap, MT6363_RG_BUCK_EFUSE_RSV1, + MT6363_RG_BUCK_EFUSE_RSV1_MASK, sel); + if (ret) + goto va15_unlock; + +va15_unlock: + ret |= mt6363_buck_unlock(rdev->regmap, false); + return ret; +} + +static const struct regulator_ops mt6363_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = mt6363_buck_enable, + .disable = mt6363_buck_disable, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6363_regulator_set_mode, + .get_mode = mt6363_regulator_get_mode, + .set_load = mt6363_regulator_set_load, +}; + +/* for sshub */ +static const struct regulator_ops mt6363_sshub_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_ops mt6363_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6363_regulator_set_mode, + .get_mode = mt6363_regulator_get_mode, +}; + +static const struct regulator_ops mt6363_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6363_regulator_set_mode, + .get_mode = mt6363_regulator_get_mode, + .set_load = mt6363_regulator_set_load, +}; + +static const struct regulator_ops mt6363_vemc_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = mt6363_vemc_set_voltage_sel, + .get_voltage_sel = mt6363_vemc_get_voltage_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6363_regulator_set_mode, + .get_mode = mt6363_regulator_get_mode, + .set_load = mt6363_regulator_set_load, +}; + +static const struct regulator_ops mt6363_va15_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = mt6363_va15_set_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6363_regulator_set_mode, + .get_mode = mt6363_regulator_get_mode, + .set_load = mt6363_regulator_set_load, +}; + +static int _isink_load_control(struct regulator_dev *rdev, bool enable) +{ + const struct { + unsigned int reg; + unsigned int mask; + unsigned int val; + } en_settings[] = { + { MT6363_ISINK_EN_CTRL0, 0xFF, 0xFF }, + { MT6363_ISINK_EN_CTRL1, 0xF0, 0xF0 }, + }, dis_settings[] = { + { MT6363_ISINK_EN_CTRL1, 0xF0, 0 }, + { MT6363_ISINK_EN_CTRL0, 0xFF, 0 }, + }, *settings; + int i, setting_size, ret; + + if (enable) { + settings = en_settings; + setting_size = ARRAY_SIZE(en_settings); + } else { + settings = dis_settings; + setting_size = ARRAY_SIZE(dis_settings); + } + + for (i = 0; i < setting_size; i++) { + ret = regmap_update_bits(rdev->regmap, + settings[i].reg, settings[i].mask, + settings[i].val); + if (ret) { + dev_err(&rdev->dev, + "Failed to %s isink settings[%d], ret=%d\n", + enable ? "enable" : "disable", + i, ret); + return ret; + } + } + return 0; +} + +static int isink_load_enable(struct regulator_dev *rdev) +{ + return _isink_load_control(rdev, true); +} + +static int isink_load_disable(struct regulator_dev *rdev) +{ + return _isink_load_control(rdev, false); +} + +static int isink_load_is_enabled(struct regulator_dev *rdev) +{ + unsigned int val = 0; + int ret; + + ret = regmap_read(rdev->regmap, MT6363_ISINK_EN_CTRL1, &val); + if (ret) + return ret; + + val &= 0xF0; + return (val == 0xF0); +} + +static const struct regulator_ops isink_load_ops = { + .enable = isink_load_enable, + .disable = isink_load_disable, + .is_enabled = isink_load_is_enabled, +}; + +static int mt6363_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config); + +/* The array is indexed by id(MT6363_ID_XXX) */ +static struct mt6363_regulator_info mt6363_regulators[] = { + MT6363_BUCK("vs2", VS2, 0, 1600000, 12500, + MT6363_RG_BUCK_VS2_EN_ADDR, + MT6363_RG_BUCK_VS2_EN_SHIFT, + MT6363_RG_BUCK_VS2_VOSEL_ADDR, + MT6363_RG_BUCK_VS2_VOSEL_MASK, + MT6363_RG_BUCK_VS2_LP_ADDR, + MT6363_RG_BUCK_VS2_LP_SHIFT, + MT6363_RG_VS2_FCCM_ADDR, + MT6363_RG_VS2_FCCM_SHIFT, 180), + MT6363_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK1_EN_ADDR, + MT6363_RG_BUCK_VBUCK1_EN_SHIFT, + MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK1_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK1_LP_ADDR, + MT6363_RG_BUCK_VBUCK1_LP_SHIFT, + MT6363_RG_VBUCK1_FCCM_ADDR, + MT6363_RG_VBUCK1_FCCM_SHIFT, 180), + MT6363_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK2_EN_ADDR, + MT6363_RG_BUCK_VBUCK2_EN_SHIFT, + MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK2_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK2_LP_ADDR, + MT6363_RG_BUCK_VBUCK2_LP_SHIFT, + MT6363_RG_VBUCK2_FCCM_ADDR, + MT6363_RG_VBUCK2_FCCM_SHIFT, 200), + MT6363_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK3_EN_ADDR, + MT6363_RG_BUCK_VBUCK3_EN_SHIFT, + MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK3_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK3_LP_ADDR, + MT6363_RG_BUCK_VBUCK3_LP_SHIFT, + MT6363_RG_VBUCK3_FCCM_ADDR, + MT6363_RG_VBUCK3_FCCM_SHIFT, 200), + MT6363_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK4_EN_ADDR, + MT6363_RG_BUCK_VBUCK4_EN_SHIFT, + MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK4_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK4_LP_ADDR, + MT6363_RG_BUCK_VBUCK4_LP_SHIFT, + MT6363_RG_VBUCK4_FCCM_ADDR, + MT6363_RG_VBUCK4_FCCM_SHIFT, 200), + MT6363_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK5_EN_ADDR, + MT6363_RG_BUCK_VBUCK5_EN_SHIFT, + MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK5_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK5_LP_ADDR, + MT6363_RG_BUCK_VBUCK5_LP_SHIFT, + MT6363_RG_VBUCK5_FCCM_ADDR, + MT6363_RG_VBUCK5_FCCM_SHIFT, 200), + MT6363_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK6_EN_ADDR, + MT6363_RG_BUCK_VBUCK6_EN_SHIFT, + MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK6_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK6_LP_ADDR, + MT6363_RG_BUCK_VBUCK6_LP_SHIFT, + MT6363_RG_VBUCK6_FCCM_ADDR, + MT6363_RG_VBUCK6_FCCM_SHIFT, 300), + MT6363_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK7_EN_ADDR, + MT6363_RG_BUCK_VBUCK7_EN_SHIFT, + MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK7_VOSEL_MASK, + MT6363_RG_BUCK_VBUCK7_LP_ADDR, + MT6363_RG_BUCK_VBUCK7_LP_SHIFT, + MT6363_RG_VBUCK7_FCCM_ADDR, + MT6363_RG_VBUCK7_FCCM_SHIFT, 300), + MT6363_BUCK("vs1", VS1, 0, 2200000, 12500, + MT6363_RG_BUCK_VS1_EN_ADDR, + MT6363_RG_BUCK_VS1_EN_SHIFT, + MT6363_RG_BUCK_VS1_VOSEL_ADDR, + MT6363_RG_BUCK_VS1_VOSEL_MASK, + MT6363_RG_BUCK_VS1_LP_ADDR, + MT6363_RG_BUCK_VS1_LP_SHIFT, + MT6363_RG_VS1_FCCM_ADDR, + MT6363_RG_VS1_FCCM_SHIFT, 180), + MT6363_BUCK("vs3", VS3, 0, 1193750, 6250, + MT6363_RG_BUCK_VS3_EN_ADDR, + MT6363_RG_BUCK_VS3_EN_SHIFT, + MT6363_RG_BUCK_VS3_VOSEL_ADDR, + MT6363_RG_BUCK_VS3_VOSEL_MASK, + MT6363_RG_BUCK_VS3_LP_ADDR, + MT6363_RG_BUCK_VS3_LP_SHIFT, + MT6363_RG_VS3_FCCM_ADDR, + MT6363_RG_VS3_FCCM_SHIFT, 180), + MT6363_SSHUB("vbuck1-sshub", VBUCK1_SSHUB, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR, + MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK), + MT6363_SSHUB("vbuck2-sshub", VBUCK2_SSHUB, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR, + MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK), + MT6363_SSHUB("vbuck4-sshub", VBUCK4_SSHUB, 0, 1193750, 6250, + MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR, + MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR, + MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK), + MT6363_LDO_LINEAR1("vsram-digrf", VSRAM_DIGRF, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR, + MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT, + MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR, + MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT, 180), + MT6363_LDO_LINEAR1("vsram-mdfe", VSRAM_MDFE, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR, + MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT, + MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR, + MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT, 180), + MT6363_LDO_LINEAR1("vsram-modem", VSRAM_MODEM, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR, + MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT, + MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR, + MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT, 180), + MT6363_LDO_LINEAR2("vsram-cpub", VSRAM_CPUB, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR, + MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT, + MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR, + MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT, 180), + MT6363_LDO_LINEAR2("vsram-cpum", VSRAM_CPUM, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR, + MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT, + MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR, + MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT, 180), + MT6363_LDO_LINEAR2("vsram-cpul", VSRAM_CPUL, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR, + MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT, + MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR, + MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT, 180), + MT6363_LDO_LINEAR2("vsram-apu", VSRAM_APU, 400000, 1193750, 6250, + MT6363_RG_LDO_VSRAM_APU_EN_ADDR, + MT6363_RG_LDO_VSRAM_APU_EN_SHIFT, + MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR, + MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK, + MT6363_RG_LDO_VSRAM_APU_LP_ADDR, + MT6363_RG_LDO_VSRAM_APU_LP_SHIFT, 180), + MT6363_LDO_OPS("vemc", VEMC, mt6363_vemc_ops, ldo_volt_table0, + MT6363_RG_LDO_VEMC_EN_ADDR, MT6363_RG_LDO_VEMC_EN_SHIFT, + MT6363_RG_VEMC_VOSEL_0_ADDR, + MT6363_RG_VEMC_VOSEL_0_MASK, + MT6363_RG_VEMC_VOCAL_0_ADDR, + MT6363_RG_VEMC_VOCAL_0_MASK, + MT6363_RG_LDO_VEMC_LP_ADDR, + MT6363_RG_LDO_VEMC_LP_SHIFT, 680), + MT6363_LDO("vcn13", VCN13, ldo_volt_table1, + MT6363_RG_LDO_VCN13_EN_ADDR, MT6363_RG_LDO_VCN13_EN_SHIFT, + MT6363_RG_VCN13_VOSEL_ADDR, + MT6363_RG_VCN13_VOSEL_MASK, + MT6363_RG_VCN13_VOCAL_ADDR, + MT6363_RG_VCN13_VOCAL_MASK, + MT6363_RG_LDO_VCN13_LP_ADDR, + MT6363_RG_LDO_VCN13_LP_SHIFT, 180), + MT6363_LDO("vtref18", VTREF18, ldo_volt_table2, + MT6363_RG_LDO_VTREF18_EN_ADDR, MT6363_RG_LDO_VTREF18_EN_SHIFT, + MT6363_RG_VTREF18_VOSEL_ADDR, + MT6363_RG_VTREF18_VOSEL_MASK, + MT6363_RG_VTREF18_VOCAL_ADDR, + MT6363_RG_VTREF18_VOCAL_MASK, + MT6363_RG_LDO_VTREF18_LP_ADDR, + MT6363_RG_LDO_VTREF18_LP_SHIFT, 240), + MT6363_LDO("vaux18", VAUX18, ldo_volt_table2, + MT6363_RG_LDO_VAUX18_EN_ADDR, MT6363_RG_LDO_VAUX18_EN_SHIFT, + MT6363_RG_VAUX18_VOSEL_ADDR, + MT6363_RG_VAUX18_VOSEL_MASK, + MT6363_RG_VAUX18_VOCAL_ADDR, + MT6363_RG_VAUX18_VOCAL_MASK, + MT6363_RG_LDO_VAUX18_LP_ADDR, + MT6363_RG_LDO_VAUX18_LP_SHIFT, 240), + MT6363_LDO("vcn15", VCN15, ldo_volt_table3, + MT6363_RG_LDO_VCN15_EN_ADDR, MT6363_RG_LDO_VCN15_EN_SHIFT, + MT6363_RG_VCN15_VOSEL_ADDR, + MT6363_RG_VCN15_VOSEL_MASK, + MT6363_RG_VCN15_VOCAL_ADDR, + MT6363_RG_VCN15_VOCAL_MASK, + MT6363_RG_LDO_VCN15_LP_ADDR, + MT6363_RG_LDO_VCN15_LP_SHIFT, 180), + MT6363_LDO("vufs18", VUFS18, ldo_volt_table3, + MT6363_RG_LDO_VUFS18_EN_ADDR, MT6363_RG_LDO_VUFS18_EN_SHIFT, + MT6363_RG_VUFS18_VOSEL_ADDR, + MT6363_RG_VUFS18_VOSEL_MASK, + MT6363_RG_VUFS18_VOCAL_ADDR, + MT6363_RG_VUFS18_VOCAL_MASK, + MT6363_RG_LDO_VUFS18_LP_ADDR, + MT6363_RG_LDO_VUFS18_LP_SHIFT, 680), + MT6363_LDO("vio18", VIO18, ldo_volt_table3, + MT6363_RG_LDO_VIO18_EN_ADDR, MT6363_RG_LDO_VIO18_EN_SHIFT, + MT6363_RG_VIO18_VOSEL_ADDR, + MT6363_RG_VIO18_VOSEL_MASK, + MT6363_RG_VIO18_VOCAL_ADDR, + MT6363_RG_VIO18_VOCAL_MASK, + MT6363_RG_LDO_VIO18_LP_ADDR, + MT6363_RG_LDO_VIO18_LP_SHIFT, 680), + MT6363_LDO("vm18", VM18, ldo_volt_table4, + MT6363_RG_LDO_VM18_EN_ADDR, MT6363_RG_LDO_VM18_EN_SHIFT, + MT6363_RG_VM18_VOSEL_ADDR, + MT6363_RG_VM18_VOSEL_MASK, + MT6363_RG_VM18_VOCAL_ADDR, + MT6363_RG_VM18_VOCAL_MASK, + MT6363_RG_LDO_VM18_LP_ADDR, + MT6363_RG_LDO_VM18_LP_SHIFT, 280), + MT6363_LDO_OPS("va15", VA15, mt6363_va15_ops, ldo_volt_table3, + MT6363_RG_LDO_VA15_EN_ADDR, MT6363_RG_LDO_VA15_EN_SHIFT, + MT6363_RG_VA15_VOSEL_ADDR, + MT6363_RG_VA15_VOSEL_MASK, + MT6363_RG_VA15_VOCAL_ADDR, + MT6363_RG_VA15_VOCAL_MASK, + MT6363_RG_LDO_VA15_LP_ADDR, + MT6363_RG_LDO_VA15_LP_SHIFT, 180), + MT6363_LDO("vrf18", VRF18, ldo_volt_table3, + MT6363_RG_LDO_VRF18_EN_ADDR, MT6363_RG_LDO_VRF18_EN_SHIFT, + MT6363_RG_VRF18_VOSEL_ADDR, + MT6363_RG_VRF18_VOSEL_MASK, + MT6363_RG_VRF18_VOCAL_ADDR, + MT6363_RG_VRF18_VOCAL_MASK, + MT6363_RG_LDO_VRF18_LP_ADDR, + MT6363_RG_LDO_VRF18_LP_SHIFT, 180), + MT6363_LDO("vrfio18", VRFIO18, ldo_volt_table3, + MT6363_RG_LDO_VRFIO18_EN_ADDR, MT6363_RG_LDO_VRFIO18_EN_SHIFT, + MT6363_RG_VRFIO18_VOSEL_ADDR, + MT6363_RG_VRFIO18_VOSEL_MASK, + MT6363_RG_VRFIO18_VOCAL_ADDR, + MT6363_RG_VRFIO18_VOCAL_MASK, + MT6363_RG_LDO_VRFIO18_LP_ADDR, + MT6363_RG_LDO_VRFIO18_LP_SHIFT, 180), + MT6363_LDO("vio075", VIO075, ldo_volt_table5, + MT6363_RG_LDO_VIO075_EN_ADDR, MT6363_RG_LDO_VIO075_EN_SHIFT, + MT6363_RG_VIO075_VOSEL_ADDR, + MT6363_RG_VIO075_VOSEL_MASK, + MT6363_RG_VIO075_VOCAL_ADDR, + MT6363_RG_VIO075_VOCAL_MASK, + MT6363_RG_LDO_VIO075_LP_ADDR, + MT6363_RG_LDO_VIO075_LP_SHIFT, 3000), + MT6363_LDO("vufs12", VUFS12, ldo_volt_table4, + MT6363_RG_LDO_VUFS12_EN_ADDR, MT6363_RG_LDO_VUFS12_EN_SHIFT, + MT6363_RG_VUFS12_VOSEL_ADDR, + MT6363_RG_VUFS12_VOSEL_MASK, + MT6363_RG_VUFS12_VOCAL_ADDR, + MT6363_RG_VUFS12_VOCAL_MASK, + MT6363_RG_LDO_VUFS12_LP_ADDR, + MT6363_RG_LDO_VUFS12_LP_SHIFT, 280), + MT6363_LDO("va12-1", VA12_1, ldo_volt_table3, + MT6363_RG_LDO_VA12_1_EN_ADDR, MT6363_RG_LDO_VA12_1_EN_SHIFT, + MT6363_RG_VA12_1_VOSEL_ADDR, + MT6363_RG_VA12_1_VOSEL_MASK, + MT6363_RG_VA12_1_VOCAL_ADDR, + MT6363_RG_VA12_1_VOCAL_MASK, + MT6363_RG_LDO_VA12_1_LP_ADDR, + MT6363_RG_LDO_VA12_1_LP_SHIFT, 180), + MT6363_LDO("va12-2", VA12_2, ldo_volt_table3, + MT6363_RG_LDO_VA12_2_EN_ADDR, MT6363_RG_LDO_VA12_2_EN_SHIFT, + MT6363_RG_VA12_2_VOSEL_ADDR, + MT6363_RG_VA12_2_VOSEL_MASK, + MT6363_RG_VA12_2_VOCAL_ADDR, + MT6363_RG_VA12_2_VOCAL_MASK, + MT6363_RG_LDO_VA12_2_LP_ADDR, + MT6363_RG_LDO_VA12_2_LP_SHIFT, 180), + MT6363_LDO("vrf12", VRF12, ldo_volt_table3, + MT6363_RG_LDO_VRF12_EN_ADDR, MT6363_RG_LDO_VRF12_EN_SHIFT, + MT6363_RG_VRF12_VOSEL_ADDR, + MT6363_RG_VRF12_VOSEL_MASK, + MT6363_RG_VRF12_VOCAL_ADDR, + MT6363_RG_VRF12_VOCAL_MASK, + MT6363_RG_LDO_VRF12_LP_ADDR, + MT6363_RG_LDO_VRF12_LP_SHIFT, 180), + MT6363_LDO("vrf13", VRF13, ldo_volt_table1, + MT6363_RG_LDO_VRF13_EN_ADDR, MT6363_RG_LDO_VRF13_EN_SHIFT, + MT6363_RG_VRF13_VOSEL_ADDR, + MT6363_RG_VRF13_VOSEL_MASK, + MT6363_RG_VRF13_VOCAL_ADDR, + MT6363_RG_VRF13_VOCAL_MASK, + MT6363_RG_LDO_VRF13_LP_ADDR, + MT6363_RG_LDO_VRF13_LP_SHIFT, 180), + MT6363_LDO("vrf09", VRF09, ldo_volt_table1, + MT6363_RG_LDO_VRF09_EN_ADDR, MT6363_RG_LDO_VRF09_EN_SHIFT, + MT6363_RG_VRF09_VOSEL_ADDR, + MT6363_RG_VRF09_VOSEL_MASK, + MT6363_RG_VRF09_VOCAL_ADDR, + MT6363_RG_VRF09_VOCAL_MASK, + MT6363_RG_LDO_VRF09_LP_ADDR, + MT6363_RG_LDO_VRF09_LP_SHIFT, 180), + [MT6363_ID_ISINK_LOAD] = { + .desc = { + .name = "isink_load", + .of_match = of_match_ptr("isink-load"), + .regulators_node = "regulators", + .id = MT6363_ID_ISINK_LOAD, + .type = REGULATOR_CURRENT, + .ops = &isink_load_ops, + .owner = THIS_MODULE, + }, + } +}; + +static void mt6363_oc_irq_enable_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct mt6363_regulator_info *info + = container_of(dwork, struct mt6363_regulator_info, oc_work); + + enable_irq(info->irq); +} + +static irqreturn_t mt6363_oc_irq(int irq, void *data) +{ + struct regulator_dev *rdev = (struct regulator_dev *)data; + struct mt6363_regulator_info *info = rdev_get_drvdata(rdev); + + disable_irq_nosync(info->irq); + if (!regulator_is_enabled_regmap(rdev)) + goto delayed_enable; + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, + NULL); +delayed_enable: + schedule_delayed_work(&info->oc_work, + msecs_to_jiffies(info->oc_irq_enable_delay_ms)); + return IRQ_HANDLED; +} + +static int mt6363_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + int ret; + struct mt6363_regulator_info *info = config->driver_data; + + if (info->irq > 0) { + ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms", + &info->oc_irq_enable_delay_ms); + if (ret || !info->oc_irq_enable_delay_ms) + info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS; + INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work); + } + return 0; +} + +static int mt6363_backup_op_setting(struct regmap *map, struct mt6363_regulator_info *info) +{ + int i, ret; + u32 val = 0; + + ret = regmap_read(map, info->op_en_reg + OP_CFG_OFFSET, &info->orig_op_cfg); + for (i = 0; i < 3; i++) { + ret |= regmap_read(map, info->op_en_reg + i, &val); + info->orig_op_en |= val << (i * 8); + } + if (ret) + return ret; + + return 0; +} + +static int mt6363_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = {}; + struct regulator_dev *rdev; + struct mt6363_regulator_info *info; + int i, ret; + + config.dev = pdev->dev.parent; + config.regmap = dev_get_regmap(pdev->dev.parent, NULL); + for (i = 0; i < MT6363_MAX_REGULATOR; i++) { + info = &mt6363_regulators[i]; + info->irq = platform_get_irq_byname_optional(pdev, info->desc.name); + config.driver_data = info; + + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&pdev->dev, "failed to register %s, ret=%d\n", + info->desc.name, ret); + continue; + } + if (info->lp_imax_uA) { + ret = mt6363_backup_op_setting(config.regmap, info); + if (ret) { + dev_notice(&pdev->dev, "failed to backup op_setting (%s)\n", + info->desc.name); + info->lp_imax_uA = 0; + } + } + + if (info->irq <= 0) + continue; + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + mt6363_oc_irq, + IRQF_TRIGGER_HIGH, + info->desc.name, + rdev); + if (ret) { + dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d", + info->desc.name, ret); + continue; + } + } + + return 0; +} + +static const struct platform_device_id mt6363_regulator_ids[] = { + { "mt6363-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6363_regulator_ids); + +static struct platform_driver mt6363_regulator_driver = { + .driver = { + .name = "mt6363-regulator", + }, + .probe = mt6363_regulator_probe, + .id_table = mt6363_regulator_ids, +}; +module_platform_driver(mt6363_regulator_driver); + +MODULE_AUTHOR("Lu Tang "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6363 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/mt6373-regulator.c b/drivers/regulator/mt6373-regulator.c new file mode 100644 index 000000000000..5a8a9f84d13a --- /dev/null +++ b/drivers/regulator/mt6373-regulator.c @@ -0,0 +1,826 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2024 MediaTek Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SET_OFFSET 0x1 +#define CLR_OFFSET 0x2 + +#define MT6373_REGULATOR_MODE_NORMAL 0 +#define MT6373_REGULATOR_MODE_FCCM 1 +#define MT6373_REGULATOR_MODE_LP 2 +#define MT6373_REGULATOR_MODE_ULP 3 + +#define DEFAULT_DELAY_MS 10 + +#define MT6373_RG_RSV_SWREG_H 0xa09 +#define MT6373_PLG_CFG_ELR1 0x3ab +#define MT6373_ELR_MASK 0xc + +/* + * MT6373 regulators' information + * + * @desc: standard fields of regulator description. + * @lp_mode_reg: for operating NORMAL/IDLE mode register. + * @lp_mode_mask: MASK for operating lp_mode register. + * @modeset_reg: for operating AUTO/PWM mode register. + * @modeset_mask: MASK for operating modeset register. + * @modeset_reg: Calibrates output voltage register. + * @modeset_mask: MASK of Calibrates output voltage register. + */ +struct mt6373_regulator_info { + int irq; + int oc_irq_enable_delay_ms; + struct delayed_work oc_work; + struct regulator_desc desc; + u32 lp_mode_reg; + u32 lp_mode_mask; + u32 modeset_reg; + u32 modeset_mask; + u32 vocal_reg; + u32 vocal_mask; +}; + +#define MT6373_BUCK(match, _name, min, max, step, \ + _enable_reg, en_bit, _vsel_reg, _vsel_mask, \ + _lp_mode_reg, lp_bit, \ + _modeset_reg, modeset_bit, _en_delay) \ +[MT6373_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6373_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6373_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6373_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6373_map_mode, \ + }, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(modeset_bit), \ +} + +#define MT6373_LDO_LINEAR(match, _name, min, max, step, \ + _enable_reg, en_bit, _vsel_reg, \ + _vsel_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6373_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6373_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6373_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6373_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .uV_step = (step), \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6373_map_mode, \ + }, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ +} + +#define MT6373_LDO(match, _name, _volt_table, _enable_reg, en_bit, \ + _vsel_reg, _vsel_mask, _vocal_reg, \ + _vocal_mask, _lp_mode_reg, lp_bit, _en_delay) \ +[MT6373_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6373_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6373_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6373_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(en_bit), \ + .enable_time = _en_delay, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .of_map_mode = mt6373_map_mode, \ + }, \ + .vocal_reg = _vocal_reg, \ + .vocal_mask = _vocal_mask, \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(lp_bit), \ +} + +#define MT6373_VMCH_EINT(match, _eint_pol, _volt_table, _en_delay) \ +[MT6373_ID_VMCH_##_eint_pol] = { \ + .desc = { \ + .name = "VMCH_"#_eint_pol, \ + .of_match = of_match_ptr(match), \ + .of_parse_cb = mt6373_of_parse_cb, \ + .regulators_node = "regulators", \ + .ops = &mt6373_vmch_eint_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6373_ID_VMCH_##_eint_pol, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .enable_reg = MT6373_LDO_VMCH_EINT, \ + .enable_mask = MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK, \ + .enable_time = _en_delay, \ + .vsel_reg = MT6373_PMIC_RG_VMCH_VOSEL_ADDR, \ + .vsel_mask = MT6373_PMIC_RG_VMCH_VOSEL_MASK, \ + .of_map_mode = mt6373_map_mode, \ + }, \ + .vocal_reg = MT6373_PMIC_RG_VMCH_VOCAL_ADDR, \ + .vocal_mask = MT6373_PMIC_RG_VMCH_VOCAL_MASK, \ + .lp_mode_reg = MT6373_PMIC_RG_LDO_VMCH_LP_ADDR, \ + .lp_mode_mask = BIT(MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT), \ +} + +static const unsigned int ldo_volt_table1[] = { + 1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2100000, 2200000, + 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000, +}; + +static const unsigned int ldo_volt_table2[] = { + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, +}; + +static const unsigned int ldo_volt_table3[] = { + 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000, + 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, +}; + +static const unsigned int ldo_volt_table4[] = { + 1200000, 1300000, 1500000, 1700000, 1800000, 2000000, 2500000, 2600000, + 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 3400000, 3500000, +}; + +static const unsigned int ldo_volt_table5[] = { + 900000, 1000000, 1100000, 1200000, 1300000, 1700000, 1800000, 1810000, +}; + +static int mt6373_buck_enable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + SET_OFFSET, + rdev->desc->enable_mask); +} + +static int mt6373_buck_disable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, rdev->desc->enable_reg + CLR_OFFSET, + rdev->desc->enable_mask); +} + +static inline unsigned int mt6373_map_mode(unsigned int mode) +{ + switch (mode) { + case MT6373_REGULATOR_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case MT6373_REGULATOR_MODE_FCCM: + return REGULATOR_MODE_FAST; + case MT6373_REGULATOR_MODE_LP: + return REGULATOR_MODE_IDLE; + case MT6373_REGULATOR_MODE_ULP: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +static unsigned int mt6373_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6373_regulator_info *info = rdev_get_drvdata(rdev); + unsigned int val = 0; + int ret; + + ret = regmap_read(rdev->regmap, info->modeset_reg, &val); + if (ret) { + dev_err(&rdev->dev, "Failed to get mt6373 mode: %d\n", ret); + return ret; + } + + if (val & info->modeset_mask) + return REGULATOR_MODE_FAST; + + ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val); + if (ret) { + dev_err(&rdev->dev, + "Failed to get mt6373 lp mode: %d\n", ret); + return ret; + } + + if (val & info->lp_mode_mask) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; +} + +static int mt6373_buck_unlock(struct regmap *map, bool unlock) +{ + u8 buf[2]; + + if (unlock) { + buf[0] = 0x43; + buf[1] = 0x55; + } else + buf[0] = buf[1] = 0; + return regmap_bulk_write(map, MT6373_BUCK_TOP_KEY_PROT_LO, buf, 2); +} + +static int mt6373_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6373_regulator_info *info = rdev_get_drvdata(rdev); + int ret = 0; + int curr_mode; + + curr_mode = mt6373_regulator_get_mode(rdev); + switch (mode) { + case REGULATOR_MODE_FAST: + ret = mt6373_buck_unlock(rdev->regmap, true); + if (ret) + return ret; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + info->modeset_mask); + ret |= mt6373_buck_unlock(rdev->regmap, false); + break; + case REGULATOR_MODE_NORMAL: + if (curr_mode == REGULATOR_MODE_FAST) { + ret = mt6373_buck_unlock(rdev->regmap, true); + if (ret) + return ret; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + 0); + ret |= mt6373_buck_unlock(rdev->regmap, false); + } else if (curr_mode == REGULATOR_MODE_IDLE) { + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + 0); + udelay(100); + } + break; + case REGULATOR_MODE_IDLE: + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + info->lp_mode_mask); + break; + default: + return -EINVAL; + } + + if (ret) { + dev_err(&rdev->dev, + "Failed to set mt6373 mode(%d): %d\n", mode, ret); + } + return ret; +} + +static int mt6373_vmch_eint_enable(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + if (rdev->desc->id == MT6373_ID_VMCH_EINT_HIGH) + val = MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK; + else + val = 0; + ret = regmap_update_bits(rdev->regmap, MT6373_LDO_VMCH_EINT, + MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK, val); + if (ret) + return ret; + + ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR, + BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT), + BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT)); + if (ret) + return ret; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, rdev->desc->enable_mask); + return ret; +} + +static int mt6373_vmch_eint_disable(struct regulator_dev *rdev) +{ + int ret; + + ret = regmap_update_bits(rdev->regmap, MT6373_PMIC_RG_LDO_VMCH_EN_ADDR, + BIT(MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT), 0); + if (ret) + return ret; + + udelay(1500); /* Must delay for VMCH discharging */ + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); + return ret; +} + +static const struct regulator_ops mt6373_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = mt6373_buck_enable, + .disable = mt6373_buck_disable, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6373_regulator_set_mode, + .get_mode = mt6373_regulator_get_mode, +}; + +static const struct regulator_ops mt6373_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6373_regulator_set_mode, + .get_mode = mt6373_regulator_get_mode, +}; + +static const struct regulator_ops mt6373_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6373_regulator_set_mode, + .get_mode = mt6373_regulator_get_mode, +}; + +static const struct regulator_ops mt6373_vmch_eint_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = mt6373_vmch_eint_enable, + .disable = mt6373_vmch_eint_disable, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mt6373_regulator_set_mode, + .get_mode = mt6373_regulator_get_mode, +}; + +static int mt6373_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config); + +/* The array is indexed by id(MT6373_ID_XXX) */ +static struct mt6373_regulator_info mt6373_regulators[] = { + MT6373_BUCK("vbuck0", VBUCK0, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK0_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT, + MT6373_PMIC_RG_VBUCK0_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT, 180), + MT6373_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT, + MT6373_PMIC_RG_VBUCK1_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT, + MT6373_PMIC_RG_VBUCK2_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT, + MT6373_PMIC_RG_VBUCK3_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck4", VBUCK4, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT, + MT6373_PMIC_RG_VBUCK4_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180), + MT6373_BUCK("vbuck4-ufs", VBUCK4_UFS, 0, 2650125, 13875, + MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT, + MT6373_PMIC_RG_VBUCK4_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT, 180), + MT6373_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT, + MT6373_PMIC_RG_VBUCK5_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT, + MT6373_PMIC_RG_VBUCK6_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT, + MT6373_PMIC_RG_VBUCK7_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck8", VBUCK8, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT, + MT6373_PMIC_RG_VBUCK8_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT, 200), + MT6373_BUCK("vbuck9", VBUCK9, 0, 1193750, 6250, + MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT, + MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK, + MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR, + MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT, + MT6373_PMIC_RG_VBUCK9_FCCM_ADDR, + MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT, 200), + MT6373_LDO_LINEAR("vsram-digrf-aif", VSRAM_DIGRF_AIF, 400000, 1193750, 6250, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT, 180), + MT6373_LDO("vusb", VUSB, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VUSB_EN_ADDR, MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT, + MT6373_PMIC_RG_VUSB_VOSEL_ADDR, + MT6373_PMIC_RG_VUSB_VOSEL_MASK, + MT6373_PMIC_RG_VUSB_VOCAL_ADDR, + MT6373_PMIC_RG_VUSB_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VUSB_LP_ADDR, + MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT, 720), + MT6373_LDO("vaux18", VAUX18, ldo_volt_table2, + MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT, + MT6373_PMIC_RG_VAUX18_VOSEL_ADDR, + MT6373_PMIC_RG_VAUX18_VOSEL_MASK, + MT6373_PMIC_RG_VAUX18_VOCAL_ADDR, + MT6373_PMIC_RG_VAUX18_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR, + MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT, 240), + MT6373_LDO("vrf13-aif", VRF13_AIF, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT, + MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK, + MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR, + MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT, 720), + MT6373_LDO("vrf18-aif", VRF18_AIF, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT, + MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK, + MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR, + MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT, 720), + MT6373_LDO("vrfio18-aif", VRFIO18_AIF, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT, + MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK, + MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR, + MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT, 720), + MT6373_LDO("vrf09-aif", VRF09_AIF, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT, + MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK, + MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR, + MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT, 720), + MT6373_LDO("vrf12-aif", VRF12_AIF, ldo_volt_table5, + MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR, MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT, + MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR, + MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK, + MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR, + MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR, + MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT, 720), + MT6373_LDO("vant18", VANT18, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VANT18_EN_ADDR, MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT, + MT6373_PMIC_RG_VANT18_VOSEL_ADDR, + MT6373_PMIC_RG_VANT18_VOSEL_MASK, + MT6373_PMIC_RG_VANT18_VOCAL_ADDR, + MT6373_PMIC_RG_VANT18_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VANT18_LP_ADDR, + MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT, 720), + MT6373_LDO("vibr", VIBR, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VIBR_EN_ADDR, MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT, + MT6373_PMIC_RG_VIBR_VOSEL_ADDR, + MT6373_PMIC_RG_VIBR_VOSEL_MASK, + MT6373_PMIC_RG_VIBR_VOCAL_ADDR, + MT6373_PMIC_RG_VIBR_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VIBR_LP_ADDR, + MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT, 210), + MT6373_LDO("vio28", VIO28, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VIO28_EN_ADDR, MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT, + MT6373_PMIC_RG_VIO28_VOSEL_ADDR, + MT6373_PMIC_RG_VIO28_VOSEL_MASK, + MT6373_PMIC_RG_VIO28_VOCAL_ADDR, + MT6373_PMIC_RG_VIO28_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VIO28_LP_ADDR, + MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT, 210), + MT6373_LDO("vfp", VFP, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VFP_EN_ADDR, MT6373_PMIC_RG_LDO_VFP_EN_SHIFT, + MT6373_PMIC_RG_VFP_VOSEL_ADDR, + MT6373_PMIC_RG_VFP_VOSEL_MASK, + MT6373_PMIC_RG_VFP_VOCAL_ADDR, + MT6373_PMIC_RG_VFP_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VFP_LP_ADDR, + MT6373_PMIC_RG_LDO_VFP_LP_SHIFT, 210), + MT6373_LDO("vtp", VTP, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VTP_EN_ADDR, MT6373_PMIC_RG_LDO_VTP_EN_SHIFT, + MT6373_PMIC_RG_VTP_VOSEL_ADDR, + MT6373_PMIC_RG_VTP_VOSEL_MASK, + MT6373_PMIC_RG_VTP_VOCAL_ADDR, + MT6373_PMIC_RG_VTP_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VTP_LP_ADDR, + MT6373_PMIC_RG_LDO_VTP_LP_SHIFT, 720), + MT6373_LDO("vmch", VMCH, ldo_volt_table4, + MT6373_PMIC_RG_LDO_VMCH_EN_ADDR, MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT, + MT6373_PMIC_RG_VMCH_VOSEL_ADDR, + MT6373_PMIC_RG_VMCH_VOSEL_MASK, + MT6373_PMIC_RG_VMCH_VOCAL_ADDR, + MT6373_PMIC_RG_VMCH_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VMCH_LP_ADDR, + MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT, 720), + MT6373_LDO("vmc", VMC, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VMC_EN_ADDR, MT6373_PMIC_RG_LDO_VMC_EN_SHIFT, + MT6373_PMIC_RG_VMC_VOSEL_ADDR, + MT6373_PMIC_RG_VMC_VOSEL_MASK, + MT6373_PMIC_RG_VMC_VOCAL_ADDR, + MT6373_PMIC_RG_VMC_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VMC_LP_ADDR, + MT6373_PMIC_RG_LDO_VMC_LP_SHIFT, 720), + MT6373_LDO("vaud18", VAUD18, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR, MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT, + MT6373_PMIC_RG_VAUD18_VOSEL_ADDR, + MT6373_PMIC_RG_VAUD18_VOSEL_MASK, + MT6373_PMIC_RG_VAUD18_VOCAL_ADDR, + MT6373_PMIC_RG_VAUD18_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR, + MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT, 720), + MT6373_LDO("vcn33-1", VCN33_1, ldo_volt_table4, + MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT, + MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR, + MT6373_PMIC_RG_VCN33_1_VOSEL_MASK, + MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR, + MT6373_PMIC_RG_VCN33_1_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR, + MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT, 210), + MT6373_LDO("vcn33-2", VCN33_2, ldo_volt_table4, + MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT, + MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR, + MT6373_PMIC_RG_VCN33_2_VOSEL_MASK, + MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR, + MT6373_PMIC_RG_VCN33_2_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR, + MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT, 210), + MT6373_LDO("vcn33-3", VCN33_3, ldo_volt_table4, + MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR, MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT, + MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR, + MT6373_PMIC_RG_VCN33_3_VOSEL_MASK, + MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR, + MT6373_PMIC_RG_VCN33_3_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR, + MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT, 210), + MT6373_LDO("vcn18io", VCN18IO, ldo_volt_table3, + MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR, MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT, + MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR, + MT6373_PMIC_RG_VCN18IO_VOSEL_MASK, + MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR, + MT6373_PMIC_RG_VCN18IO_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR, + MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT, 720), + MT6373_LDO("vefuse", VEFUSE, ldo_volt_table1, + MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR, MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT, + MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR, + MT6373_PMIC_RG_VEFUSE_VOSEL_MASK, + MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR, + MT6373_PMIC_RG_VEFUSE_VOCAL_MASK, + MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR, + MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT, 720), + MT6373_VMCH_EINT("vmch-eint-high", EINT_HIGH, ldo_volt_table4, 720), + MT6373_VMCH_EINT("vmch-eint-low", EINT_LOW, ldo_volt_table4, 720), +}; + +static void mt6373_oc_irq_enable_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct mt6373_regulator_info *info + = container_of(dwork, struct mt6373_regulator_info, oc_work); + + enable_irq(info->irq); +} + +static irqreturn_t mt6373_oc_irq(int irq, void *data) +{ + struct regulator_dev *rdev = (struct regulator_dev *)data; + struct mt6373_regulator_info *info = rdev_get_drvdata(rdev); + + disable_irq_nosync(info->irq); + if (!regulator_is_enabled_regmap(rdev)) + goto delayed_enable; + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, + NULL); +delayed_enable: + schedule_delayed_work(&info->oc_work, + msecs_to_jiffies(info->oc_irq_enable_delay_ms)); + return IRQ_HANDLED; +} + +static int mt6373_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + int ret; + struct mt6373_regulator_info *info = config->driver_data; + + if (info->irq > 0) { + ret = of_property_read_u32(np, "mediatek,oc-irq-enable-delay-ms", + &info->oc_irq_enable_delay_ms); + if (ret || !info->oc_irq_enable_delay_ms) + info->oc_irq_enable_delay_ms = DEFAULT_DELAY_MS; + INIT_DELAYED_WORK(&info->oc_work, mt6373_oc_irq_enable_work); + } + return 0; +} + +static bool mt6373_bypass_register(struct mt6373_regulator_info *info) +{ + return info->desc.id == MT6373_ID_VBUCK4_UFS; +} + +static int mt6373_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = {}; + struct regulator_dev *rdev; + struct mt6373_regulator_info *info; + int i, ret; + unsigned int val = 0; + bool is_mt6373_cw = false; + + config.dev = pdev->dev.parent; + config.regmap = dev_get_regmap(pdev->dev.parent, NULL); + + if (!config.regmap) { + dev_err(&pdev->dev, "failed to get regmap\n"); + return -EINVAL; + } + + ret = regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val); + if (ret) + dev_notice(&pdev->dev, "failed to read ELR, ret=%d\n", ret); + else if ((val & MT6373_ELR_MASK) == 0x4) + is_mt6373_cw = true; + + /* MT6373_RG_RSV_SWREG_H for checking 6989p */ + ret = regmap_read(config.regmap, MT6373_RG_RSV_SWREG_H, &val); + + for (i = 0; i < MT6373_MAX_REGULATOR; i++) { + info = &mt6373_regulators[i]; + info->irq = platform_get_irq_byname_optional(pdev, info->desc.name); + config.driver_data = info; + if (is_mt6373_cw && mt6373_bypass_register(info)) + continue; + if ((info->desc.id == MT6373_ID_VBUCK4) && (val & 0x1)) { + dev_info(&pdev->dev, "skip registering %s\n", info->desc.name); + continue; + } + + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&pdev->dev, "failed to register %s, ret=%d\n", + info->desc.name, ret); + continue; + } + + if (info->irq <= 0) + continue; + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + mt6373_oc_irq, + IRQF_TRIGGER_HIGH, + info->desc.name, + rdev); + if (ret) { + dev_err(&pdev->dev, "Failed to request IRQ:%s, ret=%d", + info->desc.name, ret); + continue; + } + } + + return 0; +} + +static void mt6373_regulator_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + int ret = 0; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) { + dev_notice(&pdev->dev, "invalid regmap.\n"); + return; + } + + ret = regmap_write(regmap, MT6373_TOP_CFG_ELR5, 0x1); + if (ret < 0) { + dev_notice(&pdev->dev, "enable sequence off failed.\n"); + return; + } +} + +static const struct platform_device_id mt6373_regulator_ids[] = { + { "mt6373-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6373_regulator_ids); + +static struct platform_driver mt6373_regulator_driver = { + .driver = { + .name = "mt6373-regulator", + }, + .probe = mt6373_regulator_probe, + .shutdown = mt6373_regulator_shutdown, + .id_table = mt6373_regulator_ids, +}; +module_platform_driver(mt6373_regulator_driver); + +MODULE_AUTHOR("Lu Tang "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6373 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/regulator/mt6316-regulator.h b/include/linux/regulator/mt6316-regulator.h new file mode 100644 index 000000000000..dd11b3d856fd --- /dev/null +++ b/include/linux/regulator/mt6316-regulator.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef __LINUX_REGULATOR_MT6316_H +#define __LINUX_REGULATOR_MT6316_H + +#define MT6316_SLAVE_ID_3 3 +#define MT6316_SLAVE_ID_6 6 +#define MT6316_SLAVE_ID_7 7 +#define MT6316_SLAVE_ID_8 8 +#define MT6316_SLAVE_ID_15 15 + +#define MT6316_ID_3_MAX 3 +#define MT6316_ID_6_MAX 3 +#define MT6316_ID_7_MAX 3 +#define MT6316_ID_8_MAX 3 +#define MT6316_ID_15_MAX 2 + +enum { + MT6316_ID_VBUCK1 = 0, + MT6316_ID_VBUCK2, + MT6316_ID_VBUCK3, + MT6316_ID_VBUCK4, + MT6316_ID_MAX, +}; + +/* Register */ +#define MT6316_TOP_CFG_ELR4 0x143 +#define MT6316_BUCK_TOP_CON0 0x1440 +#define MT6316_BUCK_TOP_CON1 0x1443 +#define MT6316_BUCK_TOP_ELR0 0x1448 +#define MT6316_BUCK_TOP_ELR2 0x144A +#define MT6316_BUCK_TOP_ELR4 0x144C +#define MT6316_BUCK_TOP_ELR6 0x144E +#define MT6316_VBUCK1_DBG4 0x14A4 +#define MT6316_VBUCK1_DBG8 0x14A8 +#define MT6316_VBUCK2_DBG4 0x1524 +#define MT6316_VBUCK2_DBG8 0x1528 +#define MT6316_VBUCK3_DBG4 0x15A4 +#define MT6316_VBUCK3_DBG8 0x15A8 +#define MT6316_VBUCK4_DBG4 0x1624 +#define MT6316_VBUCK4_DBG8 0x1628 +#define MT6316_BUCK_TOP_4PHASE_TOP_ANA_CON0 0x1688 +#define MT6316_BUCK_TOP_4PHASE_TOP_ELR_0 0x1690 + +#endif /* __LINUX_REGULATOR_MT6316_H */ diff --git a/include/linux/regulator/mt6363-regulator.h b/include/linux/regulator/mt6363-regulator.h new file mode 100644 index 000000000000..f9c2220ae18c --- /dev/null +++ b/include/linux/regulator/mt6363-regulator.h @@ -0,0 +1,424 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef __LINUX_REGULATOR_MT6363_H +#define __LINUX_REGULATOR_MT6363_H + +enum { + MT6363_ID_VS2, + MT6363_ID_VBUCK1, + MT6363_ID_VBUCK2, + MT6363_ID_VBUCK3, + MT6363_ID_VBUCK4, + MT6363_ID_VBUCK5, + MT6363_ID_VBUCK6, + MT6363_ID_VBUCK7, + MT6363_ID_VS1, + MT6363_ID_VS3, + MT6363_ID_VBUCK1_SSHUB, + MT6363_ID_VBUCK2_SSHUB, + MT6363_ID_VBUCK4_SSHUB, + MT6363_ID_VSRAM_DIGRF, + MT6363_ID_VSRAM_MDFE, + MT6363_ID_VSRAM_MODEM, + MT6363_ID_VSRAM_CPUB, + MT6363_ID_VSRAM_CPUM, + MT6363_ID_VSRAM_CPUL, + MT6363_ID_VSRAM_APU, + MT6363_ID_VEMC, + MT6363_ID_VCN13, + MT6363_ID_VTREF18, + MT6363_ID_VAUX18, + MT6363_ID_VCN15, + MT6363_ID_VUFS18, + MT6363_ID_VIO18, + MT6363_ID_VM18, + MT6363_ID_VA15, + MT6363_ID_VRF18, + MT6363_ID_VRFIO18, + MT6363_ID_VIO075, + MT6363_ID_VUFS12, + MT6363_ID_VA12_1, + MT6363_ID_VA12_2, + MT6363_ID_VRF12, + MT6363_ID_VRF13, + MT6363_ID_VRF09, + MT6363_ID_ISINK_LOAD, + MT6363_MAX_REGULATOR, +}; + +#define MTK_REGULATOR_MAX_NR MT6363_MAX_REGULATOR + +/* Register */ +#define MT6363_TOP_TRAP (0x36) +#define MT6363_TOP_TMA_KEY_L (0x39e) +#define MT6363_BUCK_TOP_KEY_PROT_LO (0x142a) +#define MT6363_BUCK_VS2_OP_EN_0 (0x148d) +#define MT6363_BUCK_VS2_HW_LP_MODE (0x1498) +#define MT6363_BUCK_VBUCK1_OP_EN_0 (0x150d) +#define MT6363_BUCK_VBUCK1_HW_LP_MODE (0x1518) +#define MT6363_BUCK_VBUCK2_OP_EN_0 (0x158d) +#define MT6363_BUCK_VBUCK2_HW_LP_MODE (0x1598) +#define MT6363_BUCK_VBUCK3_OP_EN_0 (0x160d) +#define MT6363_BUCK_VBUCK3_HW_LP_MODE (0x1618) +#define MT6363_BUCK_VBUCK4_OP_EN_0 (0x168d) +#define MT6363_BUCK_VBUCK4_HW_LP_MODE (0x1698) +#define MT6363_BUCK_VBUCK5_OP_EN_0 (0x170d) +#define MT6363_BUCK_VBUCK5_HW_LP_MODE (0x1718) +#define MT6363_BUCK_VBUCK6_OP_EN_0 (0x178d) +#define MT6363_BUCK_VBUCK6_HW_LP_MODE (0x1798) +#define MT6363_BUCK_VBUCK7_OP_EN_0 (0x180d) +#define MT6363_BUCK_VBUCK7_HW_LP_MODE (0x1818) +#define MT6363_BUCK_VS1_OP_EN_0 (0x188d) +#define MT6363_BUCK_VS1_HW_LP_MODE (0x1898) +#define MT6363_BUCK_VS3_OP_EN_0 (0x190d) +#define MT6363_BUCK_VS3_HW_LP_MODE (0x1918) +#define MT6363_LDO_VCN15_HW_LP_MODE (0x1b8b) +#define MT6363_LDO_VCN15_OP_EN0 (0x1b8c) +#define MT6363_LDO_VRF09_HW_LP_MODE (0x1b99) +#define MT6363_LDO_VRF09_OP_EN0 (0x1b9a) +#define MT6363_LDO_VRF12_HW_LP_MODE (0x1ba7) +#define MT6363_LDO_VRF12_OP_EN0 (0x1ba8) +#define MT6363_LDO_VRF13_HW_LP_MODE (0x1bb5) +#define MT6363_LDO_VRF13_OP_EN0 (0x1bb6) +#define MT6363_LDO_VRF18_HW_LP_MODE (0x1bc3) +#define MT6363_LDO_VRF18_OP_EN0 (0x1bc4) +#define MT6363_LDO_VRFIO18_HW_LP_MODE (0x1bd1) +#define MT6363_LDO_VRFIO18_OP_EN0 (0x1bd2) +#define MT6363_LDO_VTREF18_HW_LP_MODE (0x1c0b) +#define MT6363_LDO_VTREF18_OP_EN0 (0x1c0c) +#define MT6363_LDO_VAUX18_HW_LP_MODE (0x1c19) +#define MT6363_LDO_VAUX18_OP_EN0 (0x1c1a) +#define MT6363_LDO_VEMC_HW_LP_MODE (0x1c27) +#define MT6363_LDO_VEMC_OP_EN0 (0x1c28) +#define MT6363_LDO_VUFS12_HW_LP_MODE (0x1c35) +#define MT6363_LDO_VUFS12_OP_EN0 (0x1c36) +#define MT6363_LDO_VUFS18_HW_LP_MODE (0x1c43) +#define MT6363_LDO_VUFS18_OP_EN0 (0x1c44) +#define MT6363_LDO_VIO18_HW_LP_MODE (0x1c51) +#define MT6363_LDO_VIO18_OP_EN0 (0x1c52) +#define MT6363_LDO_VIO075_HW_LP_MODE (0x1c8b) +#define MT6363_LDO_VIO075_OP_EN0 (0x1c8c) +#define MT6363_LDO_VA12_1_HW_LP_MODE (0x1c99) +#define MT6363_LDO_VA12_1_OP_EN0 (0x1c9a) +#define MT6363_LDO_VA12_2_HW_LP_MODE (0x1ca7) +#define MT6363_LDO_VA12_2_OP_EN0 (0x1ca8) +#define MT6363_LDO_VA15_HW_LP_MODE (0x1cb5) +#define MT6363_LDO_VA15_OP_EN0 (0x1cb6) +#define MT6363_LDO_VM18_HW_LP_MODE (0x1cc3) +#define MT6363_LDO_VM18_OP_EN0 (0x1cc4) +#define MT6363_LDO_VCN13_HW_LP_MODE (0x1d0b) +#define MT6363_LDO_VCN13_OP_EN0 (0x1d14) +#define MT6363_LDO_VSRAM_DIGRF_HW_LP_MODE (0x1d21) +#define MT6363_LDO_VSRAM_DIGRF_OP_EN0 (0x1d2a) +#define MT6363_LDO_VSRAM_MDFE_HW_LP_MODE (0x1d8b) +#define MT6363_LDO_VSRAM_MDFE_OP_EN0 (0x1d94) +#define MT6363_LDO_VSRAM_MODEM_HW_LP_MODE (0x1da6) +#define MT6363_LDO_VSRAM_MODEM_OP_EN0 (0x1daf) +#define MT6363_LDO_VSRAM_CPUB_HW_LP_MODE (0x1e0b) +#define MT6363_LDO_VSRAM_CPUB_OP_EN0 (0x1e14) +#define MT6363_LDO_VSRAM_CPUM_HW_LP_MODE (0x1e21) +#define MT6363_LDO_VSRAM_CPUM_OP_EN0 (0x1e2a) +#define MT6363_LDO_VSRAM_CPUL_HW_LP_MODE (0x1e8b) +#define MT6363_LDO_VSRAM_CPUL_OP_EN0 (0x1e94) +#define MT6363_LDO_VSRAM_APU_HW_LP_MODE (0x1ea1) +#define MT6363_LDO_VSRAM_APU_OP_EN0 (0x1eaa) +#define MT6363_RG_BUCK_VS2_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VS2_EN_SHIFT (0) +#define MT6363_RG_BUCK_VBUCK1_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK1_EN_SHIFT (1) +#define MT6363_RG_BUCK_VBUCK2_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK2_EN_SHIFT (2) +#define MT6363_RG_BUCK_VBUCK3_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK3_EN_SHIFT (3) +#define MT6363_RG_BUCK_VBUCK4_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK4_EN_SHIFT (4) +#define MT6363_RG_BUCK_VBUCK5_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK5_EN_SHIFT (5) +#define MT6363_RG_BUCK_VBUCK6_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK6_EN_SHIFT (6) +#define MT6363_RG_BUCK_VBUCK7_EN_ADDR (0x240) +#define MT6363_RG_BUCK_VBUCK7_EN_SHIFT (7) +#define MT6363_RG_BUCK_VS1_EN_ADDR (0x243) +#define MT6363_RG_BUCK_VS1_EN_SHIFT (0) +#define MT6363_RG_BUCK_VS3_EN_ADDR (0x243) +#define MT6363_RG_BUCK_VS3_EN_SHIFT (1) +#define MT6363_RG_LDO_VSRAM_DIGRF_EN_ADDR (0x243) +#define MT6363_RG_LDO_VSRAM_DIGRF_EN_SHIFT (4) +#define MT6363_RG_LDO_VSRAM_MDFE_EN_ADDR (0x243) +#define MT6363_RG_LDO_VSRAM_MDFE_EN_SHIFT (5) +#define MT6363_RG_LDO_VSRAM_MODEM_EN_ADDR (0x243) +#define MT6363_RG_LDO_VSRAM_MODEM_EN_SHIFT (6) +#define MT6363_RG_BUCK_VS2_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VS2_LP_SHIFT (0) +#define MT6363_RG_BUCK_VBUCK1_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK1_LP_SHIFT (1) +#define MT6363_RG_BUCK_VBUCK2_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK2_LP_SHIFT (2) +#define MT6363_RG_BUCK_VBUCK3_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK3_LP_SHIFT (3) +#define MT6363_RG_BUCK_VBUCK4_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK4_LP_SHIFT (4) +#define MT6363_RG_BUCK_VBUCK5_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK5_LP_SHIFT (5) +#define MT6363_RG_BUCK_VBUCK6_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK6_LP_SHIFT (6) +#define MT6363_RG_BUCK_VBUCK7_LP_ADDR (0x246) +#define MT6363_RG_BUCK_VBUCK7_LP_SHIFT (7) +#define MT6363_RG_BUCK_VS1_LP_ADDR (0x249) +#define MT6363_RG_BUCK_VS1_LP_SHIFT (0) +#define MT6363_RG_BUCK_VS3_LP_ADDR (0x249) +#define MT6363_RG_BUCK_VS3_LP_SHIFT (1) +#define MT6363_RG_LDO_VSRAM_DIGRF_LP_ADDR (0x249) +#define MT6363_RG_LDO_VSRAM_DIGRF_LP_SHIFT (4) +#define MT6363_RG_LDO_VSRAM_MDFE_LP_ADDR (0x249) +#define MT6363_RG_LDO_VSRAM_MDFE_LP_SHIFT (5) +#define MT6363_RG_LDO_VSRAM_MODEM_LP_ADDR (0x249) +#define MT6363_RG_LDO_VSRAM_MODEM_LP_SHIFT (6) +#define MT6363_RG_BUCK_VS2_VOSEL_ADDR (0x24c) +#define MT6363_RG_BUCK_VS2_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK1_VOSEL_ADDR (0x24d) +#define MT6363_RG_BUCK_VBUCK1_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK2_VOSEL_ADDR (0x24e) +#define MT6363_RG_BUCK_VBUCK2_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK3_VOSEL_ADDR (0x24f) +#define MT6363_RG_BUCK_VBUCK3_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK4_VOSEL_ADDR (0x250) +#define MT6363_RG_BUCK_VBUCK4_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK5_VOSEL_ADDR (0x251) +#define MT6363_RG_BUCK_VBUCK5_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK6_VOSEL_ADDR (0x252) +#define MT6363_RG_BUCK_VBUCK6_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK7_VOSEL_ADDR (0x253) +#define MT6363_RG_BUCK_VBUCK7_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VS1_VOSEL_ADDR (0x254) +#define MT6363_RG_BUCK_VS1_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VS3_VOSEL_ADDR (0x255) +#define MT6363_RG_BUCK_VS3_VOSEL_MASK (0xff) +#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_ADDR (0x258) +#define MT6363_RG_LDO_VSRAM_DIGRF_VOSEL_MASK (0x7f) +#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_ADDR (0x259) +#define MT6363_RG_LDO_VSRAM_MDFE_VOSEL_MASK (0x7f) +#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_ADDR (0x25a) +#define MT6363_RG_LDO_VSRAM_MODEM_VOSEL_MASK (0x7f) +#define MT6363_BUCK_VS2_WDTDBG_VOSEL_ADDR (0x142c) +#define MT6363_BUCK_VBUCK1_WDTDBG_VOSEL_ADDR (0x142d) +#define MT6363_BUCK_VBUCK2_WDTDBG_VOSEL_ADDR (0x142e) +#define MT6363_BUCK_VBUCK3_WDTDBG_VOSEL_ADDR (0x142f) +#define MT6363_BUCK_VBUCK4_WDTDBG_VOSEL_ADDR (0x1430) +#define MT6363_BUCK_VBUCK5_WDTDBG_VOSEL_ADDR (0x1431) +#define MT6363_BUCK_VBUCK6_WDTDBG_VOSEL_ADDR (0x1432) +#define MT6363_BUCK_VBUCK7_WDTDBG_VOSEL_ADDR (0x1433) +#define MT6363_BUCK_VS1_WDTDBG_VOSEL_ADDR (0x1434) +#define MT6363_BUCK_VS3_WDTDBG_VOSEL_ADDR (0x1435) +#define MT6363_RG_BUCK_VBUCK1_SSHUB_EN_ADDR (0x151a) +#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_ADDR (0x151b) +#define MT6363_RG_BUCK_VBUCK1_SSHUB_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK2_SSHUB_EN_ADDR (0x159a) +#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_ADDR (0x159b) +#define MT6363_RG_BUCK_VBUCK2_SSHUB_VOSEL_MASK (0xff) +#define MT6363_RG_BUCK_VBUCK4_SSHUB_EN_ADDR (0x169a) +#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_ADDR (0x169b) +#define MT6363_RG_BUCK_VBUCK4_SSHUB_VOSEL_MASK (0xff) +#define MT6363_RG_VS1_FCCM_ADDR (0x1994) +#define MT6363_RG_VS1_FCCM_SHIFT (0) +#define MT6363_RG_VS3_FCCM_ADDR (0x19a3) +#define MT6363_RG_VS3_FCCM_SHIFT (0) +#define MT6363_RG_VBUCK1_FCCM_ADDR (0x1a32) +#define MT6363_RG_VBUCK1_FCCM_SHIFT (0) +#define MT6363_RG_VBUCK2_FCCM_ADDR (0x1a32) +#define MT6363_RG_VBUCK2_FCCM_SHIFT (1) +#define MT6363_RG_VBUCK3_FCCM_ADDR (0x1a32) +#define MT6363_RG_VBUCK3_FCCM_SHIFT (2) +#define MT6363_RG_VS2_FCCM_ADDR (0x1a32) +#define MT6363_RG_VS2_FCCM_SHIFT (3) +#define MT6363_RG_VBUCK4_FCCM_ADDR (0x1ab2) +#define MT6363_RG_VBUCK4_FCCM_SHIFT (0) +#define MT6363_RG_VBUCK5_FCCM_ADDR (0x1ab2) +#define MT6363_RG_VBUCK5_FCCM_SHIFT (1) +#define MT6363_RG_VBUCK6_FCCM_ADDR (0x1ab2) +#define MT6363_RG_VBUCK6_FCCM_SHIFT (2) +#define MT6363_RG_VBUCK7_FCCM_ADDR (0x1ab2) +#define MT6363_RG_VBUCK7_FCCM_SHIFT (3) +#define MT6363_RG_VCN13_VOSEL_ADDR (0x1b3f) +#define MT6363_RG_VCN13_VOSEL_MASK (0xf) +#define MT6363_RG_VEMC_VOSEL_0_ADDR (0x1b40) +#define MT6363_RG_VEMC_VOSEL_0_MASK (0xf) +#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_ADDR (0x1b44) +#define MT6363_RG_LDO_VSRAM_CPUB_VOSEL_MASK (0x7f) +#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_ADDR (0x1b45) +#define MT6363_RG_LDO_VSRAM_CPUM_VOSEL_MASK (0x7f) +#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_ADDR (0x1b46) +#define MT6363_RG_LDO_VSRAM_CPUL_VOSEL_MASK (0x7f) +#define MT6363_RG_LDO_VSRAM_APU_VOSEL_ADDR (0x1b47) +#define MT6363_RG_LDO_VSRAM_APU_VOSEL_MASK (0x7f) +#define MT6363_RG_VEMC_VOCAL_0_ADDR (0x1b4b) +#define MT6363_RG_VEMC_VOCAL_0_MASK (0xf) +#define MT6363_RG_LDO_VCN15_EN_ADDR (0x1b87) +#define MT6363_RG_LDO_VCN15_EN_SHIFT (0) +#define MT6363_RG_LDO_VCN15_LP_ADDR (0x1b87) +#define MT6363_RG_LDO_VCN15_LP_SHIFT (1) +#define MT6363_RG_LDO_VRF09_EN_ADDR (0x1b95) +#define MT6363_RG_LDO_VRF09_EN_SHIFT (0) +#define MT6363_RG_LDO_VRF09_LP_ADDR (0x1b95) +#define MT6363_RG_LDO_VRF09_LP_SHIFT (1) +#define MT6363_RG_LDO_VRF12_EN_ADDR (0x1ba3) +#define MT6363_RG_LDO_VRF12_EN_SHIFT (0) +#define MT6363_RG_LDO_VRF12_LP_ADDR (0x1ba3) +#define MT6363_RG_LDO_VRF12_LP_SHIFT (1) +#define MT6363_RG_LDO_VRF13_EN_ADDR (0x1bb1) +#define MT6363_RG_LDO_VRF13_EN_SHIFT (0) +#define MT6363_RG_LDO_VRF13_LP_ADDR (0x1bb1) +#define MT6363_RG_LDO_VRF13_LP_SHIFT (1) +#define MT6363_RG_LDO_VRF18_EN_ADDR (0x1bbf) +#define MT6363_RG_LDO_VRF18_EN_SHIFT (0) +#define MT6363_RG_LDO_VRF18_LP_ADDR (0x1bbf) +#define MT6363_RG_LDO_VRF18_LP_SHIFT (1) +#define MT6363_RG_LDO_VRFIO18_EN_ADDR (0x1bcd) +#define MT6363_RG_LDO_VRFIO18_EN_SHIFT (0) +#define MT6363_RG_LDO_VRFIO18_LP_ADDR (0x1bcd) +#define MT6363_RG_LDO_VRFIO18_LP_SHIFT (1) +#define MT6363_RG_LDO_VTREF18_EN_ADDR (0x1c07) +#define MT6363_RG_LDO_VTREF18_EN_SHIFT (0) +#define MT6363_RG_LDO_VTREF18_LP_ADDR (0x1c07) +#define MT6363_RG_LDO_VTREF18_LP_SHIFT (1) +#define MT6363_RG_LDO_VAUX18_EN_ADDR (0x1c15) +#define MT6363_RG_LDO_VAUX18_EN_SHIFT (0) +#define MT6363_RG_LDO_VAUX18_LP_ADDR (0x1c15) +#define MT6363_RG_LDO_VAUX18_LP_SHIFT (1) +#define MT6363_RG_LDO_VEMC_EN_ADDR (0x1c23) +#define MT6363_RG_LDO_VEMC_EN_SHIFT (0) +#define MT6363_RG_LDO_VEMC_LP_ADDR (0x1c23) +#define MT6363_RG_LDO_VEMC_LP_SHIFT (1) +#define MT6363_RG_LDO_VUFS12_EN_ADDR (0x1c31) +#define MT6363_RG_LDO_VUFS12_EN_SHIFT (0) +#define MT6363_RG_LDO_VUFS12_LP_ADDR (0x1c31) +#define MT6363_RG_LDO_VUFS12_LP_SHIFT (1) +#define MT6363_RG_LDO_VUFS18_EN_ADDR (0x1c3f) +#define MT6363_RG_LDO_VUFS18_EN_SHIFT (0) +#define MT6363_RG_LDO_VUFS18_LP_ADDR (0x1c3f) +#define MT6363_RG_LDO_VUFS18_LP_SHIFT (1) +#define MT6363_RG_LDO_VIO18_EN_ADDR (0x1c4d) +#define MT6363_RG_LDO_VIO18_EN_SHIFT (0) +#define MT6363_RG_LDO_VIO18_LP_ADDR (0x1c4d) +#define MT6363_RG_LDO_VIO18_LP_SHIFT (1) +#define MT6363_RG_LDO_VIO075_EN_ADDR (0x1c87) +#define MT6363_RG_LDO_VIO075_EN_SHIFT (0) +#define MT6363_RG_LDO_VIO075_LP_ADDR (0x1c87) +#define MT6363_RG_LDO_VIO075_LP_SHIFT (1) +#define MT6363_RG_LDO_VA12_1_EN_ADDR (0x1c95) +#define MT6363_RG_LDO_VA12_1_EN_SHIFT (0) +#define MT6363_RG_LDO_VA12_1_LP_ADDR (0x1c95) +#define MT6363_RG_LDO_VA12_1_LP_SHIFT (1) +#define MT6363_RG_LDO_VA12_2_EN_ADDR (0x1ca3) +#define MT6363_RG_LDO_VA12_2_EN_SHIFT (0) +#define MT6363_RG_LDO_VA12_2_LP_ADDR (0x1ca3) +#define MT6363_RG_LDO_VA12_2_LP_SHIFT (1) +#define MT6363_RG_LDO_VA15_EN_ADDR (0x1cb1) +#define MT6363_RG_LDO_VA15_EN_SHIFT (0) +#define MT6363_RG_LDO_VA15_LP_ADDR (0x1cb1) +#define MT6363_RG_LDO_VA15_LP_SHIFT (1) +#define MT6363_RG_LDO_VM18_EN_ADDR (0x1cbf) +#define MT6363_RG_LDO_VM18_EN_SHIFT (0) +#define MT6363_RG_LDO_VM18_LP_ADDR (0x1cbf) +#define MT6363_RG_LDO_VM18_LP_SHIFT (1) +#define MT6363_RG_LDO_VCN13_EN_ADDR (0x1d07) +#define MT6363_RG_LDO_VCN13_EN_SHIFT (0) +#define MT6363_RG_LDO_VCN13_LP_ADDR (0x1d07) +#define MT6363_RG_LDO_VCN13_LP_SHIFT (1) +#define MT6363_LDO_VSRAM_DIGRF_WDTDBG_VOSEL_ADDR (0x1d24) +#define MT6363_LDO_VSRAM_MDFE_WDTDBG_VOSEL_ADDR (0x1d8e) +#define MT6363_LDO_VSRAM_MODEM_WDTDBG_VOSEL_ADDR (0x1da9) +#define MT6363_RG_LDO_VSRAM_CPUB_EN_ADDR (0x1e07) +#define MT6363_RG_LDO_VSRAM_CPUB_EN_SHIFT (0) +#define MT6363_RG_LDO_VSRAM_CPUB_LP_ADDR (0x1e07) +#define MT6363_RG_LDO_VSRAM_CPUB_LP_SHIFT (1) +#define MT6363_LDO_VSRAM_CPUB_WDTDBG_VOSEL_ADDR (0x1e0e) +#define MT6363_RG_LDO_VSRAM_CPUM_EN_ADDR (0x1e1d) +#define MT6363_RG_LDO_VSRAM_CPUM_EN_SHIFT (0) +#define MT6363_RG_LDO_VSRAM_CPUM_LP_ADDR (0x1e1d) +#define MT6363_RG_LDO_VSRAM_CPUM_LP_SHIFT (1) +#define MT6363_LDO_VSRAM_CPUM_WDTDBG_VOSEL_ADDR (0x1e24) +#define MT6363_RG_LDO_VSRAM_CPUL_EN_ADDR (0x1e87) +#define MT6363_RG_LDO_VSRAM_CPUL_EN_SHIFT (0) +#define MT6363_RG_LDO_VSRAM_CPUL_LP_ADDR (0x1e87) +#define MT6363_RG_LDO_VSRAM_CPUL_LP_SHIFT (1) +#define MT6363_LDO_VSRAM_CPUL_WDTDBG_VOSEL_ADDR (0x1e8e) +#define MT6363_RG_LDO_VSRAM_APU_EN_ADDR (0x1e9d) +#define MT6363_RG_LDO_VSRAM_APU_EN_SHIFT (0) +#define MT6363_RG_LDO_VSRAM_APU_LP_ADDR (0x1e9d) +#define MT6363_RG_LDO_VSRAM_APU_LP_SHIFT (1) +#define MT6363_LDO_VSRAM_APU_WDTDBG_VOSEL_ADDR (0x1ea4) +#define MT6363_RG_VTREF18_VOCAL_ADDR (0x1f08) +#define MT6363_RG_VTREF18_VOCAL_MASK (0xf) +#define MT6363_RG_VTREF18_VOSEL_ADDR (0x1f09) +#define MT6363_RG_VTREF18_VOSEL_MASK (0xf) +#define MT6363_RG_VAUX18_VOCAL_ADDR (0x1f0c) +#define MT6363_RG_VAUX18_VOCAL_MASK (0xf) +#define MT6363_RG_VAUX18_VOSEL_ADDR (0x1f0d) +#define MT6363_RG_VAUX18_VOSEL_MASK (0xf) +#define MT6363_RG_VCN15_VOCAL_ADDR (0x1f13) +#define MT6363_RG_VCN15_VOCAL_MASK (0xf) +#define MT6363_RG_VCN15_VOSEL_ADDR (0x1f14) +#define MT6363_RG_VCN15_VOSEL_MASK (0xf) +#define MT6363_RG_VUFS18_VOCAL_ADDR (0x1f17) +#define MT6363_RG_VUFS18_VOCAL_MASK (0xf) +#define MT6363_RG_VUFS18_VOSEL_ADDR (0x1f18) +#define MT6363_RG_VUFS18_VOSEL_MASK (0xf) +#define MT6363_RG_VIO18_VOCAL_ADDR (0x1f1b) +#define MT6363_RG_VIO18_VOCAL_MASK (0xf) +#define MT6363_RG_VIO18_VOSEL_ADDR (0x1f1c) +#define MT6363_RG_VIO18_VOSEL_MASK (0xf) +#define MT6363_RG_VM18_VOCAL_ADDR (0x1f1f) +#define MT6363_RG_VM18_VOCAL_MASK (0xf) +#define MT6363_RG_VM18_VOSEL_ADDR (0x1f20) +#define MT6363_RG_VM18_VOSEL_MASK (0xf) +#define MT6363_RG_VA15_VOCAL_ADDR (0x1f23) +#define MT6363_RG_VA15_VOCAL_MASK (0xf) +#define MT6363_RG_VA15_VOSEL_ADDR (0x1f24) +#define MT6363_RG_VA15_VOSEL_MASK (0xf) +#define MT6363_RG_VRF18_VOCAL_ADDR (0x1f27) +#define MT6363_RG_VRF18_VOCAL_MASK (0xf) +#define MT6363_RG_VRF18_VOSEL_ADDR (0x1f28) +#define MT6363_RG_VRF18_VOSEL_MASK (0xf) +#define MT6363_RG_VRFIO18_VOCAL_ADDR (0x1f2b) +#define MT6363_RG_VRFIO18_VOCAL_MASK (0xf) +#define MT6363_RG_VRFIO18_VOSEL_ADDR (0x1f2c) +#define MT6363_RG_VRFIO18_VOSEL_MASK (0xf) +#define MT6363_RG_VIO075_VOCAL_ADDR (0x1f31) +#define MT6363_RG_VIO075_VOCAL_MASK (0xf) +#define MT6363_RG_VIO075_VOSEL_ADDR (0x1f31) +#define MT6363_RG_VIO075_VOSEL_MASK (0x70) +#define MT6363_RG_VCN13_VOCAL_ADDR (0x1f88) +#define MT6363_RG_VCN13_VOCAL_MASK (0xf) +#define MT6363_RG_VUFS12_VOCAL_ADDR (0x1f91) +#define MT6363_RG_VUFS12_VOCAL_MASK (0xf) +#define MT6363_RG_VUFS12_VOSEL_ADDR (0x1f92) +#define MT6363_RG_VUFS12_VOSEL_MASK (0xf) +#define MT6363_RG_VA12_1_VOCAL_ADDR (0x1f95) +#define MT6363_RG_VA12_1_VOCAL_MASK (0xf) +#define MT6363_RG_VA12_1_VOSEL_ADDR (0x1f96) +#define MT6363_RG_VA12_1_VOSEL_MASK (0xf) +#define MT6363_RG_VA12_2_VOCAL_ADDR (0x1f99) +#define MT6363_RG_VA12_2_VOCAL_MASK (0xf) +#define MT6363_RG_VA12_2_VOSEL_ADDR (0x1f9a) +#define MT6363_RG_VA12_2_VOSEL_MASK (0xf) +#define MT6363_RG_VRF12_VOCAL_ADDR (0x1f9d) +#define MT6363_RG_VRF12_VOCAL_MASK (0xf) +#define MT6363_RG_VRF12_VOSEL_ADDR (0x1f9e) +#define MT6363_RG_VRF12_VOSEL_MASK (0xf) +#define MT6363_RG_VRF13_VOCAL_ADDR (0x1fa1) +#define MT6363_RG_VRF13_VOCAL_MASK (0xf) +#define MT6363_RG_VRF13_VOSEL_ADDR (0x1fa2) +#define MT6363_RG_VRF13_VOSEL_MASK (0xf) +#define MT6363_RG_VRF09_VOCAL_ADDR (0x1fa8) +#define MT6363_RG_VRF09_VOCAL_MASK (0xf) +#define MT6363_RG_VRF09_VOSEL_ADDR (0x1fa9) +#define MT6363_RG_VRF09_VOSEL_MASK (0xf) +#define MT6363_ISINK_EN_CTRL0 (0x220b) +#define MT6363_ISINK_EN_CTRL1 (0x220c) + + +#endif /* __LINUX_REGULATOR_MT6363_H */ diff --git a/include/linux/regulator/mt6373-regulator.h b/include/linux/regulator/mt6373-regulator.h new file mode 100644 index 000000000000..9aa38741c31a --- /dev/null +++ b/include/linux/regulator/mt6373-regulator.h @@ -0,0 +1,318 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef __LINUX_REGULATOR_MT6373_H +#define __LINUX_REGULATOR_MT6373_H + +enum { + MT6373_ID_VBUCK0, + MT6373_ID_VBUCK1, + MT6373_ID_VBUCK2, + MT6373_ID_VBUCK3, + MT6373_ID_VBUCK4, + MT6373_ID_VBUCK4_UFS, + MT6373_ID_VBUCK5, + MT6373_ID_VBUCK6, + MT6373_ID_VBUCK7, + MT6373_ID_VBUCK8, + MT6373_ID_VBUCK9, + MT6373_ID_VUSB, + MT6373_ID_VAUX18, + MT6373_ID_VRF13_AIF, + MT6373_ID_VRF18_AIF, + MT6373_ID_VRFIO18_AIF, + MT6373_ID_VRF09_AIF, + MT6373_ID_VRF12_AIF, + MT6373_ID_VANT18, + MT6373_ID_VSRAM_DIGRF_AIF, + MT6373_ID_VIBR, + MT6373_ID_VIO28, + MT6373_ID_VFP, + MT6373_ID_VTP, + MT6373_ID_VMCH, + MT6373_ID_VMC, + MT6373_ID_VAUD18, + MT6373_ID_VCN33_1, + MT6373_ID_VCN33_2, + MT6373_ID_VCN33_3, + MT6373_ID_VCN18IO, + MT6373_ID_VEFUSE, + MT6373_ID_VMCH_EINT_HIGH, + MT6373_ID_VMCH_EINT_LOW, + MT6373_MAX_REGULATOR, +}; + +/* Register */ +#define MT6373_BUCK_TOP_KEY_PROT_LO 0x142a +#define MT6373_TOP_CFG_ELR5 0x147 +#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_SHIFT 0 +#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_SHIFT 1 +#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_SHIFT 2 +#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_SHIFT 3 +#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_SHIFT 4 +#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_SHIFT 5 +#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_SHIFT 6 +#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_ADDR 0x240 +#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_SHIFT 7 +#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_ADDR 0x243 +#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_SHIFT 0 +#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_ADDR 0x243 +#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_SHIFT 1 +#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_SHIFT 0 +#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_SHIFT 1 +#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_SHIFT 2 +#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_SHIFT 3 +#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_SHIFT 4 +#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_SHIFT 5 +#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_SHIFT 6 +#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_ADDR 0x246 +#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_SHIFT 7 +#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_ADDR 0x249 +#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_SHIFT 0 +#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_ADDR 0x249 +#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_SHIFT 1 +#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR 0x24c +#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR 0x24d +#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR 0x24e +#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR 0x24f +#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR 0x250 +#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR 0x251 +#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR 0x252 +#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR 0x253 +#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR 0x254 +#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR 0x255 +#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_MASK 0xFF +#define MT6373_PMIC_RG_VBUCK8_FCCM_ADDR 0x199d +#define MT6373_PMIC_RG_VBUCK8_FCCM_SHIFT 6 +#define MT6373_PMIC_RG_VBUCK9_FCCM_ADDR 0x199d +#define MT6373_PMIC_RG_VBUCK9_FCCM_SHIFT 7 +#define MT6373_PMIC_RG_VBUCK0_FCCM_ADDR 0x1a32 +#define MT6373_PMIC_RG_VBUCK0_FCCM_SHIFT 0 +#define MT6373_PMIC_RG_VBUCK1_FCCM_ADDR 0x1a32 +#define MT6373_PMIC_RG_VBUCK1_FCCM_SHIFT 1 +#define MT6373_PMIC_RG_VBUCK2_FCCM_ADDR 0x1a32 +#define MT6373_PMIC_RG_VBUCK2_FCCM_SHIFT 2 +#define MT6373_PMIC_RG_VBUCK3_FCCM_ADDR 0x1a32 +#define MT6373_PMIC_RG_VBUCK3_FCCM_SHIFT 3 +#define MT6373_PMIC_RG_VBUCK4_FCCM_ADDR 0x1ab2 +#define MT6373_PMIC_RG_VBUCK4_FCCM_SHIFT 0 +#define MT6373_PMIC_RG_VBUCK5_FCCM_ADDR 0x1ab2 +#define MT6373_PMIC_RG_VBUCK5_FCCM_SHIFT 1 +#define MT6373_PMIC_RG_VBUCK6_FCCM_ADDR 0x1ab2 +#define MT6373_PMIC_RG_VBUCK6_FCCM_SHIFT 2 +#define MT6373_PMIC_RG_VBUCK7_FCCM_ADDR 0x1ab2 +#define MT6373_PMIC_RG_VBUCK7_FCCM_SHIFT 3 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_ADDR 0x1b39 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_VOSEL_MASK 0x7F +#define MT6373_PMIC_RG_LDO_VAUD18_EN_ADDR 0x1b87 +#define MT6373_PMIC_RG_LDO_VAUD18_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VAUD18_LP_ADDR 0x1b87 +#define MT6373_PMIC_RG_LDO_VAUD18_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VUSB_EN_ADDR 0x1b95 +#define MT6373_PMIC_RG_LDO_VUSB_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VUSB_LP_ADDR 0x1b95 +#define MT6373_PMIC_RG_LDO_VUSB_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VAUX18_EN_ADDR 0x1ba3 +#define MT6373_PMIC_RG_LDO_VAUX18_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VAUX18_LP_ADDR 0x1ba3 +#define MT6373_PMIC_RG_LDO_VAUX18_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_ADDR 0x1bb1 +#define MT6373_PMIC_RG_LDO_VRF13_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_ADDR 0x1bb1 +#define MT6373_PMIC_RG_LDO_VRF13_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_ADDR 0x1bbf +#define MT6373_PMIC_RG_LDO_VRF18_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_ADDR 0x1bbf +#define MT6373_PMIC_RG_LDO_VRF18_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_ADDR 0x1bcd +#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_ADDR 0x1bcd +#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VCN33_1_EN_ADDR 0x1c07 +#define MT6373_PMIC_RG_LDO_VCN33_1_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VCN33_1_LP_ADDR 0x1c07 +#define MT6373_PMIC_RG_LDO_VCN33_1_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VCN33_2_EN_ADDR 0x1c15 +#define MT6373_PMIC_RG_LDO_VCN33_2_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VCN33_2_LP_ADDR 0x1c15 +#define MT6373_PMIC_RG_LDO_VCN33_2_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VCN33_3_EN_ADDR 0x1c23 +#define MT6373_PMIC_RG_LDO_VCN33_3_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VCN33_3_LP_ADDR 0x1c23 +#define MT6373_PMIC_RG_LDO_VCN33_3_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VCN18IO_EN_ADDR 0x1c31 +#define MT6373_PMIC_RG_LDO_VCN18IO_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VCN18IO_LP_ADDR 0x1c31 +#define MT6373_PMIC_RG_LDO_VCN18IO_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_ADDR 0x1c3f +#define MT6373_PMIC_RG_LDO_VRF09_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_ADDR 0x1c3f +#define MT6373_PMIC_RG_LDO_VRF09_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_ADDR 0x1c4d +#define MT6373_PMIC_RG_LDO_VRF12_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_ADDR 0x1c4d +#define MT6373_PMIC_RG_LDO_VRF12_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VANT18_EN_ADDR 0x1c87 +#define MT6373_PMIC_RG_LDO_VANT18_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VANT18_LP_ADDR 0x1c87 +#define MT6373_PMIC_RG_LDO_VANT18_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VEFUSE_EN_ADDR 0x1ca3 +#define MT6373_PMIC_RG_LDO_VEFUSE_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VEFUSE_LP_ADDR 0x1ca3 +#define MT6373_PMIC_RG_LDO_VEFUSE_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VMCH_EN_ADDR 0x1cb1 +#define MT6373_PMIC_RG_LDO_VMCH_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VMCH_LP_ADDR 0x1cb1 +#define MT6373_PMIC_RG_LDO_VMCH_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VMC_EN_ADDR 0x1cc0 +#define MT6373_PMIC_RG_LDO_VMC_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VMC_LP_ADDR 0x1cc0 +#define MT6373_PMIC_RG_LDO_VMC_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VIBR_EN_ADDR 0x1cce +#define MT6373_PMIC_RG_LDO_VIBR_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VIBR_LP_ADDR 0x1cce +#define MT6373_PMIC_RG_LDO_VIBR_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VIO28_EN_ADDR 0x1d07 +#define MT6373_PMIC_RG_LDO_VIO28_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VIO28_LP_ADDR 0x1d07 +#define MT6373_PMIC_RG_LDO_VIO28_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VFP_EN_ADDR 0x1d15 +#define MT6373_PMIC_RG_LDO_VFP_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VFP_LP_ADDR 0x1d15 +#define MT6373_PMIC_RG_LDO_VFP_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VTP_EN_ADDR 0x1d23 +#define MT6373_PMIC_RG_LDO_VTP_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VTP_LP_ADDR 0x1d23 +#define MT6373_PMIC_RG_LDO_VTP_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VSIM1_EN_ADDR 0x1d31 +#define MT6373_PMIC_RG_LDO_VSIM1_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VSIM1_LP_ADDR 0x1d31 +#define MT6373_PMIC_RG_LDO_VSIM1_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VSIM2_EN_ADDR 0x1d40 +#define MT6373_PMIC_RG_LDO_VSIM2_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VSIM2_LP_ADDR 0x1d40 +#define MT6373_PMIC_RG_LDO_VSIM2_LP_SHIFT 1 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_ADDR 0x1d87 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_EN_SHIFT 0 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_ADDR 0x1d87 +#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_LP_SHIFT 1 +#define MT6373_PMIC_RG_VAUX18_VOCAL_ADDR 0x1e08 +#define MT6373_PMIC_RG_VAUX18_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VAUX18_VOSEL_ADDR 0x1e09 +#define MT6373_PMIC_RG_VAUX18_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VUSB_VOCAL_ADDR 0x1e0c +#define MT6373_PMIC_RG_VUSB_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VUSB_VOSEL_ADDR 0x1e0d +#define MT6373_PMIC_RG_VUSB_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR 0x1e10 +#define MT6373_PMIC_RG_VCN33_1_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR 0x1e11 +#define MT6373_PMIC_RG_VCN33_1_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR 0x1e14 +#define MT6373_PMIC_RG_VCN33_2_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR 0x1e15 +#define MT6373_PMIC_RG_VCN33_2_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR 0x1e18 +#define MT6373_PMIC_RG_VCN33_3_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR 0x1e19 +#define MT6373_PMIC_RG_VCN33_3_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VMCH_VOCAL_ADDR 0x1e1c +#define MT6373_PMIC_RG_VMCH_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VMCH_VOSEL_ADDR 0x1e1d +#define MT6373_PMIC_RG_VMCH_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR 0x1e20 +#define MT6373_PMIC_RG_VEFUSE_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR 0x1e21 +#define MT6373_PMIC_RG_VEFUSE_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VMC_VOCAL_ADDR 0x1e24 +#define MT6373_PMIC_RG_VMC_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VMC_VOSEL_ADDR 0x1e25 +#define MT6373_PMIC_RG_VMC_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VIBR_VOCAL_ADDR 0x1e28 +#define MT6373_PMIC_RG_VIBR_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VIBR_VOSEL_ADDR 0x1e29 +#define MT6373_PMIC_RG_VIBR_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VIO28_VOCAL_ADDR 0x1e2c +#define MT6373_PMIC_RG_VIO28_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VIO28_VOSEL_ADDR 0x1e2d +#define MT6373_PMIC_RG_VIO28_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VFP_VOCAL_ADDR 0x1e30 +#define MT6373_PMIC_RG_VFP_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VFP_VOSEL_ADDR 0x1e31 +#define MT6373_PMIC_RG_VFP_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VTP_VOCAL_ADDR 0x1e34 +#define MT6373_PMIC_RG_VTP_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VTP_VOSEL_ADDR 0x1e35 +#define MT6373_PMIC_RG_VTP_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VSIM1_VOCAL_ADDR 0x1e38 +#define MT6373_PMIC_RG_VSIM1_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VSIM1_VOSEL_ADDR 0x1e39 +#define MT6373_PMIC_RG_VSIM1_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VSIM2_VOCAL_ADDR 0x1e3c +#define MT6373_PMIC_RG_VSIM2_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VSIM2_VOSEL_ADDR 0x1e3d +#define MT6373_PMIC_RG_VSIM2_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VAUD18_VOCAL_ADDR 0x1e88 +#define MT6373_PMIC_RG_VAUD18_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VAUD18_VOSEL_ADDR 0x1e89 +#define MT6373_PMIC_RG_VAUD18_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR 0x1e8c +#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR 0x1e8d +#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR 0x1e90 +#define MT6373_PMIC_RG_VCN18IO_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR 0x1e91 +#define MT6373_PMIC_RG_VCN18IO_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR 0x1e94 +#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR 0x1e95 +#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VANT18_VOCAL_ADDR 0x1e98 +#define MT6373_PMIC_RG_VANT18_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VANT18_VOSEL_ADDR 0x1e99 +#define MT6373_PMIC_RG_VANT18_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR 0x1f08 +#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR 0x1f09 +#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR 0x1f0c +#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR 0x1f0d +#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_MASK 0xF +#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR 0x1f88 +#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_MASK 0xF +#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR 0x1f89 +#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_MASK 0xF + +#define MT6373_LDO_VMCH_EINT 0x1cbf +#define MT6373_PMIC_RG_LDO_VMCH_EINT_EN_MASK 0x1 +#define MT6373_PMIC_RG_LDO_VMCH_EINT_POL_MASK 0x4 +#define MT6373_PMIC_RG_LDO_VMCH_EINT_DB_MASK 0x10 + +#endif /* __LINUX_REGULATOR_MT6373_H */ From patchwork Fri Mar 14 07:32:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?THUgVGFuZyAo5rGk55KQKQ==?= X-Patchwork-Id: 14016377 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB864198845; Fri, 14 Mar 2025 07:55:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938936; cv=none; b=fp0jP0m/iWtz+cJAG/rBh1PealG1uyLoXZqcYZh0i0a8hV3g/IdAhVugz2+a9bFhidcH8D1/M2rpJbjXSFGuDRsdQjfp9al92SMbjPmeh4rB3FYMO3TYZK/WEdKWLX0tVSEOWPoSNPSL6ZHiabjZrQ6mPE10X680sBpecR3Ca1o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938936; c=relaxed/simple; bh=gSZ1vfvttshkX70ytTykwb3n1ENaSrc0Ac3KZVRMGfI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tnxozv2u8trT4vX68zXjWNZBhyNz2TnaOguX3H2wt8evEpJOO7+/8U83MkLXWoeE2KRZ4xelVt+bg08I/G1aXahs0U1okU33LoASqMs4WPovSgrBTodaSM6E4DWU5L/XcYPrmL3GTtNDw4XFhosYL6i6fENGOaw15QrnTaxRtIA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=N7/txmfl; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="N7/txmfl" X-UUID: b070a75a00a911f0aae1fd9735fae912-20250314 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=pVWm7uFv02O/ZDF60tnLZJcnGk12CQQp+MXAlWuZspM=; b=N7/txmflyfrpDjdDklEoSDmuzCiPdmN3TUs5VDju99AlD1vWr6BwCTOjczOADABBuEXe5/DBG1Q/mSS9RhGG08IIHOFA6O+J3M2qzqMwc+8Y7GKglEjJLBzdPGGzsFiszWx1i2MjG0EIsvAAX/9ptrqJcy5km3M1mNsP4GtZUDs=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:183bc88c-59fc-4bf2-a061-e824b5389180,IP:0,UR L:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION:r elease,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:32381a4a-a527-43d8-8af6-bc8b32d9f5e9,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: b070a75a00a911f0aae1fd9735fae912-20250314 Received: from mtkmbs09n2.mediatek.inc [(172.21.101.94)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 752664611; Fri, 14 Mar 2025 15:55:25 +0800 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by MTKMBS14N1.mediatek.inc (172.21.101.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 14 Mar 2025 15:55:24 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 14 Mar 2025 15:55:23 +0800 From: Lu.Tang To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dmitry Torokhov , Lee Jones , Matthias Brugger , AngeloGioacchino Del Regno , Sean Wang , Linus Walleij , Liam Girdwood , Mark Brown , Stephen Boyd , Chen Zhong , Sen Chu CC: , , , , , , , , Lu.Tang Subject: [PATCH 3/5] pmic: mediatek: Add spmi pmic mfd driver Date: Fri, 14 Mar 2025 15:32:29 +0800 Message-ID: <20250314073307.25092-4-Lu.Tang@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250314073307.25092-1-Lu.Tang@mediatek.com> References: <20250314073307.25092-1-Lu.Tang@mediatek.com> Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Lu.Tang" Add spmi pmic mfd driver for mt8196 Signed-off-by: Lu Tang --- drivers/mfd/Kconfig | 26 ++ drivers/mfd/Makefile | 2 + drivers/mfd/mt6685-core.c | 83 +++++ drivers/mfd/mtk-spmi-pmic.c | 518 +++++++++++++++++++++++++++ include/linux/mfd/mt6363/core.h | 134 +++++++ include/linux/mfd/mt6363/registers.h | 168 +++++++++ include/linux/mfd/mt6373/core.h | 94 +++++ include/linux/mfd/mt6373/registers.h | 53 +++ 8 files changed, 1078 insertions(+) create mode 100644 drivers/mfd/mt6685-core.c create mode 100644 drivers/mfd/mtk-spmi-pmic.c create mode 100644 include/linux/mfd/mt6363/core.h create mode 100644 include/linux/mfd/mt6363/registers.h create mode 100644 include/linux/mfd/mt6373/core.h create mode 100644 include/linux/mfd/mt6373/registers.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d44c69bb3dfd..a62625566893 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1030,6 +1030,32 @@ config MFD_MT6397 accessing the device; additional drivers must be enabled in order to use the functionality of the device. +config MFD_MT6685 + tristate "MT6685 SPMI PMIC" + depends on OF + depends on SPMI + select REGMAP_SPMI + select REGMAP_IRQ + help + This enables support for the Mediatek SPMI PMICs. + These PMICs are currently used with the Mediatek series of + SoCs. Note, that this will only be useful paired with descriptions + of the independent functions as children nodes in the device tree. + +config MFD_MTK_SPMI_PMIC + tristate "Mediatek SPMI PMICs" + depends on OF + depends on SPMI + select REGMAP_SPMI + help + This enables support for the Mediatek SPMI PMICs. + These PMICs are currently used with the MT63xx series of + SoCs. Note, that this will only be useful paired with descriptions + of the independent functions as children nodes in the device tree. + + Say M here if you want to include support for the SPMI PMIC + series as a module. The module will be called "mtk-spmi-pmic". + config MFD_MENF21BMC tristate "MEN 14F021P00 Board Management Controller Support" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 9220eaf7cf12..b8cb34284e56 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -182,6 +182,8 @@ obj-$(CONFIG_MFD_MT6360) += mt6360-core.o obj-$(CONFIG_MFD_MT6370) += mt6370.o mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o obj-$(CONFIG_MFD_MT6397) += mt6397.o +obj-$(CONFIG_MFD_MT6685) += mt6685-core.o +obj-$(CONFIG_MFD_MTK_SPMI_PMIC) += mtk-spmi-pmic.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o diff --git a/drivers/mfd/mt6685-core.c b/drivers/mfd/mt6685-core.c new file mode 100644 index 000000000000..c71008184666 --- /dev/null +++ b/drivers/mfd/mt6685-core.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 MediaTek Inc. + * + */ + +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell mt6685_devs[] = { + { + .name = "mt6685-clkbuf", + .of_compatible = "mediatek,mt6685-clkbuf", + }, { + .name = "mt6685-tb-clkbuf", + .of_compatible = "mediatek,mt6685-tb-clkbuf", + }, { + .name = "mt6685-rtc", + .of_compatible = "mediatek,mt6685-rtc", + }, { + .name = "mt6685-audclk", + .of_compatible = "mediatek,mt6685-audclk", + }, { + .name = "mt6685-consys", + .of_compatible = "mediatek,mt6685-consys", + }, { + .name = "mt6685-gps", + .of_compatible = "mediatek,mt6685-gps", + } +}; + +static const struct regmap_config spmi_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x2000, + .fast_io = true, + .use_single_read = true, + .use_single_write = true +}; + +static int mt6685_spmi_probe(struct spmi_device *sdev) +{ + int ret; + struct regmap *regmap; + + regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&sdev->dev, "Failed to init mt6685 regmap: %ld\n", PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + ret = devm_mfd_add_devices(&sdev->dev, -1, mt6685_devs, + ARRAY_SIZE(mt6685_devs), NULL, 0, NULL); + if (ret) { + dev_err(&sdev->dev, "Failed to add child devices: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id mt6685_id_table[] = { + { .compatible = "mediatek,mt6685", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt6685_id_table); + +static struct spmi_driver mt6685_spmi_driver = { + .probe = mt6685_spmi_probe, + .driver = { + .name = "mt6685", + .of_match_table = mt6685_id_table, + }, +}; +module_spmi_driver(mt6685_spmi_driver); + +MODULE_DESCRIPTION("Mediatek SPMI MT6685 Clock IC driver"); +MODULE_AUTHOR("Lu Tang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mtk-spmi-pmic.c b/drivers/mfd/mtk-spmi-pmic.c new file mode 100644 index 000000000000..4c4bed5e991a --- /dev/null +++ b/drivers/mfd/mtk-spmi-pmic.c @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MTK_SPMI_PMIC_REG_WIDTH 8 +#define PMIC_SWCID 0xB +#define PMIC_MT6316_SWCID 0x20B +#define RCS_INT_DONE 0x41B + +struct irq_top_t { + int hwirq_base; + unsigned int num_int_regs; + unsigned int en_reg; + unsigned int en_reg_shift; + unsigned int sta_reg; + unsigned int sta_reg_shift; + unsigned int top_offset; +}; + +struct mtk_spmi_pmic_data { + const struct mfd_cell *cells; + int cell_size; + unsigned int num_top; + unsigned int num_pmic_irqs; + unsigned short top_int_status_reg; + struct irq_top_t *pmic_ints; + unsigned int cid_addr; +}; + +struct pmic_core { + struct device *dev; + struct spmi_device *sdev; + struct regmap *regmap; + u16 chip_id; + int irq; + bool *enable_hwirq; + bool *cache_hwirq; + struct mutex irqlock; + struct irq_domain *irq_domain; + const struct mtk_spmi_pmic_data *chip_data; +}; + +static const struct resource mt6363_regulators_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN15_OC, "VCN15"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VCN13_OC, "VCN13"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF09_OC, "VRF09"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF12_OC, "VRF12"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF13_OC, "VRF13"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRF18_OC, "VRF18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VRFIO18_OC, "VRFIO18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_MDFE_OC, "VSRAM_MDFE"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VTREF18_OC, "VTREF18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VSRAM_APU_OC, "VSRAM_APU"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VAUX18_OC, "VAUX18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VEMC_OC, "VEMC"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS12_OC, "VUFS12"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VUFS18_OC, "VUFS18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO18_OC, "VIO18"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VIO075_OC, "VIO075"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_1_OC, "VA12_1"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA12_2_OC, "VA12_2"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VA15_OC, "VA15"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_VM18_OC, "VM18"), +}; + +static const struct resource mt6363_keys_resources[] = { + DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY), + DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY), + DEFINE_RES_IRQ(MT6363_IRQ_PWRKEY_R), + DEFINE_RES_IRQ(MT6363_IRQ_HOMEKEY_R), +}; + +static const struct resource mt6363_lvsys_notify_resources[] = { + /* MT6363 LVSYS interrupt name is contrary, + * we name LVSYS_R to MT6363_IRQ_NI_LVSYS_INT_FALLING; + * LVSYS_F to MT6363_IRQ_NI_LVSYS_INT_RISING + */ + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_FALLING, "LVSYS_R"), + DEFINE_RES_IRQ_NAMED(MT6363_IRQ_NI_LVSYS_INT_RISING, "LVSYS_F"), +}; + +static const struct resource mt6373_regulators_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VUSB_OC, "VUSB"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VAUX18_OC, "VAUX18"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF13_AIF_OC, "VRF13_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF18_AIF_OC, "VRF18_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRFIO18_AIF_OC, "VRFIO18_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_1_OC, "VCN33_1"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_2_OC, "VCN33_2"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN33_3_OC, "VCN33_3"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VCN18IO_OC, "VCN18IO"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF09_AIF_OC, "VRF09_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VRF12_AIF_OC, "VRF12_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VANT18_OC, "VANT18"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VSRAM_DIGRF_AIF_OC, "VSRAM_DIGRF_AIF"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VEFUSE_OC, "VEFUSE"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMCH_OC, "VMCH"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VMC_OC, "VMC"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIBR_OC, "VIBR"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VIO28_OC, "VIO28"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VFP_OC, "VFP"), + DEFINE_RES_IRQ_NAMED(MT6373_IRQ_VTP_OC, "VTP"), +}; + +static const struct mfd_cell mt6363_devs[] = { + { + .name = "mt6363-auxadc", + .of_compatible = "mediatek,mt6363-auxadc", + }, { + .name = "mtk-dynamic-loading-throttling", + .of_compatible = "mediatek,mt6363-dynamic_loading_throttling", + }, { + .name = "mt6363-efuse", + .of_compatible = "mediatek,mt6363-efuse", + }, { + .name = "mt6363-regulator", + .num_resources = ARRAY_SIZE(mt6363_regulators_resources), + .resources = mt6363_regulators_resources, + .of_compatible = "mediatek,mt6363-regulator", + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6363_keys_resources), + .resources = mt6363_keys_resources, + .of_compatible = "mediatek,mt6363-keys" + }, { + .name = "mt6363-consys", + .of_compatible = "mediatek,mt6363-consys", + }, { + .name = "mt6363-lvsys-notify", + .num_resources = ARRAY_SIZE(mt6363_lvsys_notify_resources), + .resources = mt6363_lvsys_notify_resources, + .of_compatible = "mediatek,mt6363-lvsys-notify", + }, { + .name = "mt6363-pinctrl", + .of_compatible = "mediatek,mt6363-pinctrl", + }, +}; + +static const struct mfd_cell mt6373_devs[] = { + { + .name = "mt6373-regulator", + .num_resources = ARRAY_SIZE(mt6373_regulators_resources), + .resources = mt6373_regulators_resources, + .of_compatible = "mediatek,mt6373-regulator", + }, { + .name = "mt6373-auxadc", + .of_compatible = "mediatek,mt6373-auxadc", + }, { + .name = "mt6373-efuse", + .of_compatible = "mediatek,mt6373-efuse", + }, { + .name = "mt6373-consys", + .of_compatible = "mediatek,mt6373-consys", + }, { + .name = "mt6373-pinctrl", + .of_compatible = "mediatek,mt6373-pinctrl", + }, +}; + +static struct irq_top_t mt6363_ints[] = { + MT6363_TOP_GEN(BUCK), + MT6363_TOP_GEN(LDO), + MT6363_TOP_GEN(PSC), + MT6363_TOP_GEN(MISC), + MT6363_TOP_GEN(HK), + MT6363_TOP_GEN(BM), +}; + + +static struct irq_top_t mt6373_ints[] = { + MT6373_TOP_GEN(BUCK), + MT6373_TOP_GEN(LDO), + MT6373_TOP_GEN(MISC), +}; + +static const struct mtk_spmi_pmic_data mt6316_data = { + .num_pmic_irqs = 0, + .cid_addr = PMIC_MT6316_SWCID, +}; + +static const struct mtk_spmi_pmic_data mt6363_data = { + .cells = mt6363_devs, + .cell_size = ARRAY_SIZE(mt6363_devs), + .num_top = ARRAY_SIZE(mt6363_ints), + .num_pmic_irqs = MT6363_IRQ_NR, + .top_int_status_reg = MT6363_TOP_INT_STATUS1, + .pmic_ints = mt6363_ints, +}; + +static const struct mtk_spmi_pmic_data mt6373_data = { + .cells = mt6373_devs, + .cell_size = ARRAY_SIZE(mt6373_devs), + .num_top = ARRAY_SIZE(mt6373_ints), + .num_pmic_irqs = MT6373_IRQ_NR, + .top_int_status_reg = MT6373_TOP_INT_STATUS1, + .pmic_ints = mt6373_ints, +}; + +static void mtk_spmi_pmic_irq_enable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct pmic_core *core = irq_data_get_irq_chip_data(data); + + core->enable_hwirq[hwirq] = true; +} + +static void mtk_spmi_pmic_irq_disable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct pmic_core *core = irq_data_get_irq_chip_data(data); + + core->enable_hwirq[hwirq] = false; +} + +static void mtk_spmi_pmic_irq_lock(struct irq_data *data) +{ + struct pmic_core *core = irq_data_get_irq_chip_data(data); + + mutex_lock(&core->irqlock); +} + +static void mtk_spmi_pmic_irq_sync_unlock(struct irq_data *data) +{ + unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift; + struct irq_top_t *pmic_int; + struct pmic_core *core = irq_data_get_irq_chip_data(data); + const struct mtk_spmi_pmic_data *chip_data = core->chip_data; + + for (i = 0; i < chip_data->num_pmic_irqs; i++) { + if (core->enable_hwirq[i] == core->cache_hwirq[i]) + continue; + + /* Find out the IRQ group */ + top_gp = 0; + while ((top_gp + 1) < chip_data->num_top && + i >= chip_data->pmic_ints[top_gp + 1].hwirq_base) + top_gp++; + + pmic_int = &(chip_data->pmic_ints[top_gp]); + /* Find the IRQ registers */ + gp_offset = i - pmic_int->hwirq_base; + int_regs = gp_offset / MTK_SPMI_PMIC_REG_WIDTH; + shift = gp_offset % MTK_SPMI_PMIC_REG_WIDTH; + en_reg = pmic_int->en_reg + (pmic_int->en_reg_shift * int_regs); + + regmap_update_bits(core->regmap, en_reg, BIT(shift), + core->enable_hwirq[i] << shift); + core->cache_hwirq[i] = core->enable_hwirq[i]; + } + mutex_unlock(&core->irqlock); +} + +static struct irq_chip mtk_spmi_pmic_irq_chip = { + .name = "spmi-pmic-irq", + .flags = IRQCHIP_SKIP_SET_WAKE, + .irq_enable = mtk_spmi_pmic_irq_enable, + .irq_disable = mtk_spmi_pmic_irq_disable, + .irq_bus_lock = mtk_spmi_pmic_irq_lock, + .irq_bus_sync_unlock = mtk_spmi_pmic_irq_sync_unlock, +}; + +static void mtk_spmi_pmic_irq_sp_handler(struct pmic_core *core, + unsigned int top_gp) +{ + unsigned int irq_status = 0, sta_reg, status; + unsigned int hwirq, virq; + int ret, i, j; + struct irq_top_t *pmic_int; + const struct mtk_spmi_pmic_data *chip_data = core->chip_data; + + for (i = 0; i < chip_data->pmic_ints[top_gp].num_int_regs; i++) { + pmic_int = &(chip_data->pmic_ints[top_gp]); + sta_reg = pmic_int->sta_reg + (pmic_int->sta_reg_shift * i); + + ret = regmap_read(core->regmap, sta_reg, &irq_status); + if (ret) { + dev_err(core->dev, + "Failed to read irq status: %d\n", ret); + return; + } + + if (!irq_status) + continue; + + status = irq_status; + do { + j = __ffs(status); + + hwirq = pmic_int->hwirq_base + MTK_SPMI_PMIC_REG_WIDTH * i + j; + + virq = irq_find_mapping(core->irq_domain, hwirq); + dev_info(core->dev, "[%x]Reg[0x%x]=0x%x,hwirq=%d\n", + core->chip_id, sta_reg, irq_status, hwirq); + if (virq) + handle_nested_irq(virq); + + status &= ~BIT(j); + } while (status); + + regmap_write(core->regmap, sta_reg, irq_status); + } +} + +static irqreturn_t mtk_spmi_pmic_irq_handler(int irq, void *data) +{ + int ret; + unsigned int bit, i, top_irq_status = 0; + struct pmic_core *core = data; + const struct mtk_spmi_pmic_data *chip_data = core->chip_data; + + ret = regmap_read(core->regmap, chip_data->top_int_status_reg, + &top_irq_status); + if (ret) { + dev_err(core->dev, + "Failed to read status from the device, ret=%d\n", ret); + return IRQ_NONE; + } + + dev_info(core->dev, "top_irq_sts:0x%x\n", top_irq_status); + for (i = 0; i < chip_data->num_top; i++) { + bit = BIT(chip_data->pmic_ints[i].top_offset); + if (top_irq_status & bit) + mtk_spmi_pmic_irq_sp_handler(core, i); + } + + ret = regmap_write(core->regmap, RCS_INT_DONE, 1); + if (ret) { + dev_err(core->dev, + "Failed to clear RCS flag, ret=%d\n", ret); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int mtk_spmi_pmic_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + struct pmic_core *core = d->host_data; + + irq_set_chip_data(irq, core); + irq_set_chip_and_handler(irq, &mtk_spmi_pmic_irq_chip, + handle_level_irq); + irq_set_nested_thread(irq, 1); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops pmic_irq_domain_ops = { + .map = mtk_spmi_pmic_irq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int mtk_spmi_pmic_irq_init(struct pmic_core *core) +{ + int i, j, ret; + unsigned int en_reg, sta_reg; + const struct mtk_spmi_pmic_data *chip_data = core->chip_data; + + mutex_init(&core->irqlock); + core->enable_hwirq = devm_kcalloc(core->dev, + chip_data->num_pmic_irqs, + sizeof(bool), GFP_KERNEL); + if (!core->enable_hwirq) + return -ENOMEM; + + core->cache_hwirq = devm_kcalloc(core->dev, + chip_data->num_pmic_irqs, + sizeof(bool), GFP_KERNEL); + if (!core->cache_hwirq) + return -ENOMEM; + + /* Disable all interrupt for initializing */ + for (i = 0; i < chip_data->num_top; i++) { + for (j = 0; j < chip_data->pmic_ints[i].num_int_regs; j++) { + en_reg = chip_data->pmic_ints[i].en_reg + + chip_data->pmic_ints[i].en_reg_shift * j; + regmap_write(core->regmap, en_reg, 0); + sta_reg = chip_data->pmic_ints[i].sta_reg + + chip_data->pmic_ints[i].sta_reg_shift * j; + regmap_write(core->regmap, sta_reg, 0xFF); + } + } + regmap_write(core->regmap, RCS_INT_DONE, 1); + + core->irq_domain = irq_domain_add_linear(core->dev->of_node, + chip_data->num_pmic_irqs, + &pmic_irq_domain_ops, + core); + if (!core->irq_domain) { + dev_err(core->dev, "Could not create IRQ domain\n"); + return -ENODEV; + } + + ret = devm_request_threaded_irq(core->dev, core->irq, NULL, + mtk_spmi_pmic_irq_handler, IRQF_ONESHOT, + mtk_spmi_pmic_irq_chip.name, core); + if (ret) { + dev_err(core->dev, "Failed to register IRQ=%d, ret=%d\n", + core->irq, ret); + return ret; + } + + enable_irq_wake(core->irq); + return ret; +} + +static const struct regmap_config spmi_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xffff, + .fast_io = true, +}; + +static int mtk_spmi_pmic_probe(struct spmi_device *sdev) +{ + int ret; + unsigned int id; + struct device_node *np = sdev->dev.of_node; + struct pmic_core *core; + const struct mtk_spmi_pmic_data *chip_data; + + core = devm_kzalloc(&sdev->dev, sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + core->sdev = sdev; + core->dev = &sdev->dev; + chip_data = (struct mtk_spmi_pmic_data *)of_device_get_match_data(&sdev->dev); + if (!chip_data) + return -ENODEV; + + core->chip_data = chip_data; + core->regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); + if (IS_ERR(core->regmap)) + return PTR_ERR(core->regmap); + if (chip_data->cid_addr) + ret = regmap_read(core->regmap, chip_data->cid_addr, &id); + else + ret = regmap_read(core->regmap, PMIC_SWCID, &id); + if (ret || id == 0) { + dev_err(&sdev->dev, "Failed to read chip id: %d\n", ret); + return ret; + } + + core->chip_id = id; + + if (chip_data->num_pmic_irqs) { + core->irq = of_irq_get(np, 0); + if (core->irq < 0) + dev_err(&sdev->dev, "Failed to get irq(%d)\n", core->irq); + + ret = mtk_spmi_pmic_irq_init(core); + if (ret) + dev_err(&sdev->dev, "IRQ_init failed(%d)\n", core->irq); + + ret = devm_mfd_add_devices(&sdev->dev, -1, chip_data->cells, + chip_data->cell_size, NULL, 0, + core->irq_domain); + if (ret) { + irq_domain_remove(core->irq_domain); + dev_err(&sdev->dev, "Failed to add mfd devices: %d\n", ret); + return ret; + } + } else { + ret = devm_of_platform_populate(&sdev->dev); + if (ret) { + dev_err(&sdev->dev, "Failed to platform populate: %d\n", ret); + return ret; + } + } + + device_init_wakeup(&sdev->dev, true); + + dev_dbg(&sdev->dev, "probe chip id=0x%x done\n", core->chip_id); + + return ret; +} + +static const struct of_device_id mtk_spmi_pmic_of_match[] = { + { .compatible = "mediatek,mt6316", .data = &mt6316_data, }, + { .compatible = "mediatek,mt6363", .data = &mt6363_data, }, + { .compatible = "mediatek,mt6373", .data = &mt6373_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, mtk_spmi_pmic_of_match); + +static struct spmi_driver mtk_spmi_pmic_driver = { + .driver = { + .name = "mtk-spmi-pmic", + .of_match_table = of_match_ptr(mtk_spmi_pmic_of_match), + }, + .probe = mtk_spmi_pmic_probe, +}; +module_spmi_driver(mtk_spmi_pmic_driver); + +MODULE_DESCRIPTION("Mediatek SPMI PMIC driver"); +MODULE_ALIAS("spmi:spmi-pmic"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Argus Lin "); +MODULE_AUTHOR("Jeter Chen "); +MODULE_AUTHOR("Lu Tang "); diff --git a/include/linux/mfd/mt6363/core.h b/include/linux/mfd/mt6363/core.h new file mode 100644 index 000000000000..3243a52da34d --- /dev/null +++ b/include/linux/mfd/mt6363/core.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MFD_MT6363_CORE_H__ +#define __MFD_MT6363_CORE_H__ + +#define MT6363_REG_WIDTH 8 + +enum mt6363_irq_top_status_shift { + MT6363_BUCK_TOP = 0, + MT6363_LDO_TOP, + MT6363_PSC_TOP, + MT6363_MISC_TOP, + MT6363_HK_TOP, + MT6363_SCK_TOP, + MT6363_BM_TOP, + MT6363_AUD_TOP, +}; + +enum mt6363_irq_numbers { + MT6363_IRQ_VS2_OC = 0, + MT6363_IRQ_VBUCK1_OC, + MT6363_IRQ_VBUCK2_OC, + MT6363_IRQ_VBUCK3_OC, + MT6363_IRQ_VBUCK4_OC, + MT6363_IRQ_VBUCK5_OC, + MT6363_IRQ_VBUCK6_OC, + MT6363_IRQ_VBUCK7_OC, + MT6363_IRQ_VS1_OC, + MT6363_IRQ_VS3_OC, + MT6363_IRQ_VCN15_OC = 16, + MT6363_IRQ_VCN13_OC, + MT6363_IRQ_VRF09_OC, + MT6363_IRQ_VRF12_OC, + MT6363_IRQ_VRF13_OC, + MT6363_IRQ_VRF18_OC, + MT6363_IRQ_VRFIO18_OC, + MT6363_IRQ_VSRAM_DIGRF_OC, + MT6363_IRQ_VSRAM_MDFE_OC, + MT6363_IRQ_VSRAM_MODEM_OC, + MT6363_IRQ_VTREF18_OC, + MT6363_IRQ_VSRAM_CPUB_OC, + MT6363_IRQ_VSRAM_CPUM_OC, + MT6363_IRQ_VSRAM_CPUL_OC, + MT6363_IRQ_VSRAM_APU_OC, + MT6363_IRQ_VAUX18_OC, + MT6363_IRQ_VEMC_OC, + MT6363_IRQ_VUFS12_OC, + MT6363_IRQ_VUFS18_OC, + MT6363_IRQ_VIO18_OC, + MT6363_IRQ_VIO075_OC, + MT6363_IRQ_VA12_1_OC, + MT6363_IRQ_VA12_2_OC, + MT6363_IRQ_VA15_OC, + MT6363_IRQ_VM18_OC, + MT6363_IRQ_PWRKEY = 48, + MT6363_IRQ_HOMEKEY, + MT6363_IRQ_HOMEKEY_2, + MT6363_IRQ_PWRKEY_R, + MT6363_IRQ_HOMEKEY_R, + MT6363_IRQ_HOMEKEY_2_R, + MT6363_IRQ_NI_LVSYS_INT_FALLING, + MT6363_IRQ_NI_LVSYS_INT_RISING, + MT6363_IRQ_CHRDET_LEVEL, + MT6363_IRQ_CHRDET_EDGE, + MT6363_IRQ_RCS0 = 64, + MT6363_IRQ_SPMI_CMD_ALERT, + MT6363_IRQ_BM_PROTREG = 70, + MT6363_IRQ_BUCK_PROTREG = 72, + MT6363_IRQ_LDO_PROTREG, + MT6363_IRQ_PSC_PROTREG, + MT6363_IRQ_PLT_PROTREG, + MT6363_IRQ_HK_PROTREG, + MT6363_IRQ_TOP_PROTREG = 79, + MT6363_IRQ_BAT_H, + MT6363_IRQ_BAT_L, + MT6363_IRQ_BAT2_H, + MT6363_IRQ_BAT2_L, + MT6363_IRQ_BAT_TEMP_H, + MT6363_IRQ_BAT_TEMP_L, + MT6363_IRQ_THR_H, + MT6363_IRQ_THR_L, + MT6363_IRQ_AUXADC_IMP, + MT6363_IRQ_NAG_C_DLTV, + MT6363_IRQ_FG_BAT_H = 88, + MT6363_IRQ_FG_BAT_L, + MT6363_IRQ_FG_CUR_H, + MT6363_IRQ_FG_CUR_L, + MT6363_IRQ_FG_ZCV, + MT6363_IRQ_FG_N_CHARGE_L = 95, + MT6363_IRQ_FG_IAVG_H, + MT6363_IRQ_FG_IAVG_L, + MT6363_IRQ_FG_DISCHARGE = 99, + MT6363_IRQ_FG_CHARGE, + MT6363_IRQ_BATON_LV = 104, + MT6363_IRQ_BATON_BAT_IN = 106, + MT6363_IRQ_BATON_BAT_OUT, + MT6363_IRQ_NR = 108, +}; + +#define MT6363_IRQ_BUCK_BASE MT6363_IRQ_VS2_OC +#define MT6363_IRQ_LDO_BASE MT6363_IRQ_VCN15_OC +#define MT6363_IRQ_PSC_BASE MT6363_IRQ_PWRKEY +#define MT6363_IRQ_MISC_BASE MT6363_IRQ_RCS0 +#define MT6363_IRQ_HK_BASE MT6363_IRQ_BAT_H +#define MT6363_IRQ_BM_BASE MT6363_IRQ_FG_BAT_H + +#define MT6363_IRQ_BUCK_BITS \ + (MT6363_IRQ_VS3_OC - MT6363_IRQ_BUCK_BASE + 1) +#define MT6363_IRQ_LDO_BITS \ + (MT6363_IRQ_VM18_OC - MT6363_IRQ_LDO_BASE + 1) +#define MT6363_IRQ_PSC_BITS \ + (MT6363_IRQ_CHRDET_EDGE - MT6363_IRQ_PSC_BASE + 1) +#define MT6363_IRQ_MISC_BITS \ + (MT6363_IRQ_TOP_PROTREG - MT6363_IRQ_MISC_BASE + 1) +#define MT6363_IRQ_HK_BITS \ + (MT6363_IRQ_NAG_C_DLTV - MT6363_IRQ_HK_BASE + 1) +#define MT6363_IRQ_BM_BITS \ + (MT6363_IRQ_BATON_BAT_OUT - MT6363_IRQ_BM_BASE + 1) + +#define MT6363_TOP_GEN(sp) \ +{ \ + .hwirq_base = MT6363_IRQ_##sp##_BASE, \ + .num_int_regs = ((MT6363_IRQ_##sp##_BITS - 1) / MT6363_REG_WIDTH) + 1, \ + .en_reg = MT6363_##sp##_TOP_INT_CON0, \ + .en_reg_shift = 0x3, \ + .sta_reg = MT6363_##sp##_TOP_INT_STATUS0, \ + .sta_reg_shift = 0x1, \ + .top_offset = MT6363_##sp##_TOP, \ +} + +#endif /* __MFD_MT6363_CORE_H__ */ diff --git a/include/linux/mfd/mt6363/registers.h b/include/linux/mfd/mt6363/registers.h new file mode 100644 index 000000000000..e22ca686a7d0 --- /dev/null +++ b/include/linux/mfd/mt6363/registers.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + + +#ifndef __MFD_MT6363_REGISTERS_H__ +#define __MFD_MT6363_REGISTERS_H__ + +/* PMIC Registers */ +#define MT6363_TOPSTATUS (0x1e) +#define MT6363_MISC_TOP_INT_CON0 (0x37) +#define MT6363_MISC_TOP_INT_STATUS0 (0x43) +#define MT6363_TOP_INT_STATUS1 (0x4e) +#define MT6363_PSC_TOP_INT_CON0 (0x90f) +#define MT6363_PSC_TOP_INT_STATUS0 (0x91b) +#define MT6363_STRUP_CON11 (0xa0e) +#define MT6363_STRUP_CON12 (0xa0f) +#define MT6363_PCHR_VREF_ANA_CON1 (0xa89) +#define MT6363_PCHR_VREF_ANA_CON2 (0xa8a) +#define MT6363_BM_TOP_INT_CON0 (0xc24) +#define MT6363_BM_TOP_INT_STATUS0 (0xc36) +#define MT6363_HK_TOP_INT_CON0 (0xf92) +#define MT6363_HK_TOP_INT_STATUS0 (0xf9e) +#define MT6363_BUCK_TOP_INT_CON0 (0x1411) +#define MT6363_BUCK_TOP_INT_STATUS0 (0x141d) +#define MT6363_LDO_TOP_INT_CON0 (0x1b11) +#define MT6363_LDO_TOP_INT_STATUS0 (0x1b29) + +/* voter */ +#define MT6363_BUCK_VS2_VOTER_CON0 (0x149a) +#define MT6363_BUCK_VS2_VOTER_CON0_SET (0x149b) +#define MT6363_BUCK_VS2_VOTER_CON0_CLR (0x149c) +#define MT6363_BUCK_VS2_VOTER_CON1 (0x149d) +#define MT6363_BUCK_VS2_VOTER_CON1_SET (0x149e) +#define MT6363_BUCK_VS2_VOTER_CON1_CLR (0x149f) +#define MT6363_BUCK_VS2_VOTER_CFG (0x14a0) +#define MT6363_BUCK_VS1_VOTER_CON0 (0x189a) +#define MT6363_BUCK_VS1_VOTER_CON0_SET (0x189b) +#define MT6363_BUCK_VS1_VOTER_CON0_CLR (0x189c) +#define MT6363_BUCK_VS1_VOTER_CON1 (0x189d) +#define MT6363_BUCK_VS1_VOTER_CON1_SET (0x189e) +#define MT6363_BUCK_VS1_VOTER_CON1_CLR (0x189f) +#define MT6363_BUCK_VS1_VOTER_CFG (0x18a0) +#define MT6363_BUCK_VS3_VOTER_CON0 (0x191a) +#define MT6363_BUCK_VS3_VOTER_CON0_SET (0x191b) +#define MT6363_BUCK_VS3_VOTER_CON0_CLR (0x191c) +#define MT6363_BUCK_VS3_VOTER_CON1 (0x191d) +#define MT6363_BUCK_VS3_VOTER_CON1_SET (0x191e) +#define MT6363_BUCK_VS3_VOTER_CON1_CLR (0x191f) +#define MT6363_BUCK_VS3_VOTER_CFG (0x1920) + +#define MT6363_CHRDET_DEB_ADDR MT6363_TOPSTATUS +#define MT6363_CHRDET_DEB_MASK (0x1) +#define MT6363_CHRDET_DEB_SHIFT (2) +#define MT6363_RG_VBB_UVLO_VTHL_ADDR MT6363_PCHR_VREF_ANA_CON1 +#define MT6363_RG_VBB_UVLO_VTHL_MASK (0xF) +#define MT6363_RG_VBB_UVLO_VTHL_SHIFT (0) +#define MT6363_RG_VSYS_UVLO_VTHL_ADDR MT6363_PCHR_VREF_ANA_CON2 +#define MT6363_RG_VSYS_UVLO_VTHL_MASK (0xF) +#define MT6363_RG_VSYS_UVLO_VTHL_SHIFT (0) + +#define MT6363_AUXADC_ADC0_L (0x1088) +#define MT6363_AUXADC_ADC3_L (0x108e) +#define MT6363_AUXADC_ADC4_L (0x1090) +#define MT6363_AUXADC_ADC11_L (0x109e) +#define MT6363_AUXADC_ADC38_L (0x10c4) +#define MT6363_AUXADC_ADC39_L (0x10c6) +#define MT6363_AUXADC_ADC40_L (0x10c8) +#define MT6363_AUXADC_ADC_CH12_L (0x10d2) +#define MT6363_AUXADC_ADC_CH14_L (0x10d8) +#define MT6363_AUXADC_ADC42_L (0x10dc) +#define MT6363_AUXADC_RQST0 (0x1108) +#define MT6363_AUXADC_RQST1 (0x1109) +#define MT6363_AUXADC_RQST3 (0x110c) +#define MT6363_SDMADC_RQST0 (0x110e) +#define MT6363_SDMADC_CON0 (0x11c4) +#define MT6363_AUXADC_IMP0 (0x1208) +#define MT6363_AUXADC_IMP1 (0x1209) + +/* voter */ +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_ADDR \ + MT6363_BUCK_VS2_VOTER_CON0 +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_MASK (0xFF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_ADDR \ + MT6363_BUCK_VS2_VOTER_CON0_SET +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_MASK (0xFF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_ADDR \ + MT6363_BUCK_VS2_VOTER_CON0_CLR +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_MASK (0xFF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_LO_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_ADDR \ + MT6363_BUCK_VS2_VOTER_CON1 +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_MASK (0xF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_ADDR \ + MT6363_BUCK_VS2_VOTER_CON1_SET +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_MASK (0xF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_ADDR \ + MT6363_BUCK_VS2_VOTER_CON1_CLR +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_MASK (0xF) +#define MT6363_RG_BUCK_VS2_VOTER_EN_HI_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_ADDR \ + MT6363_BUCK_VS2_VOTER_CFG +#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_MASK (0xFF) +#define MT6363_RG_BUCK_VS2_VOTER_VOSEL_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_ADDR \ + MT6363_BUCK_VS1_VOTER_CON0 +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_MASK (0xFF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_ADDR \ + MT6363_BUCK_VS1_VOTER_CON0_SET +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_MASK (0xFF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_ADDR \ + MT6363_BUCK_VS1_VOTER_CON0_CLR +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_MASK (0xFF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_LO_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_ADDR \ + MT6363_BUCK_VS1_VOTER_CON1 +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_MASK (0xF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_ADDR \ + MT6363_BUCK_VS1_VOTER_CON1_SET +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_MASK (0xF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_ADDR \ + MT6363_BUCK_VS1_VOTER_CON1_CLR +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_MASK (0xF) +#define MT6363_RG_BUCK_VS1_VOTER_EN_HI_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_ADDR \ + MT6363_BUCK_VS1_VOTER_CFG +#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_MASK (0xFF) +#define MT6363_RG_BUCK_VS1_VOTER_VOSEL_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_ADDR \ + MT6363_BUCK_VS3_VOTER_CON0 +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_MASK (0xFF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_ADDR \ + MT6363_BUCK_VS3_VOTER_CON0_SET +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_MASK (0xFF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_ADDR \ + MT6363_BUCK_VS3_VOTER_CON0_CLR +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_MASK (0xFF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_LO_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_ADDR \ + MT6363_BUCK_VS3_VOTER_CON1 +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_MASK (0xF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_ADDR \ + MT6363_BUCK_VS3_VOTER_CON1_SET +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_MASK (0xF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_SET_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_ADDR \ + MT6363_BUCK_VS3_VOTER_CON1_CLR +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_MASK (0xF) +#define MT6363_RG_BUCK_VS3_VOTER_EN_HI_CLR_SHIFT (0) +#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_ADDR \ + MT6363_BUCK_VS3_VOTER_CFG +#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_MASK (0xFF) +#define MT6363_RG_BUCK_VS3_VOTER_VOSEL_SHIFT (0) + +#endif /* __MFD_MT6363_REGISTERS_H__ */ + diff --git a/include/linux/mfd/mt6373/core.h b/include/linux/mfd/mt6373/core.h new file mode 100644 index 000000000000..dd77d8cf29a2 --- /dev/null +++ b/include/linux/mfd/mt6373/core.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MFD_MT6373_CORE_H__ +#define __MFD_MT6373_CORE_H__ + +#define MT6373_REG_WIDTH 8 + +enum mt6373_irq_top_status_shift { + MT6373_BUCK_TOP = 0, + MT6373_LDO_TOP, + MT6373_PSC_TOP, + MT6373_MISC_TOP, + MT6373_HK_TOP, + MT6373_SCK_TOP, + MT6373_BM_TOP, + MT6373_AUD_TOP, +}; + +enum mt6373_irq_numbers { + MT6373_IRQ_VBUCK0_OC, + MT6373_IRQ_VBUCK1_OC, + MT6373_IRQ_VBUCK2_OC, + MT6373_IRQ_VBUCK3_OC, + MT6373_IRQ_VBUCK4_OC, + MT6373_IRQ_VBUCK5_OC, + MT6373_IRQ_VBUCK6_OC, + MT6373_IRQ_VBUCK7_OC, + MT6373_IRQ_VBUCK8_OC, + MT6373_IRQ_VBUCK9_OC, + MT6373_IRQ_VAUD18_OC = 16, + MT6373_IRQ_VUSB_OC, + MT6373_IRQ_VAUX18_OC, + MT6373_IRQ_VRF13_AIF_OC, + MT6373_IRQ_VRF18_AIF_OC, + MT6373_IRQ_VRFIO18_AIF_OC, + MT6373_IRQ_VCN33_1_OC, + MT6373_IRQ_VCN33_2_OC, + MT6373_IRQ_VCN33_3_OC, + MT6373_IRQ_VCN18IO_OC, + MT6373_IRQ_VRF09_AIF_OC, + MT6373_IRQ_VRF12_AIF_OC, + MT6373_IRQ_VANT18_OC, + MT6373_IRQ_VSRAM_DIGRF_AIF_OC, + MT6373_IRQ_VMDDR_OC, + MT6373_IRQ_VEFUSE_OC, + MT6373_IRQ_VMCH_OC, + MT6373_IRQ_VMC_OC, + MT6373_IRQ_VIBR_OC, + MT6373_IRQ_VIO28_OC, + MT6373_IRQ_VFP_OC, + MT6373_IRQ_VTP_OC, + MT6373_IRQ_VSIM1_OC, + MT6373_IRQ_VSIM2_OC, + MT6373_IRQ_RCS0 = 56, + MT6373_IRQ_SPMI_CMD_ALERT, + MT6373_IRQ_BM_PROTREG = 62, + MT6373_IRQ_VRC_PROTREG, + MT6373_IRQ_BUCK_PROTREG = 64, + MT6373_IRQ_LDO_PROTREG, + MT6373_IRQ_PSC_PROTREG, + MT6373_IRQ_PLT_PROTREG, + MT6373_IRQ_HK_PROTREG, + MT6373_IRQ_SCK_PROTREG, + MT6373_IRQ_XPP_PROTREG, + MT6373_IRQ_TOP_PROTREG, + MT6373_IRQ_NR = 72, +}; + +#define MT6373_IRQ_BUCK_BASE MT6373_IRQ_VBUCK0_OC +#define MT6373_IRQ_LDO_BASE MT6373_IRQ_VAUD18_OC +#define MT6373_IRQ_MISC_BASE MT6373_IRQ_RCS0 + +#define MT6373_IRQ_BUCK_BITS \ + (MT6373_IRQ_VBUCK9_OC - MT6373_IRQ_BUCK_BASE + 1) +#define MT6373_IRQ_LDO_BITS \ + (MT6373_IRQ_VSIM2_OC - MT6373_IRQ_LDO_BASE + 1) +#define MT6373_IRQ_MISC_BITS \ + (MT6373_IRQ_TOP_PROTREG - MT6373_IRQ_MISC_BASE + 1) + +#define MT6373_TOP_GEN(sp) \ +{ \ + .hwirq_base = MT6373_IRQ_##sp##_BASE, \ + .num_int_regs = ((MT6373_IRQ_##sp##_BITS - 1) / MT6373_REG_WIDTH) + 1, \ + .en_reg = MT6373_##sp##_TOP_INT_CON0, \ + .en_reg_shift = 0x3, \ + .sta_reg = MT6373_##sp##_TOP_INT_STATUS0, \ + .sta_reg_shift = 0x1, \ + .top_offset = MT6373_##sp##_TOP, \ +} + +#endif /* __MFD_MT6373_CORE_H__ */ diff --git a/include/linux/mfd/mt6373/registers.h b/include/linux/mfd/mt6373/registers.h new file mode 100644 index 000000000000..05aef78abfdf --- /dev/null +++ b/include/linux/mfd/mt6373/registers.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + + +#ifndef __MFD_MT6373_REGISTERS_H__ +#define __MFD_MT6373_REGISTERS_H__ + +/* PMIC Registers */ +#define MT6373_TOPSTATUS 0x1e +#define MT6373_MISC_TOP_INT_CON0 0x3c +#define MT6373_MISC_TOP_INT_CON1 0x3f +#define MT6373_MISC_TOP_INT_STATUS0 0x48 +#define MT6373_MISC_TOP_INT_STATUS1 0x49 +#define MT6373_TOP_INT_MASK_CON0 0x4c +#define MT6373_TOP_INT_MASK_CON0_SET 0x4d +#define MT6373_TOP_INT_MASK_CON0_CLR 0x4e +#define MT6373_TOP_INT_MASK_CON1 0x4f +#define MT6373_TOP_INT_MASK_CON1_SET 0x50 +#define MT6373_TOP_INT_MASK_CON1_CLR 0x51 +#define MT6373_TOP_INT_STATUS0 0x52 +#define MT6373_TOP_INT_STATUS1 0x53 +#define MT6373_HK_TOP_INT_CON0 0xf92 +#define MT6373_HK_TOP_INT_CON1 0xf95 +#define MT6373_HK_TOP_INT_STATUS0 0xf9e +#define MT6373_HK_TOP_INT_STATUS1 0xf9f +#define MT6373_AUXADC_ADC4_L 0x1090 +#define MT6373_AUXADC_ADC38_L 0x10c4 +#define MT6373_AUXADC_ADC39_L 0x10c6 +#define MT6373_AUXADC_ADC40_L 0x10c8 +#define MT6373_AUXADC_ADC_CH12_L 0x10d2 +#define MT6373_AUXADC_ADC_CH12_H 0x10d3 +#define MT6373_AUXADC_RQST0 0x1108 +#define MT6373_AUXADC_RQST1 0x1109 +#define MT6373_AUXADC_RQST3 0x110c +#define MT6373_SDMADC_RQST0 0x110e +#define MT6373_SDMADC_CON0 0x11c4 +#define MT6373_BUCK_TOP_INT_CON0 0x1411 +#define MT6373_BUCK_TOP_INT_CON1 0x1414 +#define MT6373_BUCK_TOP_INT_STATUS0 0x141d +#define MT6373_BUCK_TOP_INT_STATUS1 0x141e +#define MT6373_LDO_TOP_INT_CON0 0x1b10 +#define MT6373_LDO_TOP_INT_CON1 0x1b13 +#define MT6373_LDO_TOP_INT_CON2 0x1b16 +#define MT6373_LDO_TOP_INT_STATUS0 0x1b22 +#define MT6373_LDO_TOP_INT_STATUS1 0x1b23 +#define MT6373_LDO_TOP_INT_STATUS2 0x1b24 +#define MT6373_LDO_VMCH_CON0 0x1cb1 +#define MT6373_LDO_VMCH_CON1 0x1cb2 +#define MT6373_LDO_VMCH_CON2 0x1cb3 + +#endif /* __MFD_MT6373_REGISTERS_H__ */ From patchwork Fri Mar 14 07:32:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?THUgVGFuZyAo5rGk55KQKQ==?= X-Patchwork-Id: 14016376 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 22249197A68; Fri, 14 Mar 2025 07:55:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.61.82.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938935; cv=none; b=AWbwDSFp86N7tLWF+3RmQbFaP7tvX4hBcnWbx53vJgfqQK22mpdAmRwgd5TwsUqLbXEnLey0N0ZoBAfgFcxqqfbtGG5COR5pnCm7kXF7bCCGYCDKWIfvgvN7BI2QoJwr7CIPOqGl65xBVlQ7DCSSFQud/2lnOJdl9XYRWjnsUUs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938935; c=relaxed/simple; bh=gn8yNoX9/CjT9PFky1a3iNAAMhxYWTuJHS9PxtDf92Y=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=C3VuL3FBbt8yKywiFhiohvuRJ0TFODhDVclxkf55qpQYwElLyqVh2YjlVtKYobmYTXpcrgl6GuVh9QwVXva4Ya8NLCu1HQUN7d2bO0XsBf6ZkEce811HtWOzla11+EKtl5nD/8arXyUQ0r0j1ttteS27Lesk8mRJvkzuTfPW+1I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=dvhtRfp/; arc=none smtp.client-ip=210.61.82.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="dvhtRfp/" X-UUID: b22a064000a911f08eb9c36241bbb6fb-20250314 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=L7WpmlUmujbq1rOXtz+c4tqVhQ23hTxb3WmIwRZU4hs=; b=dvhtRfp/TOjJKih2GyLn7UeGsyQDYiR0wIQGKVeJrvFhFNCDmFpZlRr3jFjJY3ywM2D99F3C0i77j94/CqRIf6RccaDYvBPG/bl/dAKM3dpWBPdH0NvtD3BCzO9xnnt2H3/fkMhbVP7xIJjU1hzhhEiFd8HR5ifbGEtFWggiIH4=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:2d92ed6d-391a-474d-ac01-4f99a1cef00a,IP:0,UR L:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION:r elease,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:ef5927e1-3561-4519-9a12-e2c881788b70,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: b22a064000a911f08eb9c36241bbb6fb-20250314 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 400472573; Fri, 14 Mar 2025 15:55:28 +0800 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by mtkmbs11n1.mediatek.inc (172.21.101.185) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 14 Mar 2025 15:55:27 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 14 Mar 2025 15:55:26 +0800 From: Lu.Tang To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dmitry Torokhov , Lee Jones , Matthias Brugger , AngeloGioacchino Del Regno , Sean Wang , Linus Walleij , Liam Girdwood , Mark Brown , Stephen Boyd , Chen Zhong , Sen Chu CC: , , , , , , , , Lu.Tang Subject: [PATCH 4/5] spmi: mediatek: modify spmi dirver for mt8196 Date: Fri, 14 Mar 2025 15:32:30 +0800 Message-ID: <20250314073307.25092-5-Lu.Tang@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250314073307.25092-1-Lu.Tang@mediatek.com> References: <20250314073307.25092-1-Lu.Tang@mediatek.com> Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Lu.Tang" Modify spmi driver for mt8196 pmic. Add pmif_s/pmif_m controller and rcs irq handler. Signed-off-by: Lu.Tang --- drivers/spmi/spmi-mtk-pmif.c | 1040 +++++++++++++++++++++++++++++++--- 1 file changed, 976 insertions(+), 64 deletions(-) diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c index 160d36f7d238..36f7ef80e7c4 100644 --- a/drivers/spmi/spmi-mtk-pmif.c +++ b/drivers/spmi/spmi-mtk-pmif.c @@ -1,14 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 // -// Copyright (c) 2021 MediaTek Inc. +// Copyright (c) 2024 MediaTek Inc. #include #include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #define SWINF_IDLE 0x00 #define SWINF_WFVLDCLR 0x06 @@ -21,14 +27,21 @@ #define PMIF_CMD_EXT_REG_LONG 3 #define PMIF_DELAY_US 10 -#define PMIF_TIMEOUT_US (10 * 1000) +#define PMIF_TIMEOUT_US (100 * 1000) #define PMIF_CHAN_OFFSET 0x5 +#define PMIF_CAPS_VER_1 1 +#define PMIF_CAPS_VER_2 2 + #define PMIF_MAX_CLKS 3 #define SPMI_OP_ST_BUSY 1 +#define SPMI_SOC_CHANNEL 2 + +#define PMIF_IRQDESC(name) { #name, pmif_##name##_irq_handler, -1} + struct ch_reg { u32 ch_sta; u32 wdata; @@ -41,25 +54,53 @@ struct pmif_data { const u32 *regs; const u32 *spmimst_regs; u32 soc_chan; + u32 caps; }; struct pmif { - void __iomem *base; - void __iomem *spmimst_base; + void __iomem *pmif_base[2]; + void __iomem *spmimst_base[2]; struct ch_reg chan; struct clk_bulk_data clks[PMIF_MAX_CLKS]; size_t nclks; const struct pmif_data *data; - raw_spinlock_t lock; + raw_spinlock_t lock_m; + raw_spinlock_t lock_p; + struct spmi_controller *spmic; + struct wakeup_source *pmif_m_Thread_lock; + struct wakeup_source *pmif_p_Thread_lock; + struct mutex pmif_m_mutex; + struct mutex pmif_p_mutex; + int irq; + int irq_p; + struct irq_domain *domain; + struct irq_chip irq_chip; + struct irq_chip irq_chip_p; + int rcs_irq; + int rcs_irq_p; + struct mutex rcs_m_irqlock; + struct mutex rcs_p_irqlock; + bool *rcs_enable_hwirq; + int spmi_nack_irq; + int spmi_p_nack_irq; }; static const char * const pmif_clock_names[] = { "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux", }; +struct pmif_irq_desc { + const char *name; + irq_handler_t irq_handler; + int irq; +}; + enum pmif_regs { PMIF_INIT_DONE, PMIF_INF_EN, + MD_AUXADC_RDATA_0_ADDR, + MD_AUXADC_RDATA_1_ADDR, + MD_AUXADC_RDATA_2_ADDR, PMIF_ARB_EN, PMIF_CMDISSUE_EN, PMIF_TIMER_CTRL, @@ -103,6 +144,11 @@ enum pmif_regs { PMIF_SWINF_3_RDATA_31_0, PMIF_SWINF_3_ACC, PMIF_SWINF_3_VLD_CLR, + PMIF_PMIC_SWINF_0_PER, + PMIF_PMIC_SWINF_1_PER, + PMIF_ACC_VIO_INFO_0, + PMIF_ACC_VIO_INFO_1, + PMIF_ACC_VIO_INFO_2, }; static const u32 mt6873_regs[] = { @@ -201,6 +247,63 @@ static const u32 mt8195_regs[] = { [PMIF_SWINF_3_STA] = 0x08E8, }; +static const u32 mt6xxx_regs[] = { + [PMIF_INIT_DONE] = 0x0000, + [PMIF_INF_EN] = 0x0024, + [MD_AUXADC_RDATA_0_ADDR] = 0x0080, + [MD_AUXADC_RDATA_1_ADDR] = 0x0084, + [MD_AUXADC_RDATA_2_ADDR] = 0x0088, + [PMIF_ARB_EN] = 0x0150, + [PMIF_CMDISSUE_EN] = 0x03B8, + [PMIF_TIMER_CTRL] = 0x03E4, + [PMIF_SPI_MODE_CTRL] = 0x0408, + [PMIF_IRQ_EVENT_EN_0] = 0x0420, + [PMIF_IRQ_FLAG_0] = 0x0428, + [PMIF_IRQ_CLR_0] = 0x042C, + [PMIF_IRQ_EVENT_EN_1] = 0x0430, + [PMIF_IRQ_FLAG_1] = 0x0438, + [PMIF_IRQ_CLR_1] = 0x043C, + [PMIF_IRQ_EVENT_EN_2] = 0x0440, + [PMIF_IRQ_FLAG_2] = 0x0448, + [PMIF_IRQ_CLR_2] = 0x044C, + [PMIF_IRQ_EVENT_EN_3] = 0x0450, + [PMIF_IRQ_FLAG_3] = 0x0458, + [PMIF_IRQ_CLR_3] = 0x045C, + [PMIF_IRQ_EVENT_EN_4] = 0x0460, + [PMIF_IRQ_FLAG_4] = 0x0468, + [PMIF_IRQ_CLR_4] = 0x046C, + [PMIF_WDT_EVENT_EN_0] = 0x0474, + [PMIF_WDT_FLAG_0] = 0x0478, + [PMIF_WDT_EVENT_EN_1] = 0x047C, + [PMIF_WDT_FLAG_1] = 0x0480, + [PMIF_SWINF_0_ACC] = 0x0800, + [PMIF_SWINF_0_WDATA_31_0] = 0x0804, + [PMIF_SWINF_0_RDATA_31_0] = 0x0814, + [PMIF_SWINF_0_VLD_CLR] = 0x0824, + [PMIF_SWINF_0_STA] = 0x0828, + [PMIF_SWINF_1_ACC] = 0x0840, + [PMIF_SWINF_1_WDATA_31_0] = 0x0844, + [PMIF_SWINF_1_RDATA_31_0] = 0x0854, + [PMIF_SWINF_1_VLD_CLR] = 0x0864, + [PMIF_SWINF_1_STA] = 0x0868, + [PMIF_SWINF_2_ACC] = 0x0880, + [PMIF_SWINF_2_WDATA_31_0] = 0x0884, + [PMIF_SWINF_2_RDATA_31_0] = 0x0894, + [PMIF_SWINF_2_VLD_CLR] = 0x08A4, + [PMIF_SWINF_2_STA] = 0x08A8, + [PMIF_SWINF_3_ACC] = 0x08C0, + [PMIF_SWINF_3_WDATA_31_0] = 0x08C4, + [PMIF_SWINF_3_RDATA_31_0] = 0x08D4, + [PMIF_SWINF_3_VLD_CLR] = 0x08E4, + [PMIF_SWINF_3_STA] = 0x08E8, + [PMIF_PMIC_SWINF_0_PER] = 0x093C, + [PMIF_PMIC_SWINF_1_PER] = 0x0940, + [PMIF_ACC_VIO_INFO_0] = 0x0980, + [PMIF_ACC_VIO_INFO_1] = 0x0984, + [PMIF_ACC_VIO_INFO_2] = 0x0988, + +}; + enum spmi_regs { SPMI_OP_ST_CTRL, SPMI_GRP_ID_EN, @@ -262,26 +365,132 @@ static const u32 mt8195_spmi_regs[] = { [SPMI_MST_DBG] = 0x00FC, }; -static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg) +static const u32 mt6853_spmi_regs[] = { + [SPMI_OP_ST_CTRL] = 0x0000, + [SPMI_GRP_ID_EN] = 0x0004, + [SPMI_OP_ST_STA] = 0x0008, + [SPMI_MST_SAMPL] = 0x000C, + [SPMI_MST_REQ_EN] = 0x0010, + [SPMI_MST_RCS_CTRL] = 0x0014, + [SPMI_SLV_3_0_EINT] = 0x0020, + [SPMI_SLV_7_4_EINT] = 0x0024, + [SPMI_SLV_B_8_EINT] = 0x0028, + [SPMI_SLV_F_C_EINT] = 0x002C, + [SPMI_REC_CTRL] = 0x0040, + [SPMI_REC0] = 0x0044, + [SPMI_REC1] = 0x0048, + [SPMI_REC2] = 0x004C, + [SPMI_REC3] = 0x0050, + [SPMI_REC4] = 0x0054, + [SPMI_REC_CMD_DEC] = 0x005C, + [SPMI_DEC_DBG] = 0x00F8, + [SPMI_MST_DBG] = 0x00FC, +}; + +enum { + IRQ_LAT_LIMIT_REACHED = 6, + IRQ_HW_MONITOR = 7, + IRQ_WDT = 8, + /* MT6833/MT6877 series */ + IRQ_HW_MONITOR_V3 = 12, + IRQ_WDT_V3 = 13, + IRQ_ALL_PMIC_MPU_VIO_V3 = 14, + /* MT6885/MT6873 series */ + IRQ_PMIC_CMD_ERR_PARITY_ERR = 17, + IRQ_PMIF_ACC_VIO = 20, + IRQ_PMIC_ACC_VIO = 21, + /* MT6985/MT6897 */ + IRQ_PMIF_ACC_VIO_V3 = 27, + /* MT6853 series */ + IRQ_PMIF_ACC_VIO_V2 = 31, +}; + +enum { + IRQ_PMIC_ACC_VIO_V2 = 0, + IRQ_PMIF_SWINF_ACC_ERR_0 = 3, + IRQ_PMIF_SWINF_ACC_ERR_1 = 4, + IRQ_PMIF_SWINF_ACC_ERR_2 = 5, + IRQ_PMIF_SWINF_ACC_ERR_3 = 6, + IRQ_PMIF_SWINF_ACC_ERR_4 = 7, + IRQ_PMIF_SWINF_ACC_ERR_5 = 8, + IRQ_HW_MONITOR_V2 = 18, + IRQ_WDT_V2 = 19, + IRQ_ALL_PMIC_MPU_VIO_V2 = 20, + IRQ_PMIF_SWINF_ACC_ERR_0_V2 = 23, + IRQ_PMIF_SWINF_ACC_ERR_1_V2 = 24, + IRQ_PMIF_SWINF_ACC_ERR_2_V2 = 25, + IRQ_PMIF_SWINF_ACC_ERR_3_V2 = 26, + IRQ_PMIF_SWINF_ACC_ERR_4_V2 = 27, + IRQ_PMIF_SWINF_ACC_ERR_5_V2 = 28, + /* MT6983/MT6879 */ + IRQ_HW_MONITOR_V4 = 29, + IRQ_WDT_V4 = 30, + IRQ_ALL_PMIC_MPU_VIO_V4 = 31, +}; + +struct spmi_dev { + int exist; + int slvid; + unsigned int path; + unsigned short hwcid_addr; + unsigned char hwcid_val; +}; + +static struct spmi_dev spmidev[16]; + +static void spmi_dev_parse(struct platform_device *pdev) { - return readl(arb->base + arb->data->regs[reg]); + int i = 0, j = 0, ret = 0; + u32 spmi_dev_mask = 0; + + ret = of_property_read_u32(pdev->dev.of_node, "spmi-dev-mask", + &spmi_dev_mask); + if (ret) + dev_info(&pdev->dev, "No spmi-dev-mask found in dts, default all PMIC on SPMI-M\n"); + + j = spmi_dev_mask; + for (i = 0; i < 16; i++) { + if (j & BIT(i)) + spmidev[i].path = 1; /* slvid i is in path p */ + else + spmidev[i].path = 0; + } +} + +unsigned long long get_current_time_ms(void) +{ + unsigned long long cur_ts; + + cur_ts = sched_clock(); + do_div(cur_ts, 1000000); + return cur_ts; } -static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg) +static u32 pmif_readl(void __iomem *addr, struct pmif *arb, enum pmif_regs reg) { - writel(val, arb->base + arb->data->regs[reg]); + return readl(addr + arb->data->regs[reg]); } -static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg) +static void pmif_writel(void __iomem *addr, struct pmif *arb, u32 val, enum pmif_regs reg) { - writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]); + writel(val, addr + arb->data->regs[reg]); } -static bool pmif_is_fsm_vldclr(struct pmif *arb) +static void mtk_spmi_writel(void __iomem *addr, struct pmif *arb, u32 val, enum spmi_regs reg) +{ + writel(val, addr + arb->data->spmimst_regs[reg]); +} + +static u32 mtk_spmi_readl(void __iomem *addr, struct pmif *arb, enum spmi_regs reg) +{ + return readl(addr + arb->data->spmimst_regs[reg]); +} + +static bool pmif_is_fsm_vldclr(void __iomem *addr, struct pmif *arb) { u32 reg_rdata; - reg_rdata = pmif_readl(arb, arb->chan.ch_sta); + reg_rdata = pmif_readl(addr, arb, arb->chan.ch_sta); return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR; } @@ -298,8 +507,8 @@ static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) cmd = opc - SPMI_CMD_RESET; - mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL); - ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA], + mtk_spmi_writel(arb->spmimst_base[spmidev[sid].path], arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL); + ret = readl_poll_timeout_atomic(arb->spmimst_base[spmidev[sid].path] + arb->data->spmimst_regs[SPMI_OP_ST_STA], rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) @@ -315,7 +524,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, struct ch_reg *inf_reg; int ret; u32 data, cmd; - unsigned long flags; + unsigned long flags_m; /* Check for argument validation. */ if (sid & ~0xf) { @@ -336,31 +545,31 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, else return -EINVAL; - raw_spin_lock_irqsave(&arb->lock, flags); + raw_spin_lock_irqsave(&arb->lock_m, flags_m); /* Wait for Software Interface FSM state to be IDLE. */ inf_reg = &arb->chan; - ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], + ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + arb->data->regs[inf_reg->ch_sta], data, GET_SWINF(data) == SWINF_IDLE, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) { /* set channel ready if the data has transferred */ - if (pmif_is_fsm_vldclr(arb)) - pmif_writel(arb, 1, inf_reg->ch_rdy); - raw_spin_unlock_irqrestore(&arb->lock, flags); + if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb)) + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy); + raw_spin_unlock_irqrestore(&arb->lock_m, flags_m); dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n"); return ret; } /* Send the command. */ cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr; - pmif_writel(arb, cmd, inf_reg->ch_send); - raw_spin_unlock_irqrestore(&arb->lock, flags); + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send); + raw_spin_unlock_irqrestore(&arb->lock_m, flags_m); /* * Wait for Software Interface FSM state to be WFVLDCLR, * read the data and clear the valid flag. */ - ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], + ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + arb->data->regs[inf_reg->ch_sta], data, GET_SWINF(data) == SWINF_WFVLDCLR, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) { @@ -368,9 +577,9 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, return ret; } - data = pmif_readl(arb, inf_reg->rdata); + data = pmif_readl(arb->pmif_base[spmidev[sid].path], arb, inf_reg->rdata); memcpy(buf, &data, len); - pmif_writel(arb, 1, inf_reg->ch_rdy); + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy); return 0; } @@ -382,7 +591,7 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, struct ch_reg *inf_reg; int ret; u32 data, wdata, cmd; - unsigned long flags; + unsigned long flags_m; /* Check for argument validation. */ if (unlikely(sid & ~0xf)) { @@ -409,27 +618,27 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, /* Set the write data. */ memcpy(&wdata, buf, len); - raw_spin_lock_irqsave(&arb->lock, flags); + raw_spin_lock_irqsave(&arb->lock_m, flags_m); /* Wait for Software Interface FSM state to be IDLE. */ inf_reg = &arb->chan; - ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], + ret = readl_poll_timeout_atomic(arb->pmif_base[spmidev[sid].path] + arb->data->regs[inf_reg->ch_sta], data, GET_SWINF(data) == SWINF_IDLE, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) { /* set channel ready if the data has transferred */ - if (pmif_is_fsm_vldclr(arb)) - pmif_writel(arb, 1, inf_reg->ch_rdy); - raw_spin_unlock_irqrestore(&arb->lock, flags); + if (pmif_is_fsm_vldclr(arb->pmif_base[spmidev[sid].path], arb)) + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, 1, inf_reg->ch_rdy); + raw_spin_unlock_irqrestore(&arb->lock_m, flags_m); dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n"); return ret; } - pmif_writel(arb, wdata, inf_reg->wdata); + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, wdata, inf_reg->wdata); /* Send the command. */ cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr; - pmif_writel(arb, cmd, inf_reg->ch_send); - raw_spin_unlock_irqrestore(&arb->lock, flags); + pmif_writel(arb->pmif_base[spmidev[sid].path], arb, cmd, inf_reg->ch_send); + raw_spin_unlock_irqrestore(&arb->lock_m, flags_m); return 0; } @@ -437,15 +646,642 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, static const struct pmif_data mt6873_pmif_arb = { .regs = mt6873_regs, .spmimst_regs = mt6873_spmi_regs, - .soc_chan = 2, + .soc_chan = SPMI_SOC_CHANNEL, + .caps = PMIF_CAPS_VER_1, }; static const struct pmif_data mt8195_pmif_arb = { .regs = mt8195_regs, .spmimst_regs = mt8195_spmi_regs, - .soc_chan = 2, + .soc_chan = SPMI_SOC_CHANNEL, + .caps = PMIF_CAPS_VER_1, }; +static const struct pmif_data mt6xxx_pmif_arb = { + .regs = mt6xxx_regs, + .spmimst_regs = mt6853_spmi_regs, + .soc_chan = SPMI_SOC_CHANNEL, + .caps = PMIF_CAPS_VER_2, +}; +static void mtk_spmi_readl_datas(struct pmif *arb, int id, unsigned int *spmi_nack, + unsigned int *spmi_nack_data, unsigned int *spmi_rcs_nack, + unsigned int *spmi_debug_nack, unsigned int *spmi_mst_nack) +{ + if (id < 0 || id >= PMIF_CAPS_VER_2) { + dev_err(&arb->spmic->dev, "%s Invalid id: %d\n", __func__, id); + return; + } + *spmi_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC0); + *spmi_nack_data = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC1); + *spmi_rcs_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_REC_CMD_DEC); + *spmi_debug_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_DEC_DBG); + *spmi_mst_nack = mtk_spmi_readl(arb->spmimst_base[id], arb, SPMI_MST_DBG); +} +static irqreturn_t spmi_nack_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int sid = 0; + unsigned int spmi_nack = 0, spmi_p_nack = 0, spmi_nack_data = 0, spmi_p_nack_data = 0; + unsigned int spmi_rcs_nack = 0, spmi_debug_nack = 0, spmi_mst_nack = 0, + spmi_p_rcs_nack = 0, spmi_p_debug_nack = 0, spmi_p_mst_nack = 0; + u8 rdata = 0, rdata1 = 0; + unsigned short mt6316INTSTA = 0x240, hwcidaddr_mt6316 = 0x209, VIO18_SWITCH_6363 = 0x53, + hwcidaddr_mt6363 = 0x9; + + mutex_lock(&arb->pmif_m_mutex); + + mtk_spmi_readl_datas(arb, 0, &spmi_nack, &spmi_nack_data, &spmi_rcs_nack, + &spmi_debug_nack, &spmi_mst_nack); + if (!IS_ERR(arb->spmimst_base[1])) { + mtk_spmi_readl_datas(arb, 1, &spmi_p_nack, &spmi_p_nack_data, &spmi_p_rcs_nack, + &spmi_p_debug_nack, &spmi_p_mst_nack); + } + if ((spmi_nack & 0xD8) || (spmi_p_nack & 0xD8)) { + if (spmi_p_nack & 0xD8) { + for (sid = 0x8; sid >= 0x6; sid--) { + arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid, + mt6316INTSTA, &rdata, 1); + arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, sid, + hwcidaddr_mt6316, &rdata1, 1); + dev_notice(&arb->spmic->dev, "%s slvid 0x%x INT_RAW_STA 0x%x cid 0x%x\n", + __func__, sid, rdata, rdata1); + } + } + dev_notice(&arb->spmic->dev, "%s spmi transaction fail irq triggered", __func__); + dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n", + spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data); + } + if ((spmi_rcs_nack & 0xC0000) || (spmi_p_rcs_nack & 0xC0000)) { + dev_notice(&arb->spmic->dev, "%s spmi_rcs transaction fail irq triggered SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n", + __func__, spmi_rcs_nack, spmi_p_rcs_nack); + } + if ((spmi_debug_nack & 0xF0000) || (spmi_p_debug_nack & 0xF0000)) { + dev_notice(&arb->spmic->dev, "%s spmi_debug_nack transaction fail irq triggered SPMI_DEC_DBG m/p: 0x%x/0x%x\n", + __func__, spmi_debug_nack, spmi_p_debug_nack); + } + if ((spmi_mst_nack & 0xC0000) || (spmi_p_mst_nack & 0xC0000)) { + dev_notice(&arb->spmic->dev, "%s spmi_mst_nack transaction fail irq triggered SPMI_MST_DBG m/p: 0x%x/0x%x\n", + __func__, spmi_mst_nack, spmi_p_mst_nack); + } + if ((spmi_nack & 0x20) || (spmi_p_nack & 0x20)) { + dev_notice(&arb->spmic->dev, "%s spmi transaction fail (Read) irq triggered", __func__); + dev_notice(&arb->spmic->dev, "SPMI_REC0 m/p:0x%x/0x%x SPMI_REC1 m/p 0x%x/0x%x\n", + spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data); + } + + if ((spmi_nack & 0xF8) || (spmi_rcs_nack & 0xC0000) || + (spmi_debug_nack & 0xF0000) || (spmi_mst_nack & 0xC0000)) { + mtk_spmi_writel(arb->spmimst_base[0], arb, 0x3, SPMI_REC_CTRL); + } else if ((spmi_p_nack & 0xF8) || (spmi_p_rcs_nack & 0xC0000) || + (spmi_p_debug_nack & 0xF0000) || (spmi_p_mst_nack & 0xC0000)) { + if (spmi_p_nack & 0xD8) { + dev_notice(&arb->spmic->dev, "%s SPMI_REC0 m/p:0x%x/0x%x, SPMI_REC1 m/p:0x%x/0x%x\n", + __func__, spmi_nack, spmi_p_nack, spmi_nack_data, spmi_p_nack_data); + dev_notice(&arb->spmic->dev, "%s SPMI_REC_CMD_DEC m/p:0x%x/0x%x\n", __func__, + spmi_rcs_nack, spmi_p_rcs_nack); + dev_notice(&arb->spmic->dev, "%s SPMI_DEC_DBG m/p:0x%x/0x%x\n", __func__, + spmi_debug_nack, spmi_p_debug_nack); + dev_notice(&arb->spmic->dev, "%s SPMI_MST_DBG m/p:0x%x/0x%x\n", __func__, + spmi_mst_nack, spmi_p_mst_nack); + arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4, + hwcidaddr_mt6363, &rdata, 1); + arb->spmic->read_cmd(arb->spmic, SPMI_CMD_EXT_READL, 0x4, + VIO18_SWITCH_6363, &rdata1, 1); + dev_notice(&arb->spmic->dev, "%s 6363 CID/VIO18_SWITCH 0x%x/0x%x\n", __func__, rdata, rdata1); + } + mtk_spmi_writel(arb->spmimst_base[1], arb, 0x3, SPMI_REC_CTRL); + } else + dev_notice(&arb->spmic->dev, "%s IRQ not cleared\n", __func__); + + mutex_unlock(&arb->pmif_m_mutex); + + return IRQ_HANDLED; +} +static int spmi_nack_irq_register(struct platform_device *pdev, + struct pmif *arb, int irq) +{ + int ret = 0; + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + spmi_nack_irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED, + "spmi_nack_irq", arb); + if (ret < 0) { + dev_notice(&pdev->dev, "request %s irq fail\n", + "spmi_nack_irq"); + } + return ret; +} +static void rcs_irq_lock(struct irq_data *data) +{ + struct pmif *arb = irq_data_get_irq_chip_data(data); + mutex_lock(&arb->rcs_m_irqlock); +} +static void rcs_irq_sync_unlock(struct irq_data *data) +{ + struct pmif *arb = irq_data_get_irq_chip_data(data); + mutex_unlock(&arb->rcs_m_irqlock); +} +static void rcs_irq_enable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct pmif *arb = irq_data_get_irq_chip_data(data); + arb->rcs_enable_hwirq[hwirq] = true; +} +static void rcs_irq_disable(struct irq_data *data) +{ + unsigned int hwirq = irqd_to_hwirq(data); + struct pmif *arb = irq_data_get_irq_chip_data(data); + arb->rcs_enable_hwirq[hwirq] = false; +} +static int rcs_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct pmif *arb = irq_data_get_irq_chip_data(data); + return irq_set_irq_wake(arb->rcs_irq, on); +} +static int rcs_irq_p_set_wake(struct irq_data *data, unsigned int on) +{ + struct pmif *arb = irq_data_get_irq_chip_data(data); + return irq_set_irq_wake(arb->rcs_irq_p, on); +} +static const struct irq_chip rcs_irq_chip = { + .name = "rcs_irq", + .irq_bus_lock = rcs_irq_lock, + .irq_bus_sync_unlock = rcs_irq_sync_unlock, + .irq_enable = rcs_irq_enable, + .irq_disable = rcs_irq_disable, + .irq_set_wake = rcs_irq_set_wake, +}; + +static const struct irq_chip rcs_irq_chip_p = { + .name = "rcs_irq_p", + .irq_bus_lock = rcs_irq_lock, + .irq_bus_sync_unlock = rcs_irq_sync_unlock, + .irq_enable = rcs_irq_enable, + .irq_disable = rcs_irq_disable, + .irq_set_wake = rcs_irq_p_set_wake, +}; +static int rcs_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct pmif *arb = d->host_data; + irq_set_chip_data(virq, arb); + irq_set_chip(virq, &arb->irq_chip); + irq_set_nested_thread(virq, 1); + irq_set_parent(virq, arb->rcs_irq); + irq_set_noprobe(virq); + return 0; +} +static const struct irq_domain_ops rcs_irq_domain_ops = { + .map = rcs_irq_map, + .xlate = irq_domain_xlate_onetwocell, +}; +static void pmif_lat_limit_reached_irq_handler(int irq, void *data) +{ +} +static void pmif_acc_vio_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF ACC violation debug info\n"); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-M\n"); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[0], + arb, PMIF_ACC_VIO_INFO_0)); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[0], + arb, PMIF_ACC_VIO_INFO_1)); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[0], + arb, PMIF_ACC_VIO_INFO_2)); + if (!IS_ERR(arb->pmif_base[1])) { + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF-P\n"); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_0 = 0x%x\n", pmif_readl(arb->pmif_base[1], + arb, PMIF_ACC_VIO_INFO_0)); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_1 = 0x%x\n", pmif_readl(arb->pmif_base[1], + arb, PMIF_ACC_VIO_INFO_1)); + dev_notice(&arb->spmic->dev, "[PMIF]:PMIF_ACC_VIO_INFO_2 = 0x%x\n", pmif_readl(arb->pmif_base[1], + arb, PMIF_ACC_VIO_INFO_2)); + } +} +static void pmif_wdt_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + pmif_writel(arb->pmif_base[0], arb, 0x40000000, PMIF_IRQ_CLR_0); + if (!IS_ERR(arb->pmif_base[1])) + pmif_writel(arb->pmif_base[1], arb, 0x40000000, PMIF_IRQ_CLR_0); + dev_notice(&arb->spmic->dev, "[PMIF]:WDT IRQ HANDLER DONE\n"); +} +static void pmif_pmif_acc_vio_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; +#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE)) + aee_kernel_warning("PMIF", "PMIF:pmif_acc_vio"); +#endif + dev_notice(&arb->spmic->dev, "[PMIF]:pmif_acc_vio\n"); +} +static void pmif_pmic_acc_vio_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; +#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE)) + aee_kernel_warning("PMIF", "PMIF:pmic_acc_vio"); +#endif + dev_notice(&arb->spmic->dev, "[PMIF]:pmic_acc_vio\n"); +} +static void pmif_cmd_err_parity_err_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; +#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE)) + aee_kernel_warning("PMIF", "PMIF:parity error"); +#endif + dev_notice(&arb->spmic->dev, "[PMIF]:parity error\n"); +} +static void pmif_hw_monitor_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; +#if (IS_ENABLED(CONFIG_MTK_AEE_FEATURE)) + aee_kernel_warning("PMIF", "PMIF:pmif_hw_monitor_match"); +#endif + dev_notice(&arb->spmic->dev, "[PMIF]:pmif_hw_monitor_match\n"); +} +static void pmif_swinf_acc_err_irq_handler(int irq, void *data, u32 val) +{ + struct pmif *arb = data; + pmif_writel(arb->pmif_base[0], arb, val, MD_AUXADC_RDATA_0_ADDR); + pmif_writel(arb->pmif_base[0], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR); + if (!IS_ERR(arb->pmif_base[1])) { + pmif_writel(arb->pmif_base[1], arb, val, MD_AUXADC_RDATA_0_ADDR); + pmif_writel(arb->pmif_base[1], arb, (u32)get_current_time_ms(), MD_AUXADC_RDATA_1_ADDR); + } + dev_notice(&arb->spmic->dev, "[PMIF]:SWINF_ACC_ERR:%d\n", val); +} +static irqreturn_t pmif_event_0_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int irq_f = 0, irq_f_p = 0, idx = 0; + __pm_stay_awake(arb->pmif_m_Thread_lock); + mutex_lock(&arb->pmif_m_mutex); + irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_0); + if (!IS_ERR(arb->pmif_base[1])) + irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_0); + if ((irq_f == 0) && (irq_f_p == 0)) { + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_NONE; + } + for (idx = 0; idx < 32; idx++) { + if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) { + switch (idx) { + case IRQ_PMIF_ACC_VIO_V3: + pmif_acc_vio_irq_handler(irq, data); + break; + case IRQ_WDT_V4: + pmif_wdt_irq_handler(irq, data); + break; + case IRQ_ALL_PMIC_MPU_VIO_V4: + pmif_pmif_acc_vio_irq_handler(irq, data); + break; + default: + dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", + __func__, idx); + break; + } + if (irq_f) + pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_0); + else if (irq_f_p) + pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_0); + else + dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n", + __func__, idx); + break; + } + } + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_HANDLED; +} +static irqreturn_t pmif_event_1_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int irq_f = 0, irq_f_p = 0, idx = 0; + __pm_stay_awake(arb->pmif_m_Thread_lock); + mutex_lock(&arb->pmif_m_mutex); + irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_1); + if (!IS_ERR(arb->pmif_base[1])) + irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_1); + if ((irq_f == 0) && (irq_f_p == 0)) { + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_NONE; + } + for (idx = 0; idx < 32; idx++) { + if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) { + switch (idx) { + default: + dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", + __func__, idx); + break; + } + if (irq_f) + pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_1); + else if (irq_f_p) + pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_1); + else + dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n", + __func__, idx); + break; + } + } + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_HANDLED; +} +static irqreturn_t pmif_event_2_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int irq_f = 0, irq_f_p = 0, idx = 0; + __pm_stay_awake(arb->pmif_m_Thread_lock); + mutex_lock(&arb->pmif_m_mutex); + irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_2); + if (!IS_ERR(arb->pmif_base[1])) + irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_2); + if ((irq_f == 0) && (irq_f_p == 0)) { + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_NONE; + } + for (idx = 0; idx < 32; idx++) { + if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) { + switch (idx) { + case IRQ_PMIC_CMD_ERR_PARITY_ERR: + pmif_cmd_err_parity_err_irq_handler(irq, data); + break; + case IRQ_PMIF_ACC_VIO_V2: + pmif_pmif_acc_vio_irq_handler(irq, data); + break; + case IRQ_PMIC_ACC_VIO: + pmif_pmic_acc_vio_irq_handler(irq, data); + break; + default: + dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", + __func__, idx); + break; + } + if (irq_f) + pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_2); + else if (irq_f_p) + pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_2); + else + dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n", + __func__, idx); + break; + } + } + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_HANDLED; +} +static irqreturn_t pmif_event_3_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int irq_f = 0, irq_f_p = 0, idx = 0; + __pm_stay_awake(arb->pmif_m_Thread_lock); + mutex_lock(&arb->pmif_m_mutex); + irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_3); + if (!IS_ERR(arb->pmif_base[1])) + irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_3); + if ((irq_f == 0) && (irq_f_p == 0)) { + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_NONE; + } + for (idx = 0; idx < 32; idx++) { + if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) { + switch (idx) { + case IRQ_PMIF_SWINF_ACC_ERR_0: + case IRQ_PMIF_SWINF_ACC_ERR_0_V2: + pmif_swinf_acc_err_irq_handler(irq, data, 0x0); + break; + case IRQ_PMIF_SWINF_ACC_ERR_1: + case IRQ_PMIF_SWINF_ACC_ERR_1_V2: + pmif_swinf_acc_err_irq_handler(irq, data, 0x1); + break; + case IRQ_PMIF_SWINF_ACC_ERR_2: + case IRQ_PMIF_SWINF_ACC_ERR_2_V2: + pmif_swinf_acc_err_irq_handler(irq, data, 0x2); + break; + case IRQ_LAT_LIMIT_REACHED: + case IRQ_PMIF_SWINF_ACC_ERR_3_V2: + if (arb->data->caps == 1) + pmif_lat_limit_reached_irq_handler(irq, data); + else + pmif_swinf_acc_err_irq_handler(irq, data, 0x3); + break; + case IRQ_PMIF_SWINF_ACC_ERR_4: + case IRQ_PMIF_SWINF_ACC_ERR_4_V2: + pmif_swinf_acc_err_irq_handler(irq, data, 0x4); + break; + case IRQ_PMIF_SWINF_ACC_ERR_5: + case IRQ_PMIF_SWINF_ACC_ERR_5_V2: + pmif_swinf_acc_err_irq_handler(irq, data, 0x5); + break; + case IRQ_HW_MONITOR_V2: + case IRQ_HW_MONITOR_V3: + pmif_hw_monitor_irq_handler(irq, data); + break; + case IRQ_WDT_V2: + case IRQ_WDT_V3: + pmif_wdt_irq_handler(irq, data); + break; + case IRQ_PMIC_ACC_VIO_V2: + pmif_pmic_acc_vio_irq_handler(irq, data); + break; + case IRQ_ALL_PMIC_MPU_VIO_V2: + case IRQ_ALL_PMIC_MPU_VIO_V3: + pmif_pmif_acc_vio_irq_handler(irq, data); + break; + default: + dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", __func__, idx); + break; + } + if (irq_f) { + if ((!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) && + (!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2)))) + pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_3); + } else if (irq_f_p) { + if ((!(irq_f_p & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0))) && + (!(irq_f & (0x1 << IRQ_PMIF_SWINF_ACC_ERR_0_V2)))) + pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_3); + } else + dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n", + __func__, idx); + break; + } + } + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_HANDLED; +} +static irqreturn_t pmif_event_4_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + int irq_f = 0, irq_f_p = 0, idx = 0; + __pm_stay_awake(arb->pmif_m_Thread_lock); + mutex_lock(&arb->pmif_m_mutex); + irq_f = pmif_readl(arb->pmif_base[0], arb, PMIF_IRQ_FLAG_4); + if (!IS_ERR(arb->pmif_base[1])) + irq_f_p = pmif_readl(arb->pmif_base[1], arb, PMIF_IRQ_FLAG_4); + if ((irq_f == 0) && (irq_f_p == 0)) { + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_NONE; + } + for (idx = 0; idx < 32; idx++) { + if (((irq_f & (0x1 << idx)) != 0) || ((irq_f_p & (0x1 << idx)) != 0)) { + switch (idx) { + default: + dev_notice(&arb->spmic->dev, "%s IRQ[%d] triggered\n", + __func__, idx); + break; + } + if (irq_f) + pmif_writel(arb->pmif_base[0], arb, irq_f, PMIF_IRQ_CLR_4); + else if (irq_f_p) + pmif_writel(arb->pmif_base[1], arb, irq_f_p, PMIF_IRQ_CLR_4); + else + dev_notice(&arb->spmic->dev, "%s IRQ[%d] is not cleared due to empty flags\n", + __func__, idx); + break; + } + } + mutex_unlock(&arb->pmif_m_mutex); + __pm_relax(arb->pmif_m_Thread_lock); + return IRQ_HANDLED; +} +static struct pmif_irq_desc pmif_event_irq[] = { + PMIF_IRQDESC(event_0), + PMIF_IRQDESC(event_1), + PMIF_IRQDESC(event_2), + PMIF_IRQDESC(event_3), + PMIF_IRQDESC(event_4), +}; +static void pmif_irq_register(struct platform_device *pdev, + struct pmif *arb, int irq) +{ + int i = 0, ret = 0; + u32 irq_event_en[5] = {0}; + for (i = 0; i < ARRAY_SIZE(pmif_event_irq); i++) { + if (!pmif_event_irq[i].name) + continue; + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + pmif_event_irq[i].irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_SHARED, + pmif_event_irq[i].name, arb); + if (ret < 0) { + dev_notice(&pdev->dev, "request %s irq fail\n", + pmif_event_irq[i].name); + continue; + } + pmif_event_irq[i].irq = irq; + } + ret = of_property_read_u32_array(pdev->dev.of_node, "irq-event-en", + irq_event_en, ARRAY_SIZE(irq_event_en)); + pmif_writel(arb->pmif_base[0], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[0], + arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0); + pmif_writel(arb->pmif_base[0], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[0], + arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1); + pmif_writel(arb->pmif_base[0], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[0], + arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2); + pmif_writel(arb->pmif_base[0], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[0], + arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3); + pmif_writel(arb->pmif_base[0], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[0], + arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4); + if (!IS_ERR(arb->pmif_base[1])) { + pmif_writel(arb->pmif_base[1], arb, irq_event_en[0] | pmif_readl(arb->pmif_base[1], + arb, PMIF_IRQ_EVENT_EN_0), PMIF_IRQ_EVENT_EN_0); + pmif_writel(arb->pmif_base[1], arb, irq_event_en[1] | pmif_readl(arb->pmif_base[1], + arb, PMIF_IRQ_EVENT_EN_1), PMIF_IRQ_EVENT_EN_1); + pmif_writel(arb->pmif_base[1], arb, irq_event_en[2] | pmif_readl(arb->pmif_base[1], + arb, PMIF_IRQ_EVENT_EN_2), PMIF_IRQ_EVENT_EN_2); + pmif_writel(arb->pmif_base[1], arb, irq_event_en[3] | pmif_readl(arb->pmif_base[1], + arb, PMIF_IRQ_EVENT_EN_3), PMIF_IRQ_EVENT_EN_3); + pmif_writel(arb->pmif_base[1], arb, irq_event_en[4] | pmif_readl(arb->pmif_base[1], + arb, PMIF_IRQ_EVENT_EN_4), PMIF_IRQ_EVENT_EN_4); + } +} +static irqreturn_t rcs_irq_handler(int irq, void *data) +{ + struct pmif *arb = data; + unsigned int slv_irq_sta, slv_irq_sta_p; + int i; + + for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) { + slv_irq_sta = mtk_spmi_readl(arb->spmimst_base[0], arb, SPMI_SLV_3_0_EINT + (i / 4)); + slv_irq_sta = (slv_irq_sta >> ((i % 4) * 8)) & 0xFF; + if (!IS_ERR(arb->spmimst_base[1])) { + slv_irq_sta_p = mtk_spmi_readl(arb->spmimst_base[1], arb, SPMI_SLV_3_0_EINT + (i / 4)); + slv_irq_sta_p = (slv_irq_sta_p >> ((i % 4) * 8)) & 0xFF; + } + if (slv_irq_sta) { + mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)), + SPMI_SLV_3_0_EINT + (i / 4)); + if (arb->rcs_enable_hwirq[i] && slv_irq_sta) { + dev_info(&arb->spmic->dev, + "hwirq=%d, sta=0x%x\n", i, slv_irq_sta); + handle_nested_irq(irq_find_mapping(arb->domain, i)); + } + } else { + if (!IS_ERR(arb->spmimst_base[1])) { + mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)), + SPMI_SLV_3_0_EINT + (i / 4)); + if (arb->rcs_enable_hwirq[i] && slv_irq_sta_p) { + dev_info(&arb->spmic->dev, + "hwirq=%d, sta=0x%x\n", i, slv_irq_sta_p); + handle_nested_irq(irq_find_mapping(arb->domain, i)); + } + } + } + } + return IRQ_HANDLED; +} +static int rcs_irq_register(struct platform_device *pdev, + struct pmif *arb, int irq) +{ + int i, ret = 0; + mutex_init(&arb->rcs_m_irqlock); + mutex_init(&arb->rcs_p_irqlock); + arb->rcs_enable_hwirq = devm_kcalloc(&pdev->dev, SPMI_MAX_SLAVE_ID, + sizeof(*arb->rcs_enable_hwirq), + GFP_KERNEL); + if (!arb->rcs_enable_hwirq) + return -ENOMEM; + if (arb->rcs_irq == irq) + arb->irq_chip = rcs_irq_chip; + else if (arb->rcs_irq_p == irq) + arb->irq_chip_p = rcs_irq_chip_p; + else + dev_notice(&pdev->dev, "no rcs irq %d registered\n", irq); + arb->domain = irq_domain_add_linear(pdev->dev.of_node, + SPMI_MAX_SLAVE_ID, + &rcs_irq_domain_ops, arb); + if (!arb->domain) { + dev_notice(&pdev->dev, "Failed to create IRQ domain\n"); + return -ENODEV; + } + for (i = 0; i < SPMI_MAX_SLAVE_ID; i++) { + mtk_spmi_writel(arb->spmimst_base[0], arb, (0xFF << ((i % 4) * 8)), + SPMI_SLV_3_0_EINT + (i / 4)); + if (!IS_ERR(arb->spmimst_base[1])) { + mtk_spmi_writel(arb->spmimst_base[1], arb, (0xFF << ((i % 4) * 8)), + SPMI_SLV_3_0_EINT + (i / 4)); + } + } + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + rcs_irq_handler, IRQF_ONESHOT, + rcs_irq_chip.name, arb); + if (ret < 0) { + dev_notice(&pdev->dev, "Failed to request IRQ=%d, ret = %d\n", + irq, ret); + return ret; + } + enable_irq_wake(irq); + return ret; +} static int mtk_spmi_probe(struct platform_device *pdev) { struct pmif *arb; @@ -457,41 +1293,50 @@ static int mtk_spmi_probe(struct platform_device *pdev) if (IS_ERR(ctrl)) return PTR_ERR(ctrl); + ctrl->cmd = pmif_arb_cmd; + ctrl->read_cmd = pmif_spmi_read_cmd; + ctrl->write_cmd = pmif_spmi_write_cmd; arb = spmi_controller_get_drvdata(ctrl); + arb->spmic = ctrl; arb->data = device_get_match_data(&pdev->dev); if (!arb->data) { dev_err(&pdev->dev, "Cannot get drv_data\n"); return -EINVAL; } - arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif"); - if (IS_ERR(arb->base)) - return PTR_ERR(arb->base); - - arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst"); - if (IS_ERR(arb->spmimst_base)) - return PTR_ERR(arb->spmimst_base); - - arb->nclks = ARRAY_SIZE(pmif_clock_names); - for (i = 0; i < arb->nclks; i++) - arb->clks[i].id = pmif_clock_names[i]; - - err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks); - if (err) { - dev_err(&pdev->dev, "Failed to get clocks: %d\n", err); - return err; - } - - err = clk_bulk_prepare_enable(arb->nclks, arb->clks); - if (err) { - dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err); - goto err_put_clks; + arb->pmif_base[0] = devm_platform_ioremap_resource_byname(pdev, "pmif"); + if (IS_ERR(arb->pmif_base[0])) + return PTR_ERR(arb->pmif_base[0]); + + arb->spmimst_base[0] = devm_platform_ioremap_resource_byname(pdev, "spmimst"); + if (IS_ERR(arb->spmimst_base[0])) + return PTR_ERR(arb->spmimst_base[0]); + + arb->pmif_base[1] = devm_platform_ioremap_resource_byname(pdev, "pmif-p"); + if (IS_ERR(arb->pmif_base[1])) + dev_notice(&pdev->dev, "[PMIF]:no pmif-p found\n"); + arb->spmimst_base[1] = devm_platform_ioremap_resource_byname(pdev, "spmimst-p"); + if (IS_ERR(arb->spmimst_base[1])) + dev_notice(&pdev->dev, "[PMIF]:no spmimst-p found\n"); + if (arb->data->caps == 1) { + + arb->nclks = ARRAY_SIZE(pmif_clock_names); + for (i = 0; i < arb->nclks; i++) + arb->clks[i].id = pmif_clock_names[i]; + + err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks); + if (err) { + dev_err(&pdev->dev, "Failed to get clocks: %d\n", err); + return err; + } + + err = clk_bulk_prepare_enable(arb->nclks, arb->clks); + if (err) { + dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err); + goto err_put_clks; + } } - ctrl->cmd = pmif_arb_cmd; - ctrl->read_cmd = pmif_spmi_read_cmd; - ctrl->write_cmd = pmif_spmi_write_cmd; - chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan; arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset; arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset; @@ -499,7 +1344,71 @@ static int mtk_spmi_probe(struct platform_device *pdev) arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset; arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset; - raw_spin_lock_init(&arb->lock); + raw_spin_lock_init(&arb->lock_m); + raw_spin_lock_init(&arb->lock_p); + arb->pmif_m_Thread_lock = + wakeup_source_register(NULL, "pmif_m wakelock"); + arb->pmif_p_Thread_lock = + wakeup_source_register(NULL, "pmif_p wakelock"); + mutex_init(&arb->pmif_m_mutex); + mutex_init(&arb->pmif_p_mutex); + if (arb->data->caps == 2) { + arb->irq = platform_get_irq_byname(pdev, "pmif_irq"); + if (arb->irq < 0) { + dev_notice(&pdev->dev, + "Failed to get pmif_irq, ret = %d\n", arb->irq); + } + pmif_irq_register(pdev, arb, arb->irq); + arb->irq_p = platform_get_irq_byname(pdev, "pmif_p_irq"); + if (arb->irq_p < 0) { + dev_notice(&pdev->dev, + "Failed to get pmif_p_irq, ret = %d\n", arb->irq_p); + } + pmif_irq_register(pdev, arb, arb->irq_p); + arb->rcs_irq = platform_get_irq_byname(pdev, "rcs_irq"); + if (arb->rcs_irq < 0) { + dev_notice(&pdev->dev, + "Failed to get rcs_irq, ret = %d\n", arb->rcs_irq); + } else { + err = rcs_irq_register(pdev, arb, arb->rcs_irq); + if (err) + dev_notice(&pdev->dev, + "Failed to register rcs_irq, ret = %d\n", arb->rcs_irq); + } + arb->rcs_irq_p = platform_get_irq_byname(pdev, "rcs_irq_p"); + if (arb->rcs_irq_p < 0) { + dev_notice(&pdev->dev, + "Failed to get rcs_irq_p, ret = %d\n", arb->rcs_irq_p); + } else { + err = rcs_irq_register(pdev, arb, arb->rcs_irq_p); + if (err) + dev_notice(&pdev->dev, + "Failed to register rcs_irq_p, ret = %d\n", arb->rcs_irq_p); + } + arb->spmi_nack_irq = platform_get_irq_byname(pdev, "spmi_nack_irq"); + if (arb->spmi_nack_irq < 0) { + dev_notice(&pdev->dev, + "Failed to get spmi_nack_irq, ret = %d\n", arb->spmi_nack_irq); + } else { + err = spmi_nack_irq_register(pdev, arb, arb->spmi_nack_irq); + if (err) + dev_notice(&pdev->dev, + "Failed to register spmi_nack_irq, ret = %d\n", + arb->spmi_nack_irq); + } + arb->spmi_p_nack_irq = platform_get_irq_byname(pdev, "spmi_p_nack_irq"); + if (arb->spmi_p_nack_irq < 0) { + dev_notice(&pdev->dev, + "Failed to get spmi_p_nack_irq, ret = %d\n", arb->spmi_p_nack_irq); + } else { + err = spmi_nack_irq_register(pdev, arb, arb->spmi_p_nack_irq); + if (err) + dev_notice(&pdev->dev, + "Failed to register spmi_p_nack_irq, ret = %d\n", + arb->spmi_p_nack_irq); + } + } + spmi_dev_parse(pdev); platform_set_drvdata(pdev, ctrl); @@ -533,6 +1442,9 @@ static const struct of_device_id mtk_spmi_match_table[] = { }, { .compatible = "mediatek,mt8195-spmi", .data = &mt8195_pmif_arb, + }, { + .compatible = "mediatek,mt8196-spmi", + .data = &mt6xxx_pmif_arb, }, { /* sentinel */ }, From patchwork Fri Mar 14 07:32:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?THUgVGFuZyAo5rGk55KQKQ==?= X-Patchwork-Id: 14016378 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A389C192B65; Fri, 14 Mar 2025 07:55:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=60.244.123.138 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938938; cv=none; b=EphBtqOqcbnigUIHjUsHWlKA2bhG9nyiVn6AMuDAUu1IX/8m3/SLnWQDVMwVwKCxoAJ2tviW34p6X/cpZ6k4jNqjG9WNVs34vGpKCdrCGTO3CsIZAwEwc1ck1VoJ7NI/YVuD1LjrRgzwUWFf0vIEAwgv+RTFGV7SIUva8UA7E0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741938938; c=relaxed/simple; bh=HY0j+wYPJHp8dngZrnVwVVFsqEwJCPfDrPhdDj4GMec=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LTPm4AIX8Q0KWuaH5+EHRMxh1+/kyw7Gqvd3DMDGP7Q3ZD4DGGVAhLeaMGJoXbOLTD6ODvbEly07aijE9eYSUDb2DTJfceKvLxMYcXtgBXbtprql83qZRAKQ7wRKwdbNco+zXxBZW6DGcSEKdGFfEaMQ+ufrU9vLxz93Z1huyTY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com; spf=pass smtp.mailfrom=mediatek.com; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b=uYFtcfRw; arc=none smtp.client-ip=60.244.123.138 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mediatek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mediatek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="uYFtcfRw" X-UUID: b381703c00a911f0aae1fd9735fae912-20250314 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=YeVPzS50yaHINy2hyaHmo427d2ZmemrCtOQyBXxOGLc=; b=uYFtcfRwdxaj2iS21RarYs0NybjH/gJXTkpxGu7gB+bb9CZNKKaFzHVB+8Ok+F2h+55CFTT7AW0ctkB2bYbOhY37wEBhkDtuo6Oq5F4sZ9DbNz95V1gqOobphRk+sfFGgEjR2I/cy7ImCGuGIK3Y+e5odC+iDryIioBdNywiC+M=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:bb84586e-4306-4851-bc17-525bc5161ce1,IP:0,UR L:25,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:25 X-CID-META: VersionHash:0ef645f,CLOUDID:f35927e1-3561-4519-9a12-e2c881788b70,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:11|83|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OS A:0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: b381703c00a911f0aae1fd9735fae912-20250314 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 377927494; Fri, 14 Mar 2025 15:55:30 +0800 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 14 Mar 2025 15:55:30 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 14 Mar 2025 15:55:29 +0800 From: Lu.Tang To: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dmitry Torokhov , Lee Jones , Matthias Brugger , AngeloGioacchino Del Regno , Sean Wang , Linus Walleij , Liam Girdwood , Mark Brown , Stephen Boyd , Chen Zhong , Sen Chu CC: , , , , , , , , Lu.Tang Subject: [PATCH 5/5] dt-bindings: pmic: mediatek: Add pmic documents Date: Fri, 14 Mar 2025 15:32:31 +0800 Message-ID: <20250314073307.25092-6-Lu.Tang@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250314073307.25092-1-Lu.Tang@mediatek.com> References: <20250314073307.25092-1-Lu.Tang@mediatek.com> Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add new pmic mfd and adc documents for mt8196 Signed-off-by: Lu.Tang --- .../iio/adc/mediatek,spmi-pmic-auxadc.yaml | 31 ++++ .../bindings/input/mediatek,pmic-keys.yaml | 1 + .../bindings/mfd/mediatek,mt6685.yaml | 50 +++++ .../bindings/mfd/mediatek,spmi-pmic.yaml | 173 ++++++++++++++++++ .../pinctrl/mediatek,mt65xx-pinctrl.yaml | 1 + 5 files changed, 256 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml new file mode 100644 index 000000000000..250782ad7d01 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/mediatek,spmi-pmic-auxadc.yaml @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek SPMI PMIC AUXADC + +maintainers: + - Lu Tang + +description: + The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found + in some MediaTek PMICs, performing various PMIC related measurements + such as battery and PMIC internal voltage regulators temperatures, + other than voltages for various PMIC internal components. + +properties: + compatible: + enum: + - mediatek,mt6363-auxadc + - mediatek,mt6373-auxadc + + "#io-channel-cells": + const: 1 + +required: + - compatible + - "#io-channel-cells" + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml index b95435bd6a9b..ce760039d4c2 100644 --- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml +++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml @@ -31,6 +31,7 @@ properties: - mediatek,mt6358-keys - mediatek,mt6359-keys - mediatek,mt6397-keys + - mediatek,mt6363-keys power-off-time-sec: true diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml new file mode 100644 index 000000000000..d3276df8952b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6685.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/mediatek,mt6685.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6685 Clock IC + +maintainers: + - Lu Tang + +description: | + MT6685 is a clock IC. + Please see the sub-modules below for supported features. + + MT6685 is a multifunction device with the following sub modules: + - RTC + - Clock + +properties: + compatible: + const: mediatek,mt6685 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + #include + #include + + spmi { + mfd@9 { + compatible = "mediatek,mt6685"; + reg = <0x9 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml new file mode 100644 index 000000000000..a8f1231623cf --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,spmi-pmic.yaml @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/mediatek,spmi-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek SPMI PMICs multi-function device + +maintainers: + - Lu Tang + +description: | + Some Mediatek PMICs are interfaced to the chip via the SPMI (System Power + Management Interface) bus. + + The Mediatek SPMI series includes the MT6363, MT6373, MT6316 and other + PMICs.Please see the sub-modules below for supported features. + + MT6363/MT6373 is a multifunction device with the following sub modules: + - Regulators + - ADC + - GPIO + - Keys + MT6316 is a multifunction device with the following sub modules: + - Regulators + +properties: + compatible: + oneOf: + - enum: + - mediatek,mt6363 + - mediatek,mt6373 + - mediatek,mt6316 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + regulators: + type: object + description: + List of child nodes that specify the regulators. + additionalProperties: true + + properties: + compatible: + oneOf: + - enum: + - mediatek,mt6363-regulator + - mediatek,mt6373-regulator + - mediatek,mt6316-regulator + + required: + - compatible + + adc: + type: object + $ref: /schemas/iio/adc/mediatek,spmi-pmic-auxadc.yaml# + unevaluatedProperties: false + + keys: + type: object + $ref: /schemas/input/mediatek,pmic-keys.yaml + unevaluatedProperties: false + description: + Power and Home keys. + + pinctrl: + type: object + $ref: /schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml + unevaluatedProperties: false + description: + Pin controller + +required: + - compatible + - regulators + +additionalProperties: false + +examples: + - | + #include + #include + #include + + spmi { + main_pmic: pmic@4 { + compatible = "mediatek,mt6363"; + reg = <0x4 SPMI_USID>; + interrupts = <0x4 IRQ_TYPE_NONE>; + #address-cells = <0>; + interrupt-controller; + #interrupt-cells = <2>; + + mt6363keys: keys { + compatible = "mediatek,mt6363-keys"; + mediatek,long-press-mode = <1>; + power-off-time-sec = <0>; + + power { + linux,keycodes = <116>; + wakeup-source; + }; + + home { + linux,keycodes = <115>; + }; + }; + + mt6363_pio: pinctrl { + compatible = "mediatek,mt6363-pinctrl"; + gpio-controller; + #gpio-cells = <2>; + }; + + mt6363regulator: regulators { + compatible = "mediatek,mt6363-regulator"; + + mt6363_vs2: vs2 { + regulator-name = "mt6363_vs2"; + regulator-allowed-modes = <0 1 2>; + regulator-always-on; + regulator-allow-set-load; + }; + + mt6363_vbuck1: vbuck1 { + regulator-name = "mt6363_vbuck1"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck2: vbuck2 { + regulator-name = "mt6363_vbuck2"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck3: vbuck3 { + regulator-name = "mt6363_vbuck3"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck4: vbuck4 { + regulator-name = "mt6363_vbuck4"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck5: vbuck5 { + regulator-name = "mt6363_vbuck5"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck6: vbuck6 { + regulator-name = "mt6363_vbuck6"; + regulator-allowed-modes = <0 1 2>; + }; + + mt6363_vbuck7: vbuck7 { + regulator-name = "mt6363_vbuck7"; + regulator-allowed-modes = <0 1 2>; + }; + + // ... + + mt6363_isink_load: isink-load { + regulator-name = "mt6363_isink_load"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml index bccff08a5ba3..bf3ba58a7705 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml @@ -17,6 +17,7 @@ properties: enum: - mediatek,mt2701-pinctrl - mediatek,mt2712-pinctrl + - mediatek,mt6363-pinctrl - mediatek,mt6397-pinctrl - mediatek,mt7623-pinctrl - mediatek,mt8127-pinctrl