From patchwork Tue May 31 10:27:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577994 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6DDD1C433F5 for ; Tue, 31 May 2022 10:28:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245680AbiEaK26 (ORCPT ); Tue, 31 May 2022 06:28:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240755AbiEaK25 (ORCPT ); Tue, 31 May 2022 06:28:57 -0400 Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 130B099800; Tue, 31 May 2022 03:28:56 -0700 (PDT) Received: by mail-pj1-x102a.google.com with SMTP id gc3-20020a17090b310300b001e33092c737so1846372pjb.3; Tue, 31 May 2022 03:28:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lVCUf7UwKal2eUwczXgEX6YxihaKUqsjAaTp8vrMqa8=; b=J5bTGQcSMrYrCOk26pOXvN/PYARqCxWaFborEB83DlYaiFKttbWlrBbO65145hPp6g nEPsOhhgP2PxdFraUo10GmpELr+FKGJtangJMMJ9kJaJBwfTXNN+26whOW3duqxTSOo8 ky/zzcd36eY6aQOAv+xG3FvBuQT5efbHyD8MTK4IvEKdv8uEUeJxyfoHf+SjglfIIvYI HucqCs9czf2aGcQ2NC+S4aJMEOJ4C7xMBMXq0hi2OM+G6YGKY2O8J+ZJeeL7T6hlGku4 m0ONFsapzSIT6QLnMD9GWFFX9Y5IgP0TOOZj5WNvOQm+LGHUjQbjcwBt9kxlt+7Lmt+r ACqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lVCUf7UwKal2eUwczXgEX6YxihaKUqsjAaTp8vrMqa8=; b=12YLYfha7hMCA3jEaBGKmhvDm7k53i33MRNTwZ+244UTzGATi4qsfFTvz9cLOztK9A /Vekb+qCVGmRYbmrZeB37KScLABc9w6Q9dq5QLrGqZTI/Keya+VCfCy4zocEpGMzdmLp aCW0Zpq0GmmUBP1Zb4e8Edlsay4AkcqU7nNjy3Nur+qmUGBXqyB0x8fauxeg/jp5uusX LCOlNUZhNnt/XqGnewL/M8RQS7vmX+R7hupcsbS0/EouIO4cj+Dmtq0tJYd0wCrsZb2C ziFe/xIvnmCZorEL3B+glkCbQl6XuzDpLIog/NsOzxZdDPa7Vi4UZ8PCIBDYCYDgzkfw NthA== X-Gm-Message-State: AOAM531ILwK1t3MyJFAGvrH9RkphTiNCkxBRk9/VA418mGK/kqF6677G iwOi4rSxJDISfu5YqNEDee4= X-Google-Smtp-Source: ABdhPJx24CHOCxgxg2wZ4F7gLFmfrdlzPEtA7W9uazhTWYvSbIjcbzKDQT1ur7eU6U+bYLty+mmAmA== X-Received: by 2002:a17:90a:a085:b0:1e0:97ee:c263 with SMTP id r5-20020a17090aa08500b001e097eec263mr27986451pjp.110.1653992935603; Tue, 31 May 2022 03:28:55 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.28.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:28:55 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 01/14] mfd: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 18:27:56 +0800 Message-Id: <20220531102809.11976-2-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add Mediatek MT6370 MFD support. Signed-off-by: ChiYuan Huang --- drivers/mfd/Kconfig | 13 +++ drivers/mfd/Makefile | 1 + drivers/mfd/mt6370.c | 273 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/mfd/mt6370.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3b59456f5545..d9a7524a3e0e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -937,6 +937,19 @@ config MFD_MT6360 PMIC part includes 2-channel BUCKs and 2-channel LDOs LDO part includes 4-channel LDOs +config MFD_MT6370 + tristate "Mediatek MT6370 SubPMIC" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C + help + Say Y here to enable MT6370 SubPMIC functional support. + It integrate single cell battery charger with adc monitoring, RGB + LEDs, dual channel flashlight, WLED backlight driver, display bias + voltage supply, one general purpose LDO, and cc logic + controller with USBPD commmunication capable. + config MFD_MT6397 tristate "MediaTek MT6397 PMIC Support" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 858cacf659d6..62b27125420e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -242,6 +242,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o 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_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c new file mode 100644 index 000000000000..a5a07be7ccc2 --- /dev/null +++ b/drivers/mfd/mt6370.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_USBC_I2C = 0, + MT6370_PMU_I2C, + MT6370_MAX_I2C +}; + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_CHG_IRQ1 0x1C0 +#define MT6370_REG_CHG_MASK1 0x1E0 + +#define MT6370_VENID_MASK GENMASK(7, 4) + +#define MT6370_NUM_IRQREGS 16 +#define MT6370_USBC_I2CADDR 0x4E +#define MT6370_REG_ADDRLEN 2 +#define MT6370_REG_MAXADDR 0x1FF + +struct mt6370_info { + struct i2c_client *i2c[MT6370_MAX_I2C]; + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; +}; + +static const struct regmap_irq mt6370_irqs[] = { + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8), + REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8) +}; + +static const struct regmap_irq_chip mt6370_irq_chip = { + .name = "mt6370-irqs", + .status_base = MT6370_REG_CHG_IRQ1, + .mask_base = MT6370_REG_CHG_MASK1, + .num_regs = MT6370_NUM_IRQREGS, + .irqs = mt6370_irqs, + .num_irqs = ARRAY_SIZE(mt6370_irqs), +}; + +static const struct resource mt6370_regulator_irqs[] = { + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc") +}; + +static const struct mfd_cell mt6370_devices[] = { + MFD_CELL_OF("adc", NULL, NULL, 0, 0, "mediatek,mt6370-adc"), + MFD_CELL_OF("charger", NULL, NULL, 0, 0, "mediatek,mt6370-charger"), + MFD_CELL_OF("backlight", NULL, NULL, 0, 0, "mediatek,mt6370-backlight"), + MFD_CELL_OF("flashlight", NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"), + MFD_CELL_OF("indicator", NULL, NULL, 0, 0, "mediatek,mt6370-indicator"), + MFD_CELL_OF("tcpc", NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"), + MFD_CELL_RES("regulator", mt6370_regulator_irqs) +}; + +static int mt6370_check_vendor_info(struct mt6370_info *info) +{ + unsigned int devinfo; + int ret; + + ret = regmap_read(info->regmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) { + case 0x8: /* RT5081 */ + case 0xA: /* RT5081A */ + case 0xE: /* MT6370 */ + case 0xF: /* MT6371 */ + case 0x9: /* MT6372P */ + case 0xB: /* MT6372CP */ + break; + default: + dev_err(info->dev, "Not invalid value 0x%02x\n", devinfo); + return -ENODEV; + } + + return 0; +} + +static int mt6370_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct mt6370_info *info = context; + u8 bank_idx = *(u8 *)reg_buf, bank_addr = *(u8 *)(reg_buf + 1); + int ret; + + ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr, + val_size, val_buf); + if (ret != val_size) + return ret; + + return 0; +} + +static int mt6370_regmap_write(void *context, const void *data, size_t count) +{ + struct mt6370_info *info = context; + u8 bank_idx = *(u8 *)data, bank_addr = *(u8 *)(data + 1); + int len = count - MT6370_REG_ADDRLEN; + + return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr, + len, data + MT6370_REG_ADDRLEN); +} + +static const struct regmap_bus mt6370_regmap_bus = { + .read = mt6370_regmap_read, + .write = mt6370_regmap_write, +}; + +static const struct regmap_config mt6370_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .max_register = MT6370_REG_MAXADDR, +}; + +static int mt6370_probe(struct i2c_client *i2c) +{ + struct mt6370_info *info; + struct i2c_client *usbc_i2c; + int ret; + + info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &i2c->dev; + + usbc_i2c = devm_i2c_new_dummy_device(&i2c->dev, i2c->adapter, + MT6370_USBC_I2CADDR); + if (IS_ERR(usbc_i2c)) { + ret = PTR_ERR(usbc_i2c); + dev_err(&i2c->dev, "Failed to register usbc i2c client %d\n", ret); + return ret; + } + + /* Assign I2C client for PMU and TypeC */ + info->i2c[MT6370_PMU_I2C] = i2c; + info->i2c[MT6370_USBC_I2C] = usbc_i2c; + + info->regmap = devm_regmap_init(&i2c->dev, &mt6370_regmap_bus, info, + &mt6370_regmap_config); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&i2c->dev, "Failed to register regmap (%d)\n", ret); + return ret; + } + + ret = mt6370_check_vendor_info(info); + if (ret) { + dev_err(&i2c->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + ret = devm_regmap_add_irq_chip(&i2c->dev, info->regmap, i2c->irq, + IRQF_ONESHOT, -1, &mt6370_irq_chip, + &info->irq_data); + if (ret) { + dev_err(&i2c->dev, "Failed to add irq chip (%d)\n", ret); + return ret; + } + + return devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + mt6370_devices, ARRAY_SIZE(mt6370_devices), + NULL, 0, + regmap_irq_get_domain(info->irq_data)); +} + +static const struct of_device_id mt6370_match_table[] = { + { .compatible = "mediatek,mt6370", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_match_table); + +static struct i2c_driver mt6370_driver = { + .driver = { + .name = "mt6370", + .of_match_table = mt6370_match_table, + }, + .probe_new = mt6370_probe, +}; +module_i2c_driver(mt6370_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 I2C MFD Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:27:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577580 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04B0AC433F5 for ; Tue, 31 May 2022 10:29:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245592AbiEaK3b (ORCPT ); Tue, 31 May 2022 06:29:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240384AbiEaK3a (ORCPT ); Tue, 31 May 2022 06:29:30 -0400 Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82725996B2; Tue, 31 May 2022 03:29:28 -0700 (PDT) Received: by mail-pl1-x635.google.com with SMTP id w3so12439928plp.13; Tue, 31 May 2022 03:29:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QTCg5JULGIw2Y2CEYchomvyXaPsSNLMR9ooYVVdBZ18=; b=JyALrpUJg4IwGvAoEd66OHBB/z536MEQJlLxpzazV0i1M0fUq9kQgWMOLBKXehdCeA UeRSeuUfSTS5KUylqfDXbaD/VB+6mKChnZmV/ED2t/v4U1APfGkPdI8AlOYjMtcjdHyp 1c/JfHiflgoasBqow6Eu+jZDYqgaw7jMHkWYFMyPAj9Sj98j/PPkr3TKXi0Mte39f3b/ B6O4kWSPp8YmslGvCs9upD6apmrWYJK2XxhDAIUA1DxexrFg04gwE8vbIb/hb5k7Dgjz WxhGYGDGk9NsrXvPpWy+d4ByOvgYjCT59wEAWCthKYlEspEoafFiXMLjF10S4h+uBWXn ddvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QTCg5JULGIw2Y2CEYchomvyXaPsSNLMR9ooYVVdBZ18=; b=kSwN/efjbW4Sxqr6wHbQ1Lh8fpPtIf/264ThYljtFFYJeMxHUxxouC5jVvFhvHWnta A10fsH6f8DWDW1mNvHiCPCmUNTdWXhRrEnIX9O2qmhLoiah18Orkl4gNR0E5ouuR1cgI /TG96lCvdFcZgcouKRJR6d0lq/GhgKoG9m6Xx6JN0AtUgoTHXFx+1QcagZNJiKW92vC8 C6l++KnrTqrq+xdgwMhn1XukqBfIypYna75aZ9YZ4QUz2iO34yKq+ZQZibbrejsiWHQI g9XnX1xdtHPWnmEhwhFLbOTnV2ksNkv1oFXYvF5u1f5rQbdIiYcNaIlStaCv252/wMCa s6NA== X-Gm-Message-State: AOAM533PUu6PGTndZE1OcCwCnkY6AnIT12k3997Na7i4aLY6LiXl86ck 5vZZIdQGw1u9EXaXLoIImKo= X-Google-Smtp-Source: ABdhPJyI1IU2VPs1KZFCOAbWLDFh6/Ui6wCA7ZCL+j8rgSJaLJA73HsWZF7/1KmMAYNUFQ5Uq4KOoA== X-Received: by 2002:a17:90b:1098:b0:1e2:f4bc:d0 with SMTP id gj24-20020a17090b109800b001e2f4bc00d0mr11030825pjb.125.1653992967995; Tue, 31 May 2022 03:29:27 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.29.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:29:27 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 02/14] usb: typec: tcpci_mt6370: Add Mediatek MT6370 tcpci driver Date: Tue, 31 May 2022 18:27:57 +0800 Message-Id: <20220531102809.11976-3-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add chip level mt6370 tcpci driver. Signed-off-by: ChiYuan Huang --- drivers/usb/typec/tcpm/Kconfig | 8 + drivers/usb/typec/tcpm/Makefile | 1 + drivers/usb/typec/tcpm/tcpci_mt6370.c | 212 ++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 557f392fe24d..f4b7363bc7e9 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,14 @@ config TYPEC_MT6360 USB Type-C. It works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_TCPCI_MT6370 + tristate "Mediatek MT6370 Type-C driver" + depends on MFD_MT6370 + help + Mediatek MT6370 is a multi-functional IC that includes + USB Type-C. It works with Type-C Port Controller Manager + to provide USB PD and USB Type-C functionalities. + config TYPEC_TCPCI_MAXIM tristate "Maxim TCPCI based Type-C chip driver" help diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index 7d499f3569fd..906d9dced8e7 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -6,4 +6,5 @@ typec_wcove-y := wcove.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o +obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c new file mode 100644 index 000000000000..ce7f5e03fd10 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tcpci.h" + +#define MT6370_REG_SYSCTRL8 0x9B + +#define MT6370_AUTOIDLE_MASK BIT(3) + +#define MT6370_VENDOR_ID 0x29CF +#define MT6370_TCPC_DID_A 0x2170 + +struct mt6370_priv { + struct device *dev; + struct regulator *vbus; + struct tcpci *tcpci; + struct tcpci_data tcpci_data; + int irq; +}; + +static const struct reg_sequence mt6370_reg_init[] = { + REG_SEQ(0xA0, 0x1, 1000), + REG_SEQ(0x81, 0x38, 0), + REG_SEQ(0x82, 0x82, 0), + REG_SEQ(0xBA, 0xFC, 0), + REG_SEQ(0xBB, 0x50, 0), + REG_SEQ(0x9E, 0x8F, 0), + REG_SEQ(0xA1, 0x5, 0), + REG_SEQ(0xA2, 0x4, 0), + REG_SEQ(0xA3, 0x4A, 0), + REG_SEQ(0xA4, 0x01, 0), + REG_SEQ(0x95, 0x01, 0), + REG_SEQ(0x80, 0x71, 0), + REG_SEQ(0x9B, 0x3A, 1000) +}; + +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data) +{ + u16 did; + int ret; + + ret = regmap_register_patch(data->regmap, mt6370_reg_init, + ARRAY_SIZE(mt6370_reg_init)); + if (ret) + return ret; + + ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16)); + if (ret) + return ret; + + if (did == MT6370_TCPC_DID_A) { + ret = regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80); + if (ret) + return ret; + } + + return 0; +} + +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data, + bool enable) +{ + return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8, + MT6370_AUTOIDLE_MASK, + !enable ? MT6370_AUTOIDLE_MASK : 0); +} + +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data, + bool source, bool sink) +{ + struct mt6370_priv *priv = container_of(data, struct mt6370_priv, + tcpci_data); + int ret; + + ret = regulator_is_enabled(priv->vbus); + if (ret < 0) + return ret; + + if (ret && !source) + ret = regulator_disable(priv->vbus); + else if (!ret && source) + ret = regulator_enable(priv->vbus); + else + ret = 0; + + return ret; +} + +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id) +{ + struct mt6370_priv *priv = dev_id; + + return tcpci_irq(priv->tcpci); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + struct regmap *regmap = priv->tcpci_data.regmap; + u16 vid; + int ret; + + ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16)); + if (ret) + return ret; + + if (vid != MT6370_VENDOR_ID) { + dev_err(priv->dev, "Vendor ID not correct 0x%02x\n", vid); + return -ENODEV; + } + + return 0; +} + +static int mt6370_tcpc_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + platform_set_drvdata(pdev, priv); + + priv->tcpci_data.regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->tcpci_data.regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "Failed to get TCPC irq (%d)\n", priv->irq); + return priv->irq; + } + + /* Assign TCPCI feature and ops */ + priv->tcpci_data.auto_discharge_disconnect = 1; + priv->tcpci_data.init = mt6370_tcpc_init; + priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn; + + priv->vbus = devm_regulator_get_optional(&pdev->dev, "vbus"); + if (!IS_ERR(priv->vbus)) + priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus; + + priv->tcpci = tcpci_register_port(&pdev->dev, &priv->tcpci_data); + if (IS_ERR(priv->tcpci)) { + dev_err(&pdev->dev, "Failed to register tcpci port\n"); + return PTR_ERR(priv->tcpci); + } + + ret = devm_request_threaded_irq(&pdev->dev, priv->irq, NULL, + mt6370_irq_handler, IRQF_ONESHOT, + dev_name(&pdev->dev), priv); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate irq (%d)\n", ret); + tcpci_unregister_port(priv->tcpci); + return ret; + } + + device_init_wakeup(&pdev->dev, true); + dev_pm_set_wake_irq(&pdev->dev, priv->irq); + return 0; +} + +static int mt6370_tcpc_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + disable_irq(priv->irq); + tcpci_unregister_port(priv->tcpci); + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + return 0; +} + +static const struct of_device_id mt6370_tcpc_devid_table[] = { + { .compatible = "mediatek,mt6370-tcpc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table); + +static struct platform_driver mt6370_tcpc_driver = { + .driver = { + .name = "mt6370-tcpc", + .of_match_table = mt6370_tcpc_devid_table, + }, + .probe = mt6370_tcpc_probe, + .remove = mt6370_tcpc_remove, +}; +module_platform_driver(mt6370_tcpc_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:27:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577987 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B3B08C433EF for ; Tue, 31 May 2022 12:00:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343980AbiEaMAw (ORCPT ); Tue, 31 May 2022 08:00:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243208AbiEaMAv (ORCPT ); Tue, 31 May 2022 08:00:51 -0400 Received: from mail-qv1-xf41.google.com (mail-qv1-xf41.google.com [IPv6:2607:f8b0:4864:20::f41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32D6862A08; Tue, 31 May 2022 05:00:50 -0700 (PDT) Received: by mail-qv1-xf41.google.com with SMTP id cv1so11796617qvb.5; Tue, 31 May 2022 05:00:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sePt3x7ON3JH7CeHoCRuD6Euif4kN7Rj2nuq+sT7jGM=; b=a1C7geg44/vyN6CH6BtasgsefGUrIoeeQas19yYLFdsSwBCrHd99IIVPXwoqloAhmM /+Hd0Nu8GvWazokVuyhb5fDwtnr43eeEG6h3SDsjkfAD6lURX/LWSEltrsbNvwVNIWmC xc1rDPk3beFIetJ/zO5fDs4fIZ6loCrprKswhzjHZi2AKvOVWjLHcs5hh59Rt/GlORjz NDWalXQHaM4ki7NYyJbv8hmuD3nxk/q9xIUknNFKykTk3mx0eWSNEJMM58kD9in1CjB9 Y5qrmP2ganqIkhlAwNot4KrUXSGl/k5YlWNK0Kr5oMGHsBZo7WkBqCrlI/hueU6O3CP2 D7ZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sePt3x7ON3JH7CeHoCRuD6Euif4kN7Rj2nuq+sT7jGM=; b=Lbw6zqYEp7PD4wRB66cQzKw0DZIV3YdsQvlZW37asRQp1+Qbm8TsC/Crlsu4yPZJbr RQsvYJf2IFz1nhOP1HNClHEK5SAaPqihtVU87b1eSyC+wQRksNRX9i7GWfu5ApnxN9jg c5GR3BIgtO5vr7U0cN3wZZ2t4GZT2pXFCEd714gO8f0r+WWg4Jn+EVw+xvxPzOITbZaP 4oTFY3JcYVarz9LsG1FWXGf9ItU1+A/Fl5SKQgbOa3TIHBcRTz5okGrOXHdBzaZF1g1Z 3G5IFeFQhMwIuZV4W5Rp26gLpIe2WbGNbgB4YdYh8io4mk/bwX7yvYpZi20ynBkQir5P bw1g== X-Gm-Message-State: AOAM533uxdNKaBd3m5tcj0o4VcozCE+gEIhPnZTxzFKkHfCE11vN2jqc pL8ixgbK3Ltu8QvqNtpT7OOm6YJmBSw= X-Google-Smtp-Source: ABdhPJznECG9ysRHKdOsoxJuaAI0R0aP7H6dI0m1RwwQYampL4SnNF7DFpIy3MUp9wHblt7yBtTbrQ== X-Received: by 2002:aa7:8141:0:b0:518:425b:760e with SMTP id d1-20020aa78141000000b00518425b760emr58507803pfn.27.1653992980058; Tue, 31 May 2022 03:29:40 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.29.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:29:39 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 03/14] regulator: mt6370: Add mt6370 DisplayBias and VibLDO support Date: Tue, 31 May 2022 18:27:58 +0800 Message-Id: <20220531102809.11976-4-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add mt6370 DisplayBias and VibLDO support. Signed-off-by: ChiYuan Huang --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/mt6370-regulator.c | 389 +++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 drivers/regulator/mt6370-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index cbe0f96ca342..dcb6866dab53 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -804,6 +804,14 @@ config REGULATOR_MT6360 2-channel buck with Thermal Shutdown and Overload Protection 6-channel High PSRR and Low Dropout LDO. +config REGULATOR_MT6370 + tristate "MT6370 SubPMIC Regulator" + depends on MFD_MT6370 + help + Say Y here to enable MT6370 regulator support. + This driver support the control for DisplayBias voltages and one + general purpose LDO which commonly used to drive the vibrator. + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8d3ee8b6d41d..f1cbff21843e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-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_MT6370) += mt6370-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/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c new file mode 100644 index 000000000000..949b2c7b5556 --- /dev/null +++ b/drivers/regulator/mt6370-regulator.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_IDX_DSVBOOST = 0, + MT6370_IDX_DSVPOS, + MT6370_IDX_DSVNEG, + MT6370_IDX_VIBLDO, + MT6370_MAX_IDX +}; + +#define MT6370_REG_LDO_CFG 0x180 +#define MT6370_REG_LDO_VOUT 0x181 +#define MT6370_REG_DB_CTRL1 0x1B0 +#define MT6370_REG_DB_CTRL2 0x1B1 +#define MT6370_REG_DB_VBST 0x1B2 +#define MT6370_REG_DB_VPOS 0x1B3 +#define MT6370_REG_DB_VNEG 0x1B4 +#define MT6370_REG_LDO_STAT 0x1DC +#define MT6370_REG_DB_STAT 0x1DF + +#define MT6370_LDOOMS_MASK BIT(7) +#define MT6370_LDOEN_MASK BIT(7) +#define MT6370_LDOVOUT_MASK GENMASK(3, 0) +#define MT6370_DBPERD_MASK (BIT(7) | BIT(4)) +#define MT6370_DBEXTEN_MASK BIT(0) +#define MT6370_DBVPOSEN_MASK BIT(6) +#define MT6370_DBVPOSDISG_MASK BIT(5) +#define MT6370_DBVNEGEN_MASK BIT(3) +#define MT6370_DBVNEGDISG_MASK BIT(2) +#define MT6370_DBALLON_MASK (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK) +#define MT6370_DBSLEW_MASK GENMASK(7, 6) +#define MT6370_DBVOUT_MASK GENMASK(5, 0) +#define MT6370_LDOOC_EVT_MASK BIT(7) +#define MT6370_POSSCP_EVT_MASK BIT(7) +#define MT6370_NEGSCP_EVT_MASK BIT(6) +#define MT6370_BSTOCP_EVT_MASK BIT(5) +#define MT6370_POSOCP_EVT_MASK BIT(4) +#define MT6370_NEGOCP_EVT_MASK BIT(3) + +#define MT6370_LDO_MINUV 1600000 +#define MT6370_LDO_STPUV 200000 +#define MT6370_LDO_N_VOLT 13 +#define MT6370_DBVBOOST_MINUV 4000000 +#define MT6370_DBVBOOST_STPUV 50000 +#define MT6370_DBVBOOST_N_VOLT 45 +#define MT6370_DBVOUT_MINUV 4000000 +#define MT6370_DBVOUT_STPUV 50000 +#define MT6370_DBVOUT_N_VOLT 41 + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev[MT6370_MAX_IDX]; + bool use_external_ctrl; +}; + +static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 }; +static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 }; + +static int mt6370_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int stat_reg, stat, rpt_flags = 0; + int rid = rdev_get_id(rdev), ret; + + if (rid == MT6370_IDX_VIBLDO) + stat_reg = MT6370_REG_LDO_STAT; + else + stat_reg = MT6370_REG_DB_STAT; + + ret = regmap_read(regmap, stat_reg, &stat); + if (ret) + return ret; + + switch (rid) { + case MT6370_IDX_DSVBOOST: + if (stat & MT6370_BSTOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVPOS: + if (stat & MT6370_POSSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_POSOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVNEG: + if (stat & MT6370_NEGSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_NEGOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + default: + if (stat & MT6370_LDOOC_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + } + + *flags = rpt_flags; + return 0; +} + +static const struct regulator_ops mt6370_dbvboost_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_dbvout_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_ldo_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static int mt6370_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct mt6370_priv *priv = config->driver_data; + struct gpio_desc *enable_gpio; + int ret; + + enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0, + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + desc->name); + if (IS_ERR(enable_gpio)) { + config->ena_gpiod = NULL; + return 0; + } + + /* + * RG control by default + * Only if all are using external pin, change all by external control + */ + if (priv->use_external_ctrl) { + ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1, + MT6370_DBEXTEN_MASK, + MT6370_DBEXTEN_MASK); + if (ret) + return ret; + } + + config->ena_gpiod = enable_gpio; + priv->use_external_ctrl = true; + return 0; +} + +static const struct regulator_desc mt6370_regulator_descs[] = { + { + .name = "mt6370-dsv-vbst", + .of_match = of_match_ptr("dsvbst"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVBOOST, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_dbvboost_ops, + .min_uV = MT6370_DBVBOOST_MINUV, + .uV_step = MT6370_DBVBOOST_STPUV, + .n_voltages = MT6370_DBVBOOST_N_VOLT, + .vsel_reg = MT6370_REG_DB_VBST, + .vsel_mask = MT6370_DBVOUT_MASK, + .bypass_reg = MT6370_REG_DB_CTRL1, + .bypass_mask = MT6370_DBPERD_MASK, + .bypass_val_on = MT6370_DBPERD_MASK, + }, + { + .name = "mt6370-dsv-vpos", + .of_match = of_match_ptr("dsvpos"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVPOS, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VPOS, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVPOSEN_MASK, + .ramp_reg = MT6370_REG_DB_VPOS, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vpos_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVPOSDISG_MASK, + .active_discharge_on = MT6370_DBVPOSDISG_MASK, + }, + { + .name = "mt6370-dsv-vneg", + .of_match = of_match_ptr("dsvneg"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVNEG, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VNEG, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVNEGEN_MASK, + .ramp_reg = MT6370_REG_DB_VNEG, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vneg_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVNEGDISG_MASK, + .active_discharge_on = MT6370_DBVNEGDISG_MASK, + }, + { + .name = "mt6370-vib-ldo", + .of_match = of_match_ptr("vibldo"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_VIBLDO, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_ldo_ops, + .min_uV = MT6370_LDO_MINUV, + .uV_step = MT6370_LDO_STPUV, + .n_voltages = MT6370_LDO_N_VOLT, + .vsel_reg = MT6370_REG_LDO_VOUT, + .vsel_mask = MT6370_LDOVOUT_MASK, + .enable_reg = MT6370_REG_LDO_VOUT, + .enable_mask = MT6370_LDOEN_MASK, + .active_discharge_reg = MT6370_REG_LDO_CFG, + .active_discharge_mask = MT6370_LDOOMS_MASK, + .active_discharge_on = MT6370_LDOOMS_MASK, + } +}; + +static irqreturn_t mt6370_scp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_ocp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); + return IRQ_HANDLED; +} + +static int mt6370_regulator_irq_register(struct mt6370_priv *priv) +{ + struct platform_device *pdev = to_platform_device(priv->dev); + static const struct { + const char *name; + int rid; + irq_handler_t handler; + } mt6370_irqs[] = { + { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler }, + { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler }, + { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler }, + { "db_vpos_ocp", MT6370_IDX_DSVPOS, mt6370_ocp_handler }, + { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler }, + { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler } + }; + struct regulator_dev *rdev; + int i, irq, ret; + + for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) { + irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name); + + rdev = priv->rdev[mt6370_irqs[i].rid]; + + ret = devm_request_threaded_irq(priv->dev, irq, NULL, + mt6370_irqs[i].handler, 0, + mt6370_irqs[i].name, rdev); + if (ret) { + dev_err(priv->dev, + "Failed to register (%d) interrupt\n", i); + return ret; + } + } + + return 0; +} + +static int mt6370_regualtor_register(struct mt6370_priv *priv) +{ + struct regulator_dev *rdev; + struct regulator_config cfg = {}; + struct device *parent = priv->dev->parent; + int i; + + cfg.dev = parent; + cfg.driver_data = priv; + + for (i = 0; i < MT6370_MAX_IDX; i++) { + rdev = devm_regulator_register(priv->dev, + mt6370_regulator_descs + i, + &cfg); + if (IS_ERR(rdev)) { + dev_err(priv->dev, + "Failed to register (%d) regulator\n", i); + return PTR_ERR(rdev); + } + + priv->rdev[i] = rdev; + } + + return 0; +} + +static int mt6370_regulator_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = mt6370_regualtor_register(priv); + if (ret) + return ret; + + return mt6370_regulator_irq_register(priv); +} + +static const struct platform_device_id mt6370_devid_table[] = { + { "mt6370-regulator", 0}, + {} +}; +MODULE_DEVICE_TABLE(platform, mt6370_devid_table); + +static struct platform_driver mt6370_regulator_driver = { + .driver = { + .name = "mt6370-regulator", + }, + .id_table = mt6370_devid_table, + .probe = mt6370_regulator_probe, +}; +module_platform_driver(mt6370_regulator_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:27:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577993 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7EE77C433FE for ; Tue, 31 May 2022 10:29:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245729AbiEaK3v (ORCPT ); Tue, 31 May 2022 06:29:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240566AbiEaK3u (ORCPT ); Tue, 31 May 2022 06:29:50 -0400 Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4F41299822; Tue, 31 May 2022 03:29:49 -0700 (PDT) Received: by mail-pj1-x1030.google.com with SMTP id m14-20020a17090a414e00b001df77d29587so2189876pjg.2; Tue, 31 May 2022 03:29:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SkB25f3Zqc7wiMdR8YRJzsTcyth+4OQXoMwAgvK1QoA=; b=WaZkqw/nAE0btfMkw5k3uEASutkitZDpjyRZtRR+DynB3G+o+yWrWBW6xJFhMG1UZo tDh9p5viNQpKLRuxqsgSGnStKUmoFrlye4bmAa7YefdYjjmenqPkQe8QQdwtwUcce9P2 Hsf+AVNAY6QR2iNFRZOQSxNmYZBBQ8EfBnenX+EeI1sZ9c/hELvDKUOWW0fhAq4GXEJ3 Ue67IkuVuNAlb8goTGteaTlKyKSqogGa7DNtVQftkKV5X/qFXq7H/M2eHeFIS7iDU09g MNb7MyJeu/Tkjt8qCxmbg6V8Z8D5CCzRsEj7m8EOnsMbymSSW41Gmzzgh8JbibcVEyFX 8KpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SkB25f3Zqc7wiMdR8YRJzsTcyth+4OQXoMwAgvK1QoA=; b=pyFwsI2MdVYimaU25sy7vrIKmG8Ip7KY015RffmVla90PexFzrNOTBIbb7vVoQvGEZ piO9O7be/ScZHWq7UQoMIEjszGUrWDbmulc/6TgNZ7Wp3G/Pq04wzsClwVF2Vj4l5uMw GDfZyerHcqCXz3yKElxCNMQnYxFsLHDgNuY4I27LcauXgGTZjm1Ha1jSHC49JvuJ3+wB 1j3z4dokkgGRgOsgI6fQp1mrilwZzMcwwZorxQVcoyKsvupnmeRnNQppI8l0cMiiTriM JeEhZcioHBttpd0wEYck4dFTj/4lz9SSnr3M8I2RTeQw1qJ5mZyXLrYcWeKXlzHP3p01 QQNg== X-Gm-Message-State: AOAM531DfxtionkcnjNaBr5PdeJEXl1ReLF6V3qP62bF5stxEAdUMHHP pTVJEHiBJHJRIWBihtnCYMo= X-Google-Smtp-Source: ABdhPJzxNeCb7FAuinaV1iwx5abtVAnOKPGuzTJDEo6Rosg3S5MXFzK5UduScyddMaXRXxyUZJwz/g== X-Received: by 2002:a17:902:6505:b0:163:b040:829b with SMTP id b5-20020a170902650500b00163b040829bmr15948554plk.173.1653992988766; Tue, 31 May 2022 03:29:48 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.29.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:29:48 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 04/14] iio: adc: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 18:27:59 +0800 Message-Id: <20220531102809.11976-5-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 ADC support. Signed-off-by: ChiaEn Wu --- drivers/iio/adc/Kconfig | 9 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/mt6370-adc.c | 257 +++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/iio/adc/mt6370-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 71ab0a06aa82..d7932dd9b773 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -737,6 +737,15 @@ config MEDIATEK_MT6360_ADC is used in smartphones and tablets and supports a 11 channel general purpose ADC. +config MEDIATEK_MT6370_ADC + tristate "Mediatek MT6370 ADC driver" + depends on MFD_MT6370 + help + Say Y here to enable MT6370 ADC support. + Integrated for System Monitoring includes + is used in smartphones and tablets and supports a 9 channel + general purpose ADC. + config MEDIATEK_MT6577_AUXADC tristate "MediaTek AUXADC driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 39d806f6d457..0ce285c7e2d0 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3911) += mcp3911.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_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c new file mode 100644 index 000000000000..3320ebca17ad --- /dev/null +++ b/drivers/iio/adc/mt6370-adc.c @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_CHG_CTRL3 0x113 /* AICR */ +#define MT6370_REG_CHG_CTRL7 0x117 /* ICHG */ +#define MT6370_REG_CHG_ADC 0x121 +#define MT6370_REG_ADC_DATA_H 0x14C + +#define MT6370_ADC_START_MASK BIT(0) +#define MT6370_ADC_IN_SEL_MASK GENMASK(7, 4) +#define MT6370_AICR_ICHG_MASK GENMASK(7, 2) + +#define MT6370_ADC_CHAN_SHIFT 4 + +#define MT6370_AICR_400MA 0x6 +#define MT6370_ICHG_500MA 0x4 +#define MT6370_ICHG_900MA 0x8 + +#define ADC_CONV_TIME_US 35000 +#define ADC_CONV_POLLING_TIME 1000 + +struct mt6370_adc_data { + struct device *dev; + struct regmap *regmap; + struct mutex lock; +}; + +static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan, + unsigned long addr, int *val) +{ + __be16 be_val; + unsigned int reg_val; + int ret; + + mutex_lock(&priv->lock); + + reg_val = MT6370_ADC_START_MASK | (addr << MT6370_ADC_CHAN_SHIFT); + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val); + if (ret) + goto adc_unlock; + + msleep(ADC_CONV_TIME_US / 1000); + + ret = regmap_read_poll_timeout(priv->regmap, + MT6370_REG_CHG_ADC, reg_val, + !(reg_val & MT6370_ADC_START_MASK), + ADC_CONV_POLLING_TIME, + ADC_CONV_TIME_US * 3); + if (ret) { + if (ret == -ETIMEDOUT) + dev_err(priv->dev, "Failed to wait adc conversion\n"); + goto adc_unlock; + } + + ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H, + &be_val, sizeof(be_val)); + if (ret) + goto adc_unlock; + + *val = be16_to_cpu(be_val); + ret = IIO_VAL_INT; + +adc_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, + int chan, int *val1, int *val2) +{ + unsigned int reg_val; + int ret; + + switch (chan) { + case MT6370_CHAN_VBAT: + case MT6370_CHAN_VSYS: + case MT6370_CHAN_CHG_VDDP: + *val1 = 5000; + return IIO_VAL_INT; + case MT6370_CHAN_IBUS: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_AICR_400MA) + *val1 = 33500; + else + *val1 = 50000; + + return IIO_VAL_INT; + case MT6370_CHAN_IBAT: + ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, ®_val); + if (ret) + return ret; + + reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val); + if (reg_val < MT6370_ICHG_500MA) + *val1 = 23750; + else if (reg_val >= MT6370_ICHG_500MA && + reg_val < MT6370_ICHG_900MA) + *val1 = 26800; + else + *val1 = 50000; + + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV5: + *val1 = 25000; + return IIO_VAL_INT; + case MT6370_CHAN_VBUSDIV2: + *val1 = 50000; + return IIO_VAL_INT; + case MT6370_CHAN_TS_BAT: + *val1 = 25; + *val2 = 10000; + return IIO_VAL_FRACTIONAL; + case MT6370_CHAN_TEMP_JC: + *val1 = 2; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int mt6370_adc_read_offset(struct mt6370_adc_data *priv, + int chan, int *val) +{ + *val = (chan == MT6370_CHAN_TEMP_JC) ? -20 : 0; + return IIO_VAL_INT; +} + +static int mt6370_adc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6370_adc_data *priv = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return mt6370_adc_read_channel(priv, chan->channel, + chan->address, val); + case IIO_CHAN_INFO_SCALE: + return mt6370_adc_read_scale(priv, chan->channel, val, val2); + case IIO_CHAN_INFO_OFFSET: + return mt6370_adc_read_offset(priv, chan->channel, val); + } + + return -EINVAL; +} + +static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = { + "vbusdiv5", "vbusdiv2", "vsys", "vbat", + "ts_bat", "ibus", "ibat", "chg_vddp", + "temp_jc", +}; + +static int mt6370_adc_read_label(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, char *label) +{ + return snprintf(label, PAGE_SIZE, "%s\n", + mt6370_channel_labels[chan->channel]); +} + +static const struct iio_info mt6370_adc_iio_info = { + .read_raw = mt6370_adc_read_raw, + .read_label = mt6370_adc_read_label, +}; + +#define MT6370_ADC_CHAN(_idx, _type, _addr) { \ + .type = _type, \ + .channel = MT6370_CHAN_##_idx, \ + .address = _addr, \ + .scan_index = MT6370_CHAN_##_idx, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +} + +static const struct iio_chan_spec mt6370_adc_channels[] = { + MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1), + MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2), + MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3), + MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4), + MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6), + MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8), + MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9), + MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11), + MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12), +}; + +static int mt6370_adc_probe(struct platform_device *pdev) +{ + int ret; + struct mt6370_adc_data *priv; + struct regmap *regmap; + struct iio_dev *indio_dev; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + priv->dev = &pdev->dev; + priv->regmap = regmap; + mutex_init(&priv->lock); + + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0); + if (ret) { + dev_err(&pdev->dev, "Failed to reset adc\n"); + return ret; + } + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->info = &mt6370_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mt6370_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels); + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct of_device_id mt6370_adc_of_id[] = { + { .compatible = "mediatek,mt6370-adc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_adc_of_id); + +static struct platform_driver mt6370_adc_driver = { + .driver = { + .name = "mt6370-adc", + .of_match_table = mt6370_adc_of_id, + }, + .probe = mt6370_adc_probe, +}; +module_platform_driver(mt6370_adc_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("MT6370 ADC Drvier"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:28:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D661CC433FE for ; Tue, 31 May 2022 10:30:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245742AbiEaKaL (ORCPT ); Tue, 31 May 2022 06:30:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245759AbiEaKaC (ORCPT ); Tue, 31 May 2022 06:30:02 -0400 Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E39189AE53; Tue, 31 May 2022 03:29:59 -0700 (PDT) Received: by mail-pj1-x102d.google.com with SMTP id hv24-20020a17090ae41800b001e33eebdb5dso814803pjb.0; Tue, 31 May 2022 03:29:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7rETQ+FkwMIdlpu81TFS0C/5rmkhteGjy6EXUj0C1Zk=; b=c2VaBzutIQcaAD8Z940igwF05yfOEW2HkaXlLOukdxRfs5a0j71+SNZDL9Ui+P0uXC mmABqZk0GoTGqUL7xco+8fYCcvusMHxEqeRUzX42NaRKoOfzrzisFQ7a7NdWyDcNjSRH NjkzR1/KgCW4mVoQRjfNjrbbdEO1sw0b5FYF8dcskXGSFPbCZR3ErgD0o1rMglT6dGJM Zsgt7YdxnY4asUPjGh0snCUN6JWNlLP0BNocBsE9v1/0gjdbe12PZOdIfxcn7gokc1QB 3rpsuYDNkVwy5U/pY5sKXM1wEc5m+vkbBUL+duzMPhyXfpKvEKx1RrEafGUl1slHdXpu E5qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7rETQ+FkwMIdlpu81TFS0C/5rmkhteGjy6EXUj0C1Zk=; b=ED0UFDNpUsrZQ0HQQyBBrvJ6fz9rYWo8mUZsO2QMaUK9BRI9dhG96IRtswmaNN1zTY zARU+/P9Xkt02XEqFIbhYKv2UZ8hU5zS4267EH5BazSjbHmh/YIKSet3y2R8tP0umJzN MvDxCywWRr8XLDESUNc0nCicK0PaMhDHfRyvJOLOTjiWbXxXwEGqkDmZ2jhUwQB9TGSZ 4l52ZrijIP120vArpJfUWA8pm5kthbXTFt/kko0346fGaNjMHxzc0riZorSjSd57RtIn rSWfdtZfSz8vQvYIs4Iuvz8U8gn1FKP7sRZmOf8qmZIhb3M7eee150tRXCsSEMYnOuYq v/3w== X-Gm-Message-State: AOAM533GkwYns1ykEGUwoVrX/RMLrVCOWDpncaxOuO/t6XhMx0XUAFap hP8BIfoPr2WBIHUK1Zy211o= X-Google-Smtp-Source: ABdhPJzlpQCPVN4RwC5OF0WxF/VClj40/ABXUB1ku3oMFdeu/Lp5dn+yfewwre9w95OKgszvYGF35Q== X-Received: by 2002:a17:902:ef46:b0:153:81f7:7fc2 with SMTP id e6-20020a170902ef4600b0015381f77fc2mr60943267plx.26.1653992998717; Tue, 31 May 2022 03:29:58 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.29.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:29:58 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 05/14] power: supply: mt6370: Add Mediatek MT6370 charger driver Date: Tue, 31 May 2022 18:28:00 +0800 Message-Id: <20220531102809.11976-6-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 charger driver Signed-off-by: ChiaEn Wu --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/mt6370-charger.c | 1132 +++++++++++++++++++++++++ 3 files changed, 1144 insertions(+) create mode 100644 drivers/power/supply/mt6370-charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 1aa8323ad9f6..54d8c3ab01cc 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -619,6 +619,17 @@ config CHARGER_MT6360 Average Input Current Regulation, Battery Temperature Sensing, Over-Temperature Protection, DPDM Detection for BC1.2. +config CHARGER_MT6370 + tristate "Mediatek MT6370 Charger Driver" + depends on MFD_MT6370 + depends on REGULATOR + select LINEAR_RANGES + help + Say Y here to enable MT6370 Charger Part. + The device supports High-Accuracy Voltage/Current Regulation, + Average Input Current Regulation, Battery Temperature Sensing, + Over-Temperature Protection, DPDM Detection for BC1.2. + config CHARGER_QCOM_SMBB tristate "Qualcomm Switch-Mode Battery Charger and Boost" depends on MFD_SPMI_PMIC || COMPILE_TEST diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 7f02f36aea55..8c9527643c86 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o +obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c new file mode 100644 index 000000000000..1cfa4deeb28e --- /dev/null +++ b/drivers/power/supply/mt6370-charger.c @@ -0,0 +1,1132 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_CHG_CTRL1 0x111 +#define MT6370_REG_CHG_CTRL2 0x112 +#define MT6370_REG_CHG_CTRL3 0x113 +#define MT6370_REG_CHG_CTRL4 0x114 +#define MT6370_REG_CHG_CTRL5 0x115 +#define MT6370_REG_CHG_CTRL6 0x116 +#define MT6370_REG_CHG_CTRL7 0x117 +#define MT6370_REG_CHG_CTRL8 0x118 +#define MT6370_REG_CHG_CTRL9 0x119 +#define MT6370_REG_CHG_CTRL10 0x11A +#define MT6370_REG_DEVICE_TYPE 0x122 +#define MT6370_REG_USB_STATUS1 0x127 +#define MT6370_REG_CHG_STAT 0x14A +#define MT6370_REG_FLED_EN 0x17E +#define MT6370_REG_CHG_STAT1 0X1D0 +#define MT6370_REG_OVPCTRL_STAT 0x1D8 + +#define MT6370_VOBST_MASK GENMASK(7, 2) +#define MT6370_OTG_PIN_EN_MASK BIT(1) +#define MT6370_OPA_MODE_MASK BIT(0) +#define MT6370_OTG_OC_MASK GENMASK(2, 0) + +#define MT6370_MIVR_IBUS_TH 100000 /* 100 mA */ + +enum mt6370_chg_reg_field { + /* MT6370_REG_CHG_CTRL2 */ + F_IINLMTSEL, F_CFO_EN, F_CHG_EN, + /* MT6370_REG_CHG_CTRL3 */ + F_IAICR, F_AICR_EN, F_ILIM_EN, + /* MT6370_REG_CHG_CTRL4 */ + F_VOREG, + /* MT6370_REG_CHG_CTRL5 */ + F_VOBST, + /* MT6370_REG_CHG_CTRL6 */ + F_VMIVR, + /* MT6370_REG_CHG_CTRL7 */ + F_ICHG, + /* MT6370_REG_CHG_CTRL8 */ + F_IPREC, + /* MT6370_REG_CHG_CTRL9 */ + F_IEOC, + /* MT6370_REG_DEVICE_TYPE */ + F_USBCHGEN, + /* MT6370_REG_USB_STATUS1 */ + F_USB_STAT, F_CHGDET, + /* MT6370_REG_CHG_STAT */ + F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL, + /* MT6370_REG_FLED_EN */ + F_FL_STROBE, + /* MT6370_REG_CHG_STAT1 */ + F_CHG_MIVR_STAT, + /* MT6370_REG_OVPCTRL_STAT */ + F_UVP_D_STAT, + F_MAX, +}; + +struct mt6370_priv { + struct device *dev; + struct iio_channel *iio_adcs; + struct mutex attach_lock; + struct power_supply *psy; + struct power_supply_desc *psy_desc; + struct regmap *regmap; + struct regmap_field *rmap_fields[F_MAX]; + struct regulator_dev *rdev; + struct workqueue_struct *wq; + struct work_struct bc12_work; + struct delayed_work mivr_dwork; + atomic_t attach; + int psy_usb_type; + bool pwr_rdy; +}; + +enum mt6370_usb_status { + MT6370_USB_STAT_NO_VBUS = 0, + MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING, + MT6370_USB_STAT_SDP, + MT6370_USB_STAT_SDP_NSTD, + MT6370_USB_STAT_DCP, + MT6370_USB_STAT_CDP, + MT6370_USB_STAT_MAX, +}; + +struct mt6370_chg_range { + u32 min; + u32 max; + u16 step; + u8 offset; + const u32 *table; + u16 num_table; + bool round_up; +}; + +struct mt6370_chg_field { + const char *name; + const struct mt6370_chg_range *range; + struct reg_field field; +}; + +static const u32 mt6370_chg_otg_oc_ma[] = { + 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000, +}; + +#define MT6370_CHG_RANGE(_min, _max, _step, _offset, _ru) \ +{ \ + .min = _min, \ + .max = _max, \ + .step = _step, \ + .offset = _offset, \ + .round_up = _ru, \ +} + +#define MT6370_CHG_RANGE_T(_table, _ru) \ +{ \ + .table = _table, \ + .num_table = ARRAY_SIZE(_table), \ + .round_up = _ru, \ +} + +static const struct mt6370_chg_range mt6370_chg_ranges[F_MAX] = { + [F_IAICR] = MT6370_CHG_RANGE(100, 3250, 50, 0, false), + [F_VOREG] = MT6370_CHG_RANGE(3900, 4710, 10, 0, false), + [F_VOBST] = MT6370_CHG_RANGE(4425, 5825, 25, 0, false), + [F_VMIVR] = MT6370_CHG_RANGE(3900, 13400, 100, 0, true), + [F_ICHG] = MT6370_CHG_RANGE(900, 5000, 100, 8, false), + [F_IPREC] = MT6370_CHG_RANGE(100, 850, 50, 0, false), + [F_IEOC] = MT6370_CHG_RANGE(100, 850, 50, 0, false), +}; + +#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb, _range) \ +[_fd] = { \ + .name = #_fd, \ + .range = _range ? &mt6370_chg_ranges[_fd] : NULL, \ + .field = REG_FIELD(_reg, _lsb, _msb), \ +} + +#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb) \ + MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb, (_msb > _lsb)) + +static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = { + MT6370_CHG_FIELD_RANGE(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3, false), + MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1), + MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0), + MT6370_CHG_FIELD(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7), + MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1), + MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0), + MT6370_CHG_FIELD(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7), + MT6370_CHG_FIELD(F_VOBST, MT6370_REG_CHG_CTRL5, 2, 7), + MT6370_CHG_FIELD(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7), + MT6370_CHG_FIELD(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7), + MT6370_CHG_FIELD(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3), + MT6370_CHG_FIELD(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7), + MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7), + MT6370_CHG_FIELD_RANGE(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6, false), + MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3), + MT6370_CHG_FIELD_RANGE(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7, false), + MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3), + MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5), + MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2), + MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6), + MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4), +}; + +static inline u32 mt6370_chg_val_to_reg(const struct mt6370_chg_range *range, + u32 val) +{ + int i; + u8 reg; + + if (!range) + return val; + + if (range->table) { + if (val <= range->table[0]) + return 0; + + for (i = 1; i < range->num_table - 1; i++) { + if (val == range->table[i]) + return i; + if (val > range->table[i] && + val < range->table[i + 1]) + return range->round_up ? i + 1 : i; + } + + return range->num_table - 1; + } + + if (val <= range->min) + reg = 0; + else if (val >= range->max) + reg = (range->max - range->min) / range->step; + else if (range->round_up) + reg = DIV_ROUND_UP(val - range->min, range->step); + else + reg = (val - range->min) / range->step; + + return reg + range->offset; +} + +static inline u32 mt6370_chg_reg_to_val(const struct mt6370_chg_range *range, + u8 reg) +{ + if (!range) + return reg; + + return range->table ? range->table[reg] : + range->min + range->step * (reg - range->offset); +} + +static inline int mt6370_chg_field_get(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, u32 *val) +{ + int ret; + u32 reg_val; + + ret = regmap_field_read(priv->rmap_fields[fd], ®_val); + if (ret < 0) + return ret; + + *val = mt6370_chg_reg_to_val(mt6370_chg_fields[fd].range, reg_val); + + return 0; +} + +static inline int mt6370_chg_field_set(struct mt6370_priv *priv, + enum mt6370_chg_reg_field fd, u32 val) +{ + val = mt6370_chg_val_to_reg(mt6370_chg_fields[fd].range, val); + + return regmap_field_write(priv->rmap_fields[fd], val); +} + +enum { + MT6370_CHG_STAT_READY = 0, + MT6370_CHG_STAT_CHARGE_IN_PROGRESS, + MT6370_CHG_STAT_DONE, + MT6370_CHG_STAT_FAULT, + MT6370_CHG_STAT_MAX, +}; + +enum { + MT6370_ATTACH_STAT_DETACH = 0, + MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE, + MT6370_ATTACH_STAT_ATTACH_BC12_DONE, + MT6370_ATTACH_STAT_ATTACH_MAX, +}; + +static int mt6370_chg_otg_of_parse_cb(struct device_node *of, + const struct regulator_desc *rdesc, + struct regulator_config *rcfg) +{ + struct mt6370_priv *priv = rcfg->driver_data; + unsigned int val; + int ret = 0; + + rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of), + "enable", 0, + GPIOD_OUT_LOW | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + rdesc->name); + if (IS_ERR(rcfg->ena_gpiod)) { + dev_err(priv->dev, "Failed to requeset OTG EN Pin\n"); + rcfg->ena_gpiod = NULL; + } else { + val = MT6370_OPA_MODE_MASK | MT6370_OTG_PIN_EN_MASK; + ret = regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1, + val, val); + if (ret) + dev_err(priv->dev, "Failed to set otg bits\n"); + } + + return ret; +} + +static void mt6370_chg_bc12_work_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + bc12_work); + int ret, attach; + bool rpt_psy = false; + u32 usb_stat; + + mutex_lock(&priv->attach_lock); + attach = atomic_read(&priv->attach); + + switch (attach) { + case MT6370_ATTACH_STAT_DETACH: + usb_stat = 0; + break; + case MT6370_ATTACH_STAT_ATTACH_BC12_DONE: + ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat); + if (ret < 0) { + dev_err(priv->dev, "Failed to get USB status\n"); + goto bc12_work_func_out; + } + break; + case MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE: + ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach); + if (ret < 0) + dev_err(priv->dev, "Failed to enable USB CHG EN\n"); + goto bc12_work_func_out; + default: + dev_err(priv->dev, "Invalid attach state\n"); + goto bc12_work_func_out; + } + + rpt_psy = true; + + switch (usb_stat) { + case MT6370_USB_STAT_SDP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case MT6370_USB_STAT_SDP_NSTD: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6370_USB_STAT_DCP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB_DCP; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6370_USB_STAT_CDP: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB_CDP; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; + break; + case MT6370_USB_STAT_NO_VBUS: + case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING: + default: + priv->psy_desc->type = POWER_SUPPLY_TYPE_USB; + priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + break; + } + +bc12_work_func_out: + mutex_unlock(&priv->attach_lock); + + if (rpt_psy) + power_supply_changed(priv->psy); +} + +static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv, + const char *irq_name, bool en) +{ + int irq_num; + struct platform_device *pdev = to_platform_device(priv->dev); + + irq_num = platform_get_irq_byname(pdev, irq_name); + + if (irq_num < 0) { + dev_err(priv->dev, "Failed to get platform resource\n"); + } else { + if (en) + enable_irq(irq_num); + else + disable_irq_nosync(irq_num); + } +} + +static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv) +{ + int ret; + u32 fl_strobe; + + /* check if flash led in strobe mode */ + ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe); + if (ret < 0) { + dev_err(priv->dev, "Failed to get FL_STROBE_EN\n"); + goto toggle_cfo_exit; + } + + if (fl_strobe) { + dev_err(priv->dev, "Flash led is still in strobe mode\n"); + goto toggle_cfo_exit; + } + + /* cfo off */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 0); + if (ret < 0) { + dev_err(priv->dev, "Failed to disable CFO_EN\n"); + goto toggle_cfo_exit; + } + + /* cfo on */ + ret = mt6370_chg_field_set(priv, F_CFO_EN, 1); + if (ret < 0) { + dev_err(priv->dev, "Failed to enable CFO_EN\n"); + goto toggle_cfo_exit; + } + +toggle_cfo_exit: + return ret; +} + +static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan, + int *val) +{ + int ret; + + if (chan >= MT6370_CHAN_MAX) + return -EINVAL; + + ret = iio_read_channel_processed(&priv->iio_adcs[chan], val); + if (ret) + dev_err(priv->dev, "Failed to read adc\n"); + + return ret; +} + +static void mt6370_chg_mivr_dwork_func(struct work_struct *work) +{ + struct mt6370_priv *priv = container_of(work, struct mt6370_priv, + mivr_dwork.work); + int ret; + u32 mivr_stat; + unsigned int ibus; + + ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat); + if (ret < 0) { + dev_err(priv->dev, "Failed to get mivr state\n"); + goto mivr_handler_out; + } + + if (!mivr_stat) + goto mivr_handler_out; + + ret = mt6370_chg_read_adc_chan(priv, MT6370_CHAN_IBUS, &ibus); + if (ret) { + dev_err(priv->dev, "Failed to get ibus\n"); + goto mivr_handler_out; + } + + if (ibus < MT6370_MIVR_IBUS_TH) { + ret = mt6370_chg_toggle_cfo(priv); + if (ret) + dev_err(priv->dev, "Failed to toggle cfo\n"); + } + +mivr_handler_out: + mt6370_chg_enable_irq(priv, "mivr", true); + pm_relax(priv->dev); +} + +static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv) +{ + int ret; + u32 pwr_rdy, otg_en; + union power_supply_propval val; + + /* Check in otg mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret < 0) { + dev_err(priv->dev, "Failed to get otg state\n"); + return; + } + + if (otg_en) + return; + + ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &pwr_rdy); + if (ret < 0) { + dev_err(priv->dev, "Failed to get pwr_rdy state reg\n"); + return; + } + + val.intval = !pwr_rdy; + + ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE, + &val); + if (ret) + dev_err(priv->dev, "Failed to start attach/detach flow\n"); +} + +static int mt6370_chg_get_online(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + mutex_lock(&priv->attach_lock); + val->intval = !!atomic_read(&priv->attach); + mutex_unlock(&priv->attach_lock); + + return 0; +} + +static int mt6370_chg_get_status(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int ret; + u32 chg_stat; + + ret = mt6370_chg_get_online(priv, val); + if (!val->intval) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret < 0) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_FAULT: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case MT6370_CHG_STAT_DONE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + + return ret; +} + +static int mt6370_chg_get_charge_type(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + int type, ret; + u32 chg_stat, vbat_lvl; + + ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat); + if (ret < 0) + return ret; + + ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl); + if (ret < 0) + return ret; + + switch (chg_stat) { + case MT6370_CHG_STAT_CHARGE_IN_PROGRESS: + if (vbat_lvl) + type = POWER_SUPPLY_CHARGE_TYPE_FAST; + else + type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MT6370_CHG_STAT_READY: + case MT6370_CHG_STAT_DONE: + case MT6370_CHG_STAT_FAULT: + default: + type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + + val->intval = type; + + return 0; +} + +static int mt6370_chg_get_ichg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_ICHG, &val->intval); +} + +static int mt6370_chg_get_max_ichg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_ranges[F_ICHG].max; +} + +static int mt6370_chg_get_cv(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_VOREG, &val->intval); +} + +static int mt6370_chg_get_max_cv(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_ranges[F_VOREG].max; +} + +static int mt6370_chg_get_aicr(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IAICR, &val->intval); +} + +static int mt6370_chg_get_mivr(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_VMIVR, &val->intval); +} + +static int mt6370_chg_get_iprechg(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IPREC, &val->intval); +} + +static int mt6370_chg_get_ieoc(struct mt6370_priv *priv, + union power_supply_propval *val) +{ + return mt6370_chg_field_get(priv, F_IEOC, &val->intval); +} + +static int mt6370_chg_set_online(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + int attach; + u32 pwr_rdy = !!val->intval; + + mutex_lock(&priv->attach_lock); + attach = atomic_read(&priv->attach); + if (pwr_rdy == !!attach) { + dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy); + mutex_unlock(&priv->attach_lock); + return 0; + } + + atomic_set(&priv->attach, pwr_rdy); + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return 0; + +} + +static int mt6370_chg_set_ichg(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_ICHG, val->intval); +} + +static int mt6370_chg_set_cv(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_VOREG, val->intval); +} + +static int mt6370_chg_set_aicr(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IAICR, val->intval); +} + +static int mt6370_chg_set_mivr(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_VMIVR, val->intval); +} + +static int mt6370_chg_set_iprechg(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IPREC, val->intval); +} + +static int mt6370_chg_set_ieoc(struct mt6370_priv *priv, + const union power_supply_propval *val) +{ + return mt6370_chg_field_set(priv, F_IEOC, val->intval); +} + +static int mt6370_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6370_chg_get_online(priv, val); + break; + case POWER_SUPPLY_PROP_STATUS: + ret = mt6370_chg_get_status(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = mt6370_chg_get_charge_type(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6370_chg_get_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = mt6370_chg_get_max_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6370_chg_get_cv(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + ret = mt6370_chg_get_max_cv(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6370_chg_get_aicr(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6370_chg_get_mivr(priv, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6370_chg_get_iprechg(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6370_chg_get_ieoc(priv, val); + break; + case POWER_SUPPLY_PROP_TYPE: + val->intval = priv->psy_desc->type; + break; + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = priv->psy_usb_type; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int mt6370_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct mt6370_priv *priv = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6370_chg_set_online(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6370_chg_set_ichg(priv, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6370_chg_set_cv(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6370_chg_set_aicr(priv, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6370_chg_set_mivr(priv, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6370_chg_set_iprechg(priv, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6370_chg_set_ieoc(priv, val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int mt6370_chg_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return 1; + default: + return 0; + } +} + +static enum power_supply_property mt6370_chg_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_USB_TYPE, +}; + +static enum power_supply_usb_type mt6370_chg_usb_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_DCP, +}; + +static struct power_supply_desc mt6370_chg_psy_desc = { + .type = POWER_SUPPLY_TYPE_USB, + .properties = mt6370_chg_properties, + .num_properties = ARRAY_SIZE(mt6370_chg_properties), + .get_property = mt6370_chg_get_property, + .set_property = mt6370_chg_set_property, + .property_is_writeable = mt6370_chg_property_is_writeable, + .usb_types = mt6370_chg_usb_types, + .num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types), +}; + +static const struct regulator_ops mt6370_chg_otg_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, +}; + +static const struct regulator_desc mt6370_chg_otg_rdesc = { + .of_match = "mt6370,otg-vbus", + .of_parse_cb = mt6370_chg_otg_of_parse_cb, + .name = "mt6370,otg-vbus", + .ops = &mt6370_chg_otg_ops, + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .min_uV = 4425000, + .uV_step = 25000, + .n_voltages = 57, + .vsel_reg = MT6370_REG_CHG_CTRL5, + .vsel_mask = MT6370_VOBST_MASK, + .enable_reg = MT6370_REG_CHG_CTRL1, + .enable_mask = MT6370_OPA_MODE_MASK, + .curr_table = mt6370_chg_otg_oc_ma, + .n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma), + .csel_reg = MT6370_REG_CHG_CTRL10, + .csel_mask = MT6370_OTG_OC_MASK, +}; + +static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv) +{ + int i; + const struct mt6370_chg_field *fds = mt6370_chg_fields; + + for (i = 0; i < F_MAX; i++) { + priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev, + priv->regmap, + fds[i].field); + if (IS_ERR(priv->rmap_fields[i])) { + dev_err(priv->dev, + "Failed to allocate regmap field [%s]\n", + fds[i].name); + return PTR_ERR(priv->rmap_fields[i]); + } + } + + return 0; +} + +static int mt6370_chg_init_setting(struct mt6370_priv *priv) +{ + int ret; + + priv->wq = create_singlethread_workqueue(dev_name(priv->dev)); + if (IS_ERR(priv->wq)) { + dev_err(priv->dev, "Failed to create workqueue\n"); + return PTR_ERR(priv->wq); + } + + INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func); + INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func); + mutex_init(&priv->attach_lock); + atomic_set(&priv->attach, 0); + + /* Disable usb_chg_en */ + ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0); + if (ret < 0) { + dev_err(priv->dev, "Failed to disable usb_chg_en\n"); + return ret; + } + + /* ICHG/IEOC Workaroud, ICHG can not be set less than 900mA */ + ret = mt6370_chg_field_set(priv, F_ICHG, 900); + if (ret < 0) { + dev_err(priv->dev, "Failed to set ICHG to 900mA"); + return ret; + } + + /* Change input current limit selection to using IAICR results */ + ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3); + if (ret < 0) { + dev_err(priv->dev, "Failed to set IINLMTSEL\n"); + return ret; + } + + return 0; +} + +#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field) \ +{ \ + .name = "mediatek,chg-" #_name, \ + .type = MT6370_PARSE_TYPE_##_type, \ + .fd = _field, \ +} + +static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv) +{ + struct regulator_config rcfg = { + .dev = priv->dev, + .regmap = priv->regmap, + .driver_data = priv, + }; + + priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc, + &rcfg); + + return IS_ERR(priv->rdev) ? PTR_ERR(priv->rdev) : 0; +} + +static int mt6370_chg_init_psy(struct mt6370_priv *priv) +{ + struct power_supply_config cfg = { + .drv_data = priv, + .of_node = priv->dev->of_node, + }; + + priv->psy_desc = &mt6370_chg_psy_desc; + priv->psy_desc->name = dev_name(priv->dev); + priv->psy = devm_power_supply_register(priv->dev, priv->psy_desc, &cfg); + + return IS_ERR(priv->psy) ? PTR_ERR(priv->psy) : 0; +} + +static irqreturn_t mt6370_attach_i_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + u32 otg_en; + int ret; + + /* Check in otg mode or not */ + ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en); + if (ret < 0) { + dev_err(priv->dev, "failed to get otg state\n"); + return IRQ_HANDLED; + } + + if (otg_en) + return IRQ_HANDLED; + + mutex_lock(&priv->attach_lock); + atomic_set(&priv->attach, MT6370_ATTACH_STAT_ATTACH_BC12_DONE); + mutex_unlock(&priv->attach_lock); + + if (!queue_work(priv->wq, &priv->bc12_work)) + dev_err(priv->dev, "bc12 work has already queued\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + mt6370_chg_pwr_rdy_check(priv); + + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_mivr_handler(int irq, void *data) +{ + struct mt6370_priv *priv = data; + + pm_stay_awake(priv->dev); + mt6370_chg_enable_irq(priv, "mivr", false); + schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200)); + + return IRQ_HANDLED; +} + +#define MT6370_CHG_IRQ(_name) \ +{ \ + .name = #_name, \ + .handler = mt6370_##_name##_handler, \ +} + +static int mt6370_chg_init_irq(struct mt6370_priv *priv) +{ + int i, ret; + const struct { + char *name; + irq_handler_t handler; + } mt6370_chg_irqs[] = { + MT6370_CHG_IRQ(attach_i), + MT6370_CHG_IRQ(uvp_d_evt), + MT6370_CHG_IRQ(mivr), + }; + + for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) { + ret = platform_get_irq_byname(to_platform_device(priv->dev), + mt6370_chg_irqs[i].name); + if (ret < 0) { + dev_err(priv->dev, "Failed to get irq %s\n", + mt6370_chg_irqs[i].name); + return ret; + } + + ret = devm_request_threaded_irq(priv->dev, ret, NULL, + mt6370_chg_irqs[i].handler, + IRQF_TRIGGER_FALLING, + dev_name(priv->dev), + priv); + + if (ret < 0) { + dev_err(priv->dev, "Failed to request irq %s\n", + mt6370_chg_irqs[i].name); + return ret; + } + } + + return 0; +} + +static int mt6370_chg_probe(struct platform_device *pdev) +{ + int ret; + struct mt6370_priv *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + ret = mt6370_chg_init_rmap_fields(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init regmap fields\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + priv->iio_adcs = devm_iio_channel_get_all(priv->dev); + if (IS_ERR(priv->iio_adcs)) { + dev_err(&pdev->dev, "Failed to get iio adc\n"); + return PTR_ERR(priv->iio_adcs); + } + + ret = mt6370_chg_init_otg_regulator(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init otg regulator\n"); + return ret; + } + + ret = mt6370_chg_init_psy(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init psy\n"); + return ret; + } + + ret = mt6370_chg_init_setting(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init mt6370 private data\n"); + goto probe_out; + } + + ret = mt6370_chg_init_irq(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to init irq\n"); + goto probe_out; + } + + mt6370_chg_pwr_rdy_check(priv); + + return 0; + +probe_out: + destroy_workqueue(priv->wq); + mutex_destroy(&priv->attach_lock); + + return ret; +} + +static int mt6370_chg_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + if (priv) { + mt6370_chg_enable_irq(priv, "mivr", false); + cancel_delayed_work_sync(&priv->mivr_dwork); + destroy_workqueue(priv->wq); + mutex_destroy(&priv->attach_lock); + } + + return 0; +} + +static const struct of_device_id mt6370_chg_of_match[] = { + { .compatible = "mediatek,mt6370-charger", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_chg_of_match); + +static struct platform_driver mt6370_chg_driver = { + .probe = mt6370_chg_probe, + .remove = mt6370_chg_remove, + .driver = { + .name = "mt6370-charger", + .of_match_table = of_match_ptr(mt6370_chg_of_match), + }, +}; +module_platform_driver(mt6370_chg_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("Mediatek MT6370 Charger Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:28:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577992 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B07FBC4332F for ; Tue, 31 May 2022 10:30:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343509AbiEaKaY (ORCPT ); Tue, 31 May 2022 06:30:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343490AbiEaKaV (ORCPT ); Tue, 31 May 2022 06:30:21 -0400 Received: from mail-pf1-x42a.google.com (mail-pf1-x42a.google.com [IPv6:2607:f8b0:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 343BF9AE72; Tue, 31 May 2022 03:30:17 -0700 (PDT) Received: by mail-pf1-x42a.google.com with SMTP id g205so1685567pfb.11; Tue, 31 May 2022 03:30:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6XRfvkGn1CSxkqOOGSIlgNisWraQte9YHtsokeaF/pA=; b=Isl8cNgNtXnC9yVrQrRCcosFog8v9Z1554c/GSXzk+0o5Nbd0bODgFBLJ0xOa557Re KSbx06VBp90yJjAzMJSXZnV7KO3tVn9nS8DXIsc2oFHLeqAo0O5z15I4UMNCdTz3cMFp oG4qmIch96gIqjJ28HNvbcyPyjGeag2e2XxAyQqj0vDDUu8arqkLfXW9qyvrZ9Y7nLdk ZtB3kNRqYSf+kzSCy/d8R2CSoVInuL0qFid5PTlIdFlH3RJrgXLCQXTzDfBMmyg0jQjq 93HQDqQBxCTVVFEMcvKIYYiidBur/JynhFEeIQ2OD/F84oz+vA1SZI2yCq09USuad7f4 irRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6XRfvkGn1CSxkqOOGSIlgNisWraQte9YHtsokeaF/pA=; b=WeuVlp32h6re0BbIuTwhIXoC9Lc63Sf6ehyLitgAyvDNBPqNSaTSXRmj74IWXyBGir BHuh7N+0mn7bFgptC0N6FNqPdSzOHLtr7gUSVRnr0MXKHgIcYQpzb59lSlGiupdO8YDP 0z1uN4juQpU4y2RqGLAyj8EELppcFNfdrOTZ8GXvBIUe05lLm+43svz5a4+LQ5w4rSq8 iMmbFknEWO42W75O146TX1oTiYZx/kvLMW+PwxSzvfoAAOQC/QpR8pY8S8wqUeJz36TU zEG3EW6qiAT2ZQkuPNYhuKdFudY9Lj1dTzlDvV3Oei1MVGAX1zmHibKwmFCMkPq/ENoA Bs6A== X-Gm-Message-State: AOAM5335w2kngMYkBokiqVyxthfV69Z+5gkJrfGJzUUOq6TLrCWEQ8IR +N+hRFBWwiBYPDf+TC9P5hY= X-Google-Smtp-Source: ABdhPJxA0tZQm1WKUWGPau8i7PGdOLi48eD1RSr8oMF4Gc0KSi7KMTNRRGG9UXIUBcbz+4pAzJFQtg== X-Received: by 2002:a05:6a00:1a55:b0:518:a189:8f7e with SMTP id h21-20020a056a001a5500b00518a1898f7emr41836682pfv.48.1653993016477; Tue, 31 May 2022 03:30:16 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:30:16 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 06/14] leds: mt6370: Add Mediatek MT6370 Indicator support Date: Tue, 31 May 2022 18:28:01 +0800 Message-Id: <20220531102809.11976-7-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Alice Chen Add Mediatek MT6370 Indicator support Signed-off-by: Alice Chen --- drivers/leds/Kconfig | 11 + drivers/leds/Makefile | 1 + drivers/leds/leds-mt6370.c | 994 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1006 insertions(+) create mode 100644 drivers/leds/leds-mt6370.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6090e647daee..0cb2294b3431 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -244,6 +244,17 @@ config LEDS_MT6323 This option enables support for on-chip LED drivers found on Mediatek MT6323 PMIC. +config LEDS_MT6370_RGB + tristate "LED Support for Mediatek MT6370 PMIC" + depends on LEDS_CLASS + depends on MFD_MT6370 + select LINEAR_RANGE + help + Support 4 channels and reg/pwm/breath mode. + Isink4 can also use as a CHG_VIN power good Indicator. + Say Y here to enable support for + MT6370_RGB_LED device. + config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e58ecb36360f..b641fd83f49a 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o +obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o diff --git a/drivers/leds/leds-mt6370.c b/drivers/leds/leds-mt6370.c new file mode 100644 index 000000000000..54f654d4f4fc --- /dev/null +++ b/drivers/leds/leds-mt6370.c @@ -0,0 +1,994 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MT6370_LED_ISNK1 = 0, + MT6370_LED_ISNK2, + MT6370_LED_ISNK3, + MT6370_LED_ISNK4, + MT6370_MAX_LEDS +}; + +enum mt6370_led_mode { + MT6370_LED_PWM_MODE = 0, + MT6370_LED_BREATH_MODE, + MT6370_LED_REG_MODE, + MT6370_LED_MAX_MODE +}; + +enum mt6370_led_field { + F_RGB_EN = 0, + F_CHGIND_EN, + F_LED1_CURR, + F_LED2_CURR, + F_LED3_CURR, + F_LED4_CURR, + F_LED1_MODE, + F_LED2_MODE, + F_LED3_MODE, + F_LED4_MODE, + F_LED1_DUTY, + F_LED2_DUTY, + F_LED3_DUTY, + F_LED4_DUTY, + F_LED1_FREQ, + F_LED2_FREQ, + F_LED3_FREQ, + F_LED4_FREQ, + F_MAX_FIELDS +}; + +enum mt6370_led_ranges { + R_LED123_CURR = 0, + R_LED4_CURR, + R_LED_TRFON, + R_LED_TOFF, + R_MAX_RANGES, +}; + +enum mt6370_pattern { + P_LED_TR1 = 0, + P_LED_TR2, + P_LED_TF1, + P_LED_TF2, + P_LED_TON, + P_LED_TOFF, + P_MAX_PATTERNS +}; + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_RGB1_DIM 0x182 +#define MT6370_REG_RGB2_DIM 0x183 +#define MT6370_REG_RGB3_DIM 0x184 +#define MT6370_REG_RGB_EN 0x185 +#define MT6370_REG_RGB1_ISNK 0x186 +#define MT6370_REG_RGB2_ISNK 0x187 +#define MT6370_REG_RGB3_ISNK 0x188 +#define MT6370_REG_RGB1_TR 0x189 +#define MT6370_REG_RGB_CHRIND_DIM 0x192 +#define MT6370_REG_RGB_CHRIND_CTRL 0x193 +#define MT6370_REG_RGB_CHRIND_TR 0x194 + +#define MT6372_REG_RGB_EN 0x182 +#define MT6372_REG_RGB1_ISNK 0x183 +#define MT6372_REG_RGB2_ISNK 0x184 +#define MT6372_REG_RGB3_ISNK 0x185 +#define MT6372_REG_RGB4_ISNK 0x186 +#define MT6372_REG_RGB1_DIM 0x187 +#define MT6372_REG_RGB2_DIM 0x188 +#define MT6372_REG_RGB3_DIM 0x189 +#define MT6372_REG_RGB4_DIM 0x18A +#define MT6372_REG_RGB12_FREQ 0x18B +#define MT6372_REG_RGB34_FREQ 0x18C +#define MT6372_REG_RGB1_TR 0x18D + +#define MT6370_VENID_MASK GENMASK(7, 4) +#define MT6370_CHEN_BIT(id) BIT(MT6370_LED_ISNK4 - id) +#define MT6370_VIRTUAL_MULTICOLOR 5 +#define MC_CHANNEL_NUM 3 +#define MT6370_PWM_DUTY 31 +#define MT6372_PMW_DUTY 255 + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +struct mt6370_led { + union { + struct led_classdev isink; + struct led_classdev_mc mc; + }; + struct mt6370_priv *priv; + u32 default_state; + u32 index; +}; + +struct mt6370_priv { + struct mutex lock; + struct device *dev; + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + const struct reg_field *reg_fields; + const struct linear_range *ranges; + struct reg_cfg *reg_cfgs; + unsigned int leds_count; + unsigned int leds_active; + bool is_mt6372; + struct mt6370_led leds[]; +}; + +static const struct reg_field common_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6370_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7), + [F_LED1_CURR] = REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2), + [F_LED2_CURR] = REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2), + [F_LED3_CURR] = REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2), + [F_LED4_CURR] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1), + [F_LED1_MODE] = REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6), + [F_LED2_MODE] = REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6), + [F_LED3_MODE] = REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6), + [F_LED4_MODE] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6), + [F_LED1_DUTY] = REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4), + [F_LED2_DUTY] = REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4), + [F_LED3_DUTY] = REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4), + [F_LED4_DUTY] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4), + [F_LED1_FREQ] = REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5), + [F_LED2_FREQ] = REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5), + [F_LED3_FREQ] = REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5), + [F_LED4_FREQ] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4) +}; + +static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6372_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6372_REG_RGB_EN, 3, 3), + [F_LED1_CURR] = REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3), + [F_LED2_CURR] = REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3), + [F_LED3_CURR] = REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3), + [F_LED4_CURR] = REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3), + [F_LED1_MODE] = REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7), + [F_LED2_MODE] = REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7), + [F_LED3_MODE] = REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7), + [F_LED4_MODE] = REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7), + [F_LED1_DUTY] = REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7), + [F_LED2_DUTY] = REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7), + [F_LED3_DUTY] = REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7), + [F_LED4_DUTY] = REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7), + [F_LED1_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7), + [F_LED2_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4), + [F_LED3_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7), + [F_LED4_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4) +}; + +/* Current unit: microamp, time unit: millisecond */ +static const struct linear_range common_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 4000, 1, 6, 4000 }, + [R_LED4_CURR] = { 2000, 1, 3, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 200 }, + [R_LED_TOFF] = { 250, 0, 15, 400 } +}; + +static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 2000, 1, 14, 2000 }, + [R_LED4_CURR] = { 2000, 1, 14, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 250 }, + [R_LED_TOFF] = { 250, 0, 15, 500 } +}; + +static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no) +{ + switch (led_no) { + case MT6370_LED_ISNK1: + return F_LED1_CURR; + case MT6370_LED_ISNK2: + return F_LED2_CURR; + case MT6370_LED_ISNK3: + return F_LED3_CURR; + default: + return F_LED4_CURR; + } +} + +static int mt6370_set_led_brightness(struct mt6370_priv *priv, + unsigned int led_no, unsigned int level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_write(priv->fields[sel_field], level); +} + +static int mt6370_get_led_brightness(struct mt6370_priv *priv, + unsigned int led_no, unsigned int *level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_read(priv->fields[sel_field], level); +} + +static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no, + unsigned int ton, unsigned int toff) +{ + enum mt6370_led_field sel_field; + unsigned int divisor, ratio; + + divisor = priv->is_mt6372 ? MT6372_PMW_DUTY : MT6370_PWM_DUTY; + ratio = ton * divisor / (ton + toff); + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_DUTY; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_DUTY; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_DUTY; + break; + default: + sel_field = F_LED4_DUTY; + } + + return regmap_field_write(priv->fields[sel_field], ratio); +} + +static const unsigned int common_tfreqs[] = { + 10000, 5000, 2000, 1000, 500, 200, 5, 1 +}; + +static const unsigned int mt6372_tfreqs[] = { + 8000, 4000, 2000, 1000, 500, 250, 8, 4 +}; + +static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no, + unsigned int ton, unsigned int toff) +{ + enum mt6370_led_field sel_field; + const unsigned int *tfreq; + unsigned int tfreq_len, tsum; + int i; + + if (priv->is_mt6372) { + tfreq = mt6372_tfreqs; + tfreq_len = ARRAY_SIZE(mt6372_tfreqs); + } else { + tfreq = common_tfreqs; + tfreq_len = ARRAY_SIZE(common_tfreqs); + } + + tsum = ton + toff; + + if (tsum > tfreq[0] || tsum < tfreq[tfreq_len - 1]) + return -EOPNOTSUPP; + + for (i = 0; i < tfreq_len; i++) { + if (tsum >= tfreq[i]) + break; + } + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_FREQ; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_FREQ; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_FREQ; + break; + default: + sel_field = F_LED4_FREQ; + } + + return regmap_field_write(priv->fields[sel_field], i); +} + +static void mt6370_get_breath_reg_base(struct mt6370_priv *priv, + unsigned int led_no, unsigned int *base) +{ + if (priv->is_mt6372) { + *base = MT6372_REG_RGB1_TR + led_no * 3; + return; + } + + switch (led_no) { + case MT6370_LED_ISNK1: + case MT6370_LED_ISNK2: + case MT6370_LED_ISNK3: + *base = MT6370_REG_RGB1_TR + led_no * 3; + break; + default: + *base = MT6370_REG_RGB_CHRIND_TR; + } +} + +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv, + struct led_pattern *pattern, u32 len, + u8 *pattern_val, u32 val_len) +{ + enum mt6370_led_ranges sel_range; + struct led_pattern *curr; + unsigned int sel; + u8 val[P_MAX_PATTERNS / 2] = {0}; + int i; + + if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2) + return -EINVAL; + + /* + * Pattern list + * tr1: byte 0, b'[7: 4] + * tr2: byte 0, b'[3: 0] + * tf1: byte 1, b'[7: 4] + * tf2: byte 1, b'[3: 0] + * ton: byte 2, b'[7: 4] + * toff: byte 2, b'[3: 0] + */ + for (i = 0; i < P_MAX_PATTERNS; i++) { + curr = pattern + i; + + sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON; + + linear_range_get_selector_within(priv->ranges + sel_range, + curr->delta_t, &sel); + + val[i / 2] |= sel << (4 * ((i + 1) % 2)); + } + + memcpy(pattern_val, val, 3); + return 0; +} + +static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no, + enum mt6370_led_mode mode) +{ + enum mt6370_led_field sel_field; + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_MODE; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_MODE; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_MODE; + break; + default: + sel_field = F_LED4_MODE; + } + + return regmap_field_write(priv->fields[sel_field], mode); +} + +static int mt6370_mc_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + led_mc_calc_color_components(mccdev, level); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + u32 brightness; + + subled = mccdev->subled_info + i; + brightness = min(subled->brightness, lcdev->max_brightness); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + if (level == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_REG_MODE); + if (ret) + goto out; + + continue; + } + + if (brightness == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + continue; + } + + enable |= MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_brightness(priv, subled->channel, + brightness); + if (ret) + goto out; + } + + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_blink_set(struct led_classdev *lcdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_duty(priv, subled->channel, *delay_on, + *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_freq(priv, subled->channel, *delay_on, + *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_PWM_MODE); + if (ret) + goto out; + } + + /* Toggle to make pattern timing the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_pattern_set(struct led_classdev *lcdev, + struct led_pattern *pattern, u32 len, int repeat) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int reg_base, enable, disable; + u8 params[P_MAX_PATTERNS / 2]; + int i, ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, + sizeof(params)); + if (ret) + goto out; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + mt6370_get_breath_reg_base(priv, subled->channel, ®_base); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = regmap_raw_write(priv->regmap, reg_base, params, + sizeof(params)); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_BREATH_MODE); + if (ret) + goto out; + } + + /* Toggle to make pattern timing be the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + int i, ret = 0; + + mutex_lock(&led->priv->lock); + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + ret = mt6370_set_led_mode(priv, subled->channel, + MT6370_LED_REG_MODE); + if (ret) + break; + } + + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_isnk_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int enable; + int ret; + + mutex_lock(&priv->lock); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out; + + if (level == LED_OFF) { + enable &= ~MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_mode(priv, led->index, + MT6370_LED_REG_MODE); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + } else { + enable |= MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_brightness(priv, led->index, level); + if (ret) + goto out; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + } + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_blink_set(struct led_classdev *lcdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_pattern_set(struct led_classdev *lcdev, + struct led_pattern *pattern, u32 len, + int repeat) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int reg_base; + u8 params[P_MAX_PATTERNS / 2]; + int ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, + sizeof(params)); + if (ret) + goto out; + + mt6370_get_breath_reg_base(priv, led->index, ®_base); + + ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); + if (ret) + goto out; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE); + +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&led->priv->lock); + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_init_led_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev; + struct fwnode_handle *child; + enum mt6370_led_ranges sel_range; + u32 max_uA, max_level; + const char * const states[] = { "off", "keep", "on" }; + const char *stat_str; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) { + struct mc_subled *sub_led; + u32 num_color = 0; + + sub_led = devm_kzalloc(priv->dev, + sizeof(*sub_led) * MC_CHANNEL_NUM, + GFP_KERNEL); + if (!sub_led) + return -ENOMEM; + + fwnode_for_each_child_node(init_data->fwnode, child) { + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg > MT6370_LED_ISNK3 || + priv->leds_active & BIT(reg)) + return -EINVAL; + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + dev_err(priv->dev, + "led %d, no color specified\n", + led->index); + return ret; + } + + priv->leds_active |= BIT(reg); + sub_led[num_color].color_index = color; + sub_led[num_color].channel = reg; + num_color++; + } + + if (num_color < 2) { + dev_err(priv->dev, + "Multicolor must include 2 or more led channel\n"); + return -EINVAL; + } + + led->mc.num_colors = num_color; + led->mc.subled_info = sub_led; + + lcdev = &led->mc.led_cdev; + lcdev->brightness_set_blocking = mt6370_mc_brightness_set; + lcdev->blink_set = mt6370_mc_blink_set; + lcdev->pattern_set = mt6370_mc_pattern_set; + lcdev->pattern_clear = mt6370_mc_pattern_clear; + } else { + lcdev = &led->isink; + lcdev->brightness_set_blocking = mt6370_isnk_brightness_set; + lcdev->blink_set = mt6370_isnk_blink_set; + lcdev->pattern_set = mt6370_isnk_pattern_set; + lcdev->pattern_clear = mt6370_isnk_pattern_clear; + } + + ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", + &max_uA); + if (ret) { + dev_warn(priv->dev, + "Not specified led-max-microamp, config to the minimum\n"); + max_uA = 0; + } + + if (led->index == MT6370_LED_ISNK4) + sel_range = R_LED4_CURR; + else + sel_range = R_LED123_CURR; + + linear_range_get_selector_within(priv->ranges + sel_range, max_uA, + &max_level); + + lcdev->max_brightness = max_level; + + fwnode_property_read_string(init_data->fwnode, "linux,default-trigger", + &lcdev->default_trigger); + + if (!fwnode_property_read_string(init_data->fwnode, "default-state", + &stat_str)) { + ret = match_string(states, ARRAY_SIZE(states), stat_str); + if (ret < 0) + ret = STATE_OFF; + + led->default_state = ret; + } + + return 0; +} + +static int mt6370_isnk_init_default_state(struct mt6370_led *led) +{ + struct mt6370_priv *priv = led->priv; + unsigned int enable, level; + int ret; + + ret = mt6370_get_led_brightness(priv, led->index, &level); + if (ret) + return ret; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + return ret; + + if (!(enable & MT6370_CHEN_BIT(led->index))) + level = LED_OFF; + + switch (led->default_state) { + case STATE_ON: + led->isink.brightness = led->isink.max_brightness; + break; + case STATE_KEEP: + led->isink.brightness = min(level, led->isink.max_brightness); + break; + default: + led->isink.brightness = LED_OFF; + } + + return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness); +} + +static int mt6370_led_register(struct device *parent, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) { + ret = mt6370_mc_brightness_set(&led->mc.led_cdev, LED_OFF); + if (ret) { + dev_err(parent, "Couldn't set multicolor brightness\n"); + return ret; + } + + ret = devm_led_classdev_multicolor_register_ext(parent, + &led->mc, + init_data); + if (ret) { + dev_err(parent, "Couldn't register multicolor\n"); + return ret; + } + } else { + if (led->index == MT6370_LED_ISNK4) { + ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1); + if (ret) { + dev_err(parent, "Failed to set CHRIND to SW\n"); + return ret; + } + } + + ret = mt6370_isnk_init_default_state(led); + if (ret) { + dev_err(parent, "Failed to init %d isnk state\n", + led->index); + return ret; + } + + ret = devm_led_classdev_register_ext(parent, &led->isink, + init_data); + if (ret) { + dev_err(parent, "Couldn't register isink %d\n", + led->index); + return ret; + } + } + + return 0; +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + unsigned int devinfo, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENID_MASK, devinfo); + if (vid == 0x9 || vid == 0xb) { + priv->reg_fields = mt6372_reg_fields; + priv->ranges = mt6372_led_ranges; + priv->is_mt6372 = true; + } else { + priv->reg_fields = common_reg_fields; + priv->ranges = common_led_ranges; + } + + return 0; +} + +static int mt6370_leds_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(&pdev->dev); + if (!count || count > MT6370_MAX_LEDS) { + dev_err(&pdev->dev, + "No child node or node count over max led number %zu\n", + count); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, leds, count), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + priv->dev = &pdev->dev; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + ret = devm_regmap_field_bulk_alloc(&pdev->dev, priv->regmap, + priv->fields, priv->reg_fields, + F_MAX_FIELDS); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate regmap field\n"); + return ret; + } + + device_for_each_child_node(&pdev->dev, child) { + struct mt6370_led *led = priv->leds + i++; + struct led_init_data init_data = { .fwnode = child, }; + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + dev_err(&pdev->dev, "Failed to parse reg property\n"); + return ret; + } + + if (reg >= MT6370_MAX_LEDS) { + dev_err(&pdev->dev, "Error reg property number\n"); + return -EINVAL; + } + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + dev_err(&pdev->dev, "Failed to parse color property\n"); + return ret; + } + + if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI) + reg = MT6370_VIRTUAL_MULTICOLOR; + + if (priv->leds_active & BIT(reg)) { + dev_err(&pdev->dev, "Duplicat reg property\n"); + return -EINVAL; + } + + priv->leds_active |= BIT(reg); + + led->index = reg; + led->priv = priv; + + ret = mt6370_init_led_properties(led, &init_data); + if (ret) + return ret; + + ret = mt6370_led_register(&pdev->dev, led, &init_data); + if (ret) + return ret; + } + + return 0; +} + +static const struct of_device_id mt6370_rgbled_device_table[] = { + { .compatible = "mediatek,mt6370-indicator", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table); + +static struct platform_driver mt6370_rgbled_driver = { + .driver = { + .name = "mt6370-indicator", + .of_match_table = mt6370_rgbled_device_table, + }, + .probe = mt6370_leds_probe, +}; +module_platform_driver(mt6370_rgbled_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_DESCRIPTION("Mediatek MT6370 RGB Led Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:28:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C8CFC433F5 for ; Tue, 31 May 2022 10:30:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343550AbiEaKaq (ORCPT ); Tue, 31 May 2022 06:30:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46106 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343522AbiEaKao (ORCPT ); Tue, 31 May 2022 06:30:44 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 81B149AE62; Tue, 31 May 2022 03:30:24 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id n10so13321796pjh.5; Tue, 31 May 2022 03:30:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BSdr8+r5Ds9gs2IXE1+eZosXCCxyKF7WbPPTygW5JnM=; b=i3eFbSo2a0aFLyNEvR84KXzrLVU5b4Yx1YjPdSUsSX+Lt6/a0KndN+MTcqFmORxYAk +qvOlV90XbEtVzZ3BxSnZxxw9lCYeBoHPaunOXruU4Qhd/JXdLHnmmU5AW6YVky9IbJx qBlD5xpJXHN9mSU222yrWPjdwjIuxHyBUl70qGZfMx7n5IBDhylndZyH8XGNPhpNdzXZ q1ApslHRagKMguTcRVQl/X3UKei4OPxgQcZNTd1gIwi7t3YmjkV0Cd4KGf30cl3Kq6i7 2D2y25d7F6i0MzQ0q9YxBU70uOCD6fBA9dl0lKtjhhMPOlruV+gPQp0Ev4BLGkY9mQo7 8qBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BSdr8+r5Ds9gs2IXE1+eZosXCCxyKF7WbPPTygW5JnM=; b=QidyDATocjqHA9K28bg/+07Dqk7hFOf+EPFm04vl/9ZaQ3vnRbm/lVMiwU7FZ5d9Hp Y/j2HnjbAR0fhnAGcCQjJtw1xdKbIchXfBroIEUbPBHNwPszj92jw8IwROhiAqVnfNsn lRNuzYFEtZAgsgitypFkXzwxpDyBj5jTuAM8Zq7pU2wROHJbS95Yfn90pfWvMvxVW/eN xTm8mYl7uleGhAP2UX+GHHemQanaZGCsmv7gmLF4z+Xdw6A8I8Vz6qZI4sxt6qHYrx9T txEG7Hr9J3jePEkS0ApqdHUHE6iVzlu9E2oLeJoMPsUR1OmtlJxYItCJX35O5fKs/suu nirA== X-Gm-Message-State: AOAM533Lk4TzPGVpOIEv86p31rtMUKRhJDMLQqzvNEXj6w1bvzvwU+KP W+MttpWdQGLmMx5A6hWO9VI= X-Google-Smtp-Source: ABdhPJz3PrUNeYaD7uQmj3die0vgxP2W59LuZ3x2ik/ogplORvtHo9pzIJO5eSykieLnMY08DD2NzQ== X-Received: by 2002:a17:902:d491:b0:163:e9cf:7d03 with SMTP id c17-20020a170902d49100b00163e9cf7d03mr7281869plg.162.1653993024141; Tue, 31 May 2022 03:30:24 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:30:23 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 07/14] leds: flashlight: mt6370: Add Mediatek MT6370 flashlight support Date: Tue, 31 May 2022 18:28:02 +0800 Message-Id: <20220531102809.11976-8-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Alice Chen Add Mediatek MT6370 flashlight support Signed-off-by: Alice Chen --- drivers/leds/flash/Kconfig | 9 + drivers/leds/flash/Makefile | 1 + drivers/leds/flash/leds-mt6370-flash.c | 665 +++++++++++++++++++++++++ 3 files changed, 675 insertions(+) create mode 100644 drivers/leds/flash/leds-mt6370-flash.c diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index d3eb689b193c..d38e263aaf09 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -90,4 +90,13 @@ config LEDS_SGM3140 This option enables support for the SGM3140 500mA Buck/Boost Charge Pump LED Driver. +config LEDS_MT6370_FLASHLIGHT + tristate "Flash LED Support for Mediatek MT6370 PMIC" + depends on LEDS_CLASS + depends on MFD_MT6370 + help + Support 2 channels and torch/strobe mode. + Say Y here to enable support for + MT6370_FLASH_LED device. + endif # LEDS_CLASS_FLASH diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile index 0acbddc0b91b..4c4c1710f506 100644 --- a/drivers/leds/flash/Makefile +++ b/drivers/leds/flash/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT) += leds-mt6370-flash.o diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c new file mode 100644 index 000000000000..8f6796aae3e1 --- /dev/null +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +enum { + MT6370_LED_FLASH1, + MT6370_LED_FLASH2, + MT6370_MAX_LEDS +}; + +/* Virtual definition for multicolor */ + +#define MT6370_REG_FLEDEN 0x17E +#define MT6370_REG_STRBTO 0x173 +#define MT6370_REG_CHGSTAT2 0x1D1 +#define MT6370_REG_FLEDSTAT1 0x1D9 +#define MT6370_REG_FLEDISTRB(_id) (0x174 + 4 * _id) +#define MT6370_REG_FLEDITOR(_id) (0x175 + 4 * _id) +#define MT6370_ITORCH_MASK GENMASK(4, 0) +#define MT6370_ISTROBE_MASK GENMASK(6, 0) +#define MT6370_STRBTO_MASK GENMASK(6, 0) +#define MT6370_TORCHEN_MASK BIT(3) +#define MT6370_STROBEN_MASK BIT(2) +#define MT6370_FLCSEN_MASK(_id) BIT(MT6370_LED_FLASH2 - _id) +#define MT6370_FLCSEN_MASK_ALL (BIT(0) | BIT(1)) +#define MT6370_FLEDCHGVINOVP_MASK BIT(3) +#define MT6370_FLED1STRBTO_MASK BIT(11) +#define MT6370_FLED2STRBTO_MASK BIT(10) +#define MT6370_FLED1STRB_MASK BIT(9) +#define MT6370_FLED2STRB_MASK BIT(8) +#define MT6370_FLED1SHORT_MASK BIT(7) +#define MT6370_FLED2SHORT_MASK BIT(6) +#define MT6370_FLEDLVF_MASK BIT(3) + +#define MT6370_LED_JOINT 2 +#define MT6370_RANGE_FLED_REG 4 +#define MT6370_ITORCH_MINUA 25000 +#define MT6370_ITORCH_STEPUA 12500 +#define MT6370_ITORCH_MAXUA 400000 +#define MT6370_ITORCH_DOUBLE_MAXUA 800000 +#define MT6370_ISTRB_MINUA 50000 +#define MT6370_ISTRB_STEPUA 12500 +#define MT6370_ISTRB_MAXUA 1500000 +#define MT6370_ISTRB_DOUBLE_MAXUA 3000000 +#define MT6370_STRBTO_MINUS 64000 +#define MT6370_STRBTO_STEPUS 32000 +#define MT6370_STRBTO_MAXUS 2432000 + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +struct mt6370_led { + struct led_classdev_flash flash; + struct v4l2_flash *v4l2_flash; + struct mt6370_priv *priv; + u32 led_no; + u32 default_state; +}; + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct mutex lock; + unsigned int fled_strobe_used; + unsigned int fled_torch_used; + unsigned int leds_active; + unsigned int leds_count; + struct mt6370_led leds[]; +}; + +static int mt6370_torch_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = + container_of(lcdev, struct mt6370_led, flash.led_cdev); + struct mt6370_priv *priv = led->priv; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask; + u32 val = level ? led_enable_mask : 0; + u32 prev = priv->fled_torch_used, curr; + int ret, i; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid strobe is currently used. + */ + if (priv->fled_strobe_used) { + dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", + priv->fled_strobe_used); + ret = -EBUSY; + goto unlock; + } + + if (level) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_TORCHEN_MASK; + + + if (level) { + level -= 1; + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = level / 2; + flevel[1] = level - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(i), + MT6370_ITORCH_MASK, flevel[i]); + if (ret) + goto unlock; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDITOR(led->led_no), + MT6370_ITORCH_MASK, level); + if (ret) + goto unlock; + } + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, + enable_mask, val); + if (ret) + goto unlock; + + priv->fled_torch_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, + u32 brightness) +{ + /* + * Due to the current spike when turning on flash, + * let brightness to be kept by framework. + * This empty function is used to + * prevent led_classdev_flash register ops check failure. + */ + return 0; +} + +static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, + u32 brightness) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 val = (brightness - s->min) / s->step; + int ret, i; + + if (led->led_no == MT6370_LED_JOINT) { + int flevel[MT6370_MAX_LEDS]; + + flevel[0] = val / 2; + flevel[1] = val - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(i), + MT6370_ISTROBE_MASK, flevel[i]); + if (ret) + return ret; + } + } else { + ret = regmap_update_bits(priv->regmap, + MT6370_REG_FLEDISTRB(led->led_no), + MT6370_ISTROBE_MASK, val); + if (ret) + return ret; + } + return ret; +} + +static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + flash); + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev = &fl_cdev->led_cdev; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ? + MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask; + u32 val = state ? led_enable_mask : 0; + u32 prev = priv->fled_strobe_used, curr; + int ret; + + mutex_lock(&priv->lock); + + /* + * Only one set of flash control logic, + * use the flag to avoid torch is currently used + */ + if (priv->fled_torch_used) { + dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", + priv->fled_torch_used); + ret = -EBUSY; + goto unlock; + } + + if (state) + curr = prev | BIT(led->led_no); + else + curr = prev & ~BIT(led->led_no); + + if (curr) + val |= MT6370_STROBEN_MASK; + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, + val); + if (ret) { + dev_err(lcdev->dev, "[%d] control current source %d fail\n", + led->led_no, state); + goto unlock; + } + + /* + * If the flash need to be on, + * config the flash current ramping up to the setting value + * Else, always recover back to the minimum one + */ + ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min); + if (ret) + goto unlock; + + /* + * For the flash turn on/off, HW rampping up/down time is 5ms/500us, + * respectively + */ + if (!prev && curr) + usleep_range(5000, 6000); + else if (prev && !curr) + udelay(500); + + priv->fled_strobe_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + flash); + struct mt6370_priv *priv = led->priv; + + mutex_lock(&priv->lock); + *state = !!(priv->fled_strobe_used & BIT(led->led_no)); + mutex_unlock(&priv->lock); + + return 0; +} + +static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->timeout; + u32 val = (timeout - s->min) / s->step; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO, + MT6370_STRBTO_MASK, val); + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) +{ + struct mt6370_led *led = container_of(fl_cdev, struct mt6370_led, + flash); + struct mt6370_priv *priv = led->priv; + u16 fled_stat; + unsigned int chg_stat, strobe_timeout_mask, fled_short_mask; + u32 rfault = 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat); + if (ret) + goto unlock; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat, + sizeof(fled_stat)); + if (ret) + goto unlock; + + switch (led->led_no) { + case MT6370_LED_FLASH1: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK; + break; + + case MT6370_LED_FLASH2: + strobe_timeout_mask = MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED2SHORT_MASK; + break; + + case MT6370_LED_JOINT: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK | + MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK | + MT6370_FLED2SHORT_MASK; + } + + if (chg_stat & MT6370_FLEDCHGVINOVP_MASK) + rfault |= LED_FAULT_INPUT_VOLTAGE; + + if (fled_stat & strobe_timeout_mask) + rfault |= LED_FAULT_TIMEOUT; + + if (fled_stat & fled_short_mask) + rfault |= LED_FAULT_SHORT_CIRCUIT; + + if (fled_stat & MT6370_FLEDLVF_MASK) + rfault |= LED_FAULT_UNDER_VOLTAGE; + + *fault = rfault; +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct led_flash_ops mt6370_flash_ops = { + .flash_brightness_set = mt6370_flash_brightness_set, + .strobe_set = mt6370_strobe_set, + .strobe_get = mt6370_strobe_get, + .timeout_set = mt6370_timeout_set, + .fault_get = mt6370_fault_get, +}; + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, + bool enable) +{ + struct led_classdev_flash *flash = v4l2_flash->fled_cdev; + struct mt6370_led *led = container_of(flash, struct mt6370_led, flash); + struct mt6370_priv *priv = led->priv; + u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 val = enable ? mask : 0; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val); + if (ret) + goto unlock; + + if (enable) + priv->fled_strobe_used |= BIT(led->led_no); + else + priv->fled_strobe_used &= ~BIT(led->led_no); + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct v4l2_flash_ops v4l2_flash_ops = { + .external_strobe_set = mt6370_flash_external_strobe_set, +}; + +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, + struct v4l2_flash_config *config) +{ + struct led_classdev *lcdev; + struct led_flash_setting *s = &config->intensity; + + lcdev = &led->flash.led_cdev; + + s->min = MT6370_ITORCH_MINUA; + s->step = MT6370_ITORCH_STEPUA; + s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step; + + config->has_external_strobe = 1; + strscpy(config->dev_name, lcdev->dev->kobj.name, + sizeof(config->dev_name)); + + config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT | + LED_FAULT_INPUT_VOLTAGE | + LED_FAULT_UNDER_VOLTAGE; +} +#else +static const struct v4l2_flash_ops v4l2_flash_ops; +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, + struct v4l2_flash_config *config) +{ +} +#endif + +static int mt6370_led_register(struct device *parent, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct v4l2_flash_config v4l2_config = {0}; + int ret; + + ret = devm_led_classdev_flash_register_ext(parent, &led->flash, + init_data); + if (ret) { + dev_err(parent, "Couldn't register flash %d\n", led->led_no); + return ret; + } + + mt6370_init_v4l2_flash_config(led, &v4l2_config); + led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode, + &led->flash, &v4l2_flash_ops, + &v4l2_config); + if (IS_ERR(led->v4l2_flash)) { + dev_err(parent, "Failed to register %d v4l2 sd\n", led->led_no); + return PTR_ERR(led->v4l2_flash); + } + + return 0; +} + +static u32 clamp_align(u32 val, u32 min, u32 max, u32 step) +{ + u32 retval; + + retval = clamp_val(val, min, max); + if (step > 1) + retval = rounddown(retval - min, step) + min; + + return retval; +} + +static int mt6370_init_flash_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct led_classdev_flash *flash = &led->flash; + struct led_classdev *lcdev = &flash->led_cdev; + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s; + u32 sources[MT6370_MAX_LEDS]; + u32 max_uA, val; + int i, ret, num; + + num = fwnode_property_count_u32(init_data->fwnode, "led-sources"); + if (num < 1 || num > MT6370_MAX_LEDS) { + dev_err(priv->dev, + "Not specified or wrong number of led-sources\n"); + return -EINVAL; + } + + ret = fwnode_property_read_u32_array(init_data->fwnode, + "led-sources", sources, num); + if (ret) + return ret; + + for (i = 0; i < num; i++) { + if (sources[i] >= MT6370_MAX_LEDS) + return -EINVAL; + if (priv->leds_active & BIT(sources[i])) + return -EINVAL; + priv->leds_active |= BIT(sources[i]); + + } + led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT : + sources[0]; + + max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAXUA : MT6370_ITORCH_MAXUA; + ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", + &val); + if (ret) { + dev_warn(priv->dev, + "Not specified led-max-microamp, config to the minimum\n"); + val = MT6370_ITORCH_MINUA; + } else + val = clamp_align(val, MT6370_ITORCH_MINUA, max_uA, + MT6370_ITORCH_STEPUA); + + lcdev->max_brightness = (val - MT6370_ITORCH_MINUA) / + MT6370_ITORCH_STEPUA + 1; + lcdev->brightness_set_blocking = mt6370_torch_brightness_set; + lcdev->flags |= LED_DEV_CAP_FLASH; + + max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAXUA : MT6370_ISTRB_MAXUA; + ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", + &val); + if (ret) { + dev_warn(priv->dev, + "Not specified flash-max-microamp, config to the minimum\n"); + val = MT6370_ISTRB_MINUA; + } else + val = clamp_align(val, MT6370_ISTRB_MINUA, max_uA, + MT6370_ISTRB_STEPUA); + + s = &flash->brightness; + s->min = MT6370_ISTRB_MINUA; + s->step = MT6370_ISTRB_STEPUA; + s->val = s->max = val; + + /* + * Always configure as min level when off to + * prevent flash current spike + */ + ret = _mt6370_flash_brightness_set(flash, s->min); + if (ret) + return ret; + + ret = fwnode_property_read_u32(init_data->fwnode, + "flash-max-timeout-us", &val); + if (ret) { + dev_warn(priv->dev, + "Not specified flash-max-timeout-us, config to the minimum\n"); + val = MT6370_STRBTO_MINUS; + } else + val = clamp_align(val, MT6370_STRBTO_MINUS, MT6370_STRBTO_MAXUS, + MT6370_STRBTO_STEPUS); + + + s = &flash->timeout; + s->min = MT6370_STRBTO_MINUS; + s->step = MT6370_STRBTO_STEPUS; + s->val = s->max = val; + + flash->ops = &mt6370_flash_ops; + + return 0; +} + +static int mt6370_init_common_properties(struct mt6370_led *led, + struct led_init_data *init_data) +{ + const char * const states[] = { "off", "keep", "on" }; + const char *str; + int ret; + + if (!fwnode_property_read_string(init_data->fwnode, + "default-state", &str)) { + ret = match_string(states, ARRAY_SIZE(states), str); + if (ret < 0) + ret = STATE_OFF; + + led->default_state = ret; + } + + return 0; +} + +static void mt6370_v4l2_flash_release(struct mt6370_priv *priv) +{ + int i; + + for (i = 0; i < priv->leds_count; i++) { + struct mt6370_led *led = priv->leds + i; + + if (led->v4l2_flash) + v4l2_flash_release(led->v4l2_flash); + } +} + +static int mt6370_led_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(&pdev->dev); + if (!count || count > MT6370_MAX_LEDS) { + dev_err(&pdev->dev, + "No child node or node count over max led number %lu\n", count); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + priv->dev = &pdev->dev; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + device_for_each_child_node(&pdev->dev, child) { + struct mt6370_led *led = priv->leds + i; + struct led_init_data init_data = { .fwnode = child, }; + + led->priv = priv; + ret = mt6370_init_common_properties(led, &init_data); + if (ret) + goto out_flash_release; + + ret = mt6370_init_flash_properties(led, &init_data); + + if (ret) + goto out_flash_release; + + ret = mt6370_led_register(&pdev->dev, led, &init_data); + if (ret) + goto out_flash_release; + + i++; + } + + platform_set_drvdata(pdev, priv); + return 0; + +out_flash_release: + mt6370_v4l2_flash_release(priv); + return ret; +} + +static int mt6370_led_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + + mt6370_v4l2_flash_release(priv); + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_led_of_id[] = { + { .compatible = "mediatek,mt6370-flashlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_led_of_id); + +static struct platform_driver mt6370_led_driver = { + .driver = { + .name = "mt6370-flashlight", + .of_match_table = mt6370_led_of_id, + }, + .probe = mt6370_led_probe, + .remove = mt6370_led_remove, +}; +module_platform_driver(mt6370_led_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_DESCRIPTION("MT6370 FLASH LED Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:28:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577991 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5BF7EC43219 for ; Tue, 31 May 2022 10:31:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343548AbiEaKax (ORCPT ); Tue, 31 May 2022 06:30:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46276 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343543AbiEaKaq (ORCPT ); Tue, 31 May 2022 06:30:46 -0400 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 486249C2CB; Tue, 31 May 2022 03:30:33 -0700 (PDT) Received: by mail-pj1-x1029.google.com with SMTP id v11-20020a17090a4ecb00b001e2c5b837ccso2173468pjl.3; Tue, 31 May 2022 03:30:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gSHJ8cU7Tk4Hdo/isRqfWUjlGNskb5R2AVQxrPbbCvI=; b=SAX5OgGshyh0S7Q0P1G5oGCltp30E0lVS7VMHwVSGtJzobus0r+DSq4HZ9dVlccA// L7FsL/3Cc/4VWO1fCCTnIRfxF9dICs905OFUIaS8polL5LqvFba4ii/xGg5A3euqE/Gq hqwWt5bT8r53Ff+88JekCF8hEVqQz1OgUeKgug2ZTSS6z60EkuT3MgEBIhfMwptDimft m4KcPqMyGtnWFp1V1hFwZGTEHb0zBUzVFVKHmXVfjw0rT3dtM8EjbCEoeF7OaEyWl9uU bj8y9S3JytkJe6N7OsX3ScPNoaGUFC1mnMmYbbtgAa7FApCvVo6PwK0fou3Ruyx1w2eR zeig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gSHJ8cU7Tk4Hdo/isRqfWUjlGNskb5R2AVQxrPbbCvI=; b=QQNkx7JCM4Q4UE4ah7KI11HkcNfjag2EGKFtWi2YQ0mVp9I2wyVOwCWfPtrZ4rjTYg xVZU8TkzuhkeRMzxOWevQUZeq1bE4ajEK1e4MdTWeovPiZYgzYNfHCN4V7H21Wdj3BRp UtCCQ4Jx4ntnkqilMUgo8K0O6E6NjYFGOcvr+6J4wz5/CaOO77LLROD1UAu1cuhHE3hO syeoYKSIV7nDrr43mycD5v9BPesI81R1HERMLU5Kye/niUQYZlLg3eU/W1miFRwiimma BtrYNmW2C4VqXv9EnRUjBtzIVAdVzt8ONYfoY+TMcXZlsdq15cGUJa1OVR5BYLrpL0WK iwyA== X-Gm-Message-State: AOAM533iMdeuUhFXq1lG+WpyaEJGyUmbHGvCamLIQLlzdypQl9BLP4P2 fUTr4iqZ//UKe24fvobnClg= X-Google-Smtp-Source: ABdhPJxeJjnsS/OG2s2o/PBurv6FPum5YkGzaAOy+mj8Ht/7zT6NftWz5GABkl7zQzsb3ERmo9fwcA== X-Received: by 2002:a17:90a:a085:b0:1e0:97ee:c263 with SMTP id r5-20020a17090aa08500b001e097eec263mr27994149pjp.110.1653993032769; Tue, 31 May 2022 03:30:32 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:30:32 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 08/14] video: backlight: mt6370: Add Mediatek MT6370 support Date: Tue, 31 May 2022 18:28:03 +0800 Message-Id: <20220531102809.11976-9-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 Backlight support. Signed-off-by: ChiaEn Wu --- drivers/video/backlight/Kconfig | 8 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/mt6370-backlight.c | 338 +++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 drivers/video/backlight/mt6370-backlight.c diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a003e02e13ce..d9868fbe7488 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -268,6 +268,14 @@ config BACKLIGHT_MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. +config BACKLIGHT_MT6370 + tristate "Mediatek MT6370 Backlight Driver" + depends on MFD_MT6370 + help + Say Y here to enable MT6370 Backlight support. + It's commonly used to drive the display WLED. There're 4 channels + inisde, and each channel can provide up to 30mA current. + config BACKLIGHT_APPLE tristate "Apple Backlight Driver" depends on X86 && ACPI diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index cae2c83422ae..e815f3f1deff 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o +obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c new file mode 100644 index 000000000000..f8a8d33203ed --- /dev/null +++ b/drivers/video/backlight/mt6370-backlight.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_BL_EN 0x1A0 +#define MT6370_REG_BL_BSTCTRL 0x1A1 +#define MT6370_REG_BL_PWM 0x1A2 +#define MT6370_REG_BL_DIM2 0x1A4 + +#define MT6370_VENID_MASK GENMASK(7, 4) +#define MT6370_BL_EXT_EN_MASK BIT(7) +#define MT6370_BL_EN_MASK BIT(6) +#define MT6370_BL_CONFIG_MASK BIT(0) +#define MT6370_BL_CH_MASK GENMASK(5, 2) +#define MT6370_BL_DIM2_MASK GENMASK(2, 0) +#define MT6370_BL_DUMMY_6372_MASK GENMASK(2, 0) +#define MT6370_BL_DIM2_6372_SHIFT 3 +#define MT6370_BL_PWM_EN_MASK BIT(7) +#define MT6370_BL_PWM_HYS_EN_MASK BIT(2) +#define MT6370_BL_PWM_HYS_SEL_MASK GENMASK(1, 0) +#define MT6370_BL_OVP_EN_MASK BIT(7) +#define MT6370_BL_OVP_SEL_MASK GENMASK(6, 5) +#define MT6370_BL_OC_EN_MASK BIT(3) +#define MT6370_BL_OC_SEL_MASK GENMASK(2, 1) + +#define MT6370_BL_MAX_BRIGHTNESS 2048 + +enum { + MT6370_VID_COMMON = 0, + MT6370_VID_6372, + MT6370_VID_MAX, +}; + +enum mt6370_prop_type { + MT6370_PARSE_TYPE_BOOL = 0, + MT6370_PARSE_TYPE_U8, + MT6370_PARSE_TYPE_MAX, +}; + +struct mt6370_priv { + int vid_type; + struct backlight_device *bl; + struct device *dev; + struct gpio_desc *enable_gpio; + struct regmap *regmap; +}; + +static int mt6370_bl_update_status(struct backlight_device *bl_dev) +{ + struct mt6370_priv *priv = bl_get_data(bl_dev); + int brightness = backlight_get_brightness(bl_dev); + unsigned int enable_val; + u8 brightness_val[2]; + int ret; + + if (brightness) { + brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK; + brightness_val[1] = (brightness - 1) + >> fls(MT6370_BL_DIM2_MASK); + + if (priv->vid_type == MT6370_VID_6372) { + brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT; + brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK; + } + + ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2, + brightness_val, sizeof(brightness_val)); + if (ret) + return ret; + } + + if (priv->enable_gpio) + gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0); + + enable_val = brightness ? MT6370_BL_EN_MASK : 0; + return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, + MT6370_BL_EN_MASK, enable_val); +} + +static int mt6370_bl_get_brightness(struct backlight_device *bl_dev) +{ + struct mt6370_priv *priv = bl_get_data(bl_dev); + unsigned int enable; + u8 brightness_val[2]; + int brightness, ret; + + ret = regmap_read(priv->regmap, MT6370_REG_BL_EN, &enable); + if (ret) + return ret; + + if (!(enable & MT6370_BL_EN_MASK)) + return 0; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_BL_DIM2, + brightness_val, sizeof(brightness_val)); + if (ret) + return ret; + + if (priv->vid_type == MT6370_VID_6372) + brightness_val[0] >>= MT6370_BL_DIM2_6372_SHIFT; + + brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK); + brightness += (brightness_val[0] & MT6370_BL_DIM2_MASK); + + return brightness + 1; +} + +static const struct backlight_ops mt6370_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = mt6370_bl_update_status, + .get_brightness = mt6370_bl_get_brightness, +}; + +#define MT6370_DT_PROP_DECL(_name, _type, _reg, _mask, _max, _inv) \ +{ \ + .name = "mediatek,bled-" #_name, \ + .type = MT6370_PARSE_TYPE_##_type, \ + .reg = _reg, \ + .mask = _mask, \ + .max_val = _max, \ + .invert = _inv, \ +} + +static int mt6370_init_backlight_properties(struct mt6370_priv *priv, + struct backlight_properties *props) +{ + struct device *dev = priv->dev; + u8 prop_val; + u32 brightness; + unsigned int mask, val; + static const struct { + char *name; + enum mt6370_prop_type type; + unsigned int reg; + unsigned int mask; + u8 max_val; + bool invert; + } vendor_opt_props[] = { + MT6370_DT_PROP_DECL(pwm-enable, BOOL, MT6370_REG_BL_PWM, + MT6370_BL_PWM_EN_MASK, 1, false), + MT6370_DT_PROP_DECL(pwm-hys-enable, BOOL, MT6370_REG_BL_PWM, + MT6370_BL_PWM_HYS_EN_MASK, 1, false), + MT6370_DT_PROP_DECL(pwm-hys-sel, U8, MT6370_REG_BL_PWM, + MT6370_BL_PWM_HYS_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ovp-level-sel, U8, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OVP_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ovp-shutdown, BOOL, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OVP_EN_MASK, 1, true), + MT6370_DT_PROP_DECL(ocp-level-sel, U8, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OC_SEL_MASK, 3, false), + MT6370_DT_PROP_DECL(ocp-shutdown, BOOL, MT6370_REG_BL_BSTCTRL, + MT6370_BL_OC_EN_MASK, 1, true), + }, *prop_now; + int i, ret; + + /* vendor optional properties */ + for (i = 0; i < ARRAY_SIZE(vendor_opt_props); i++) { + prop_now = vendor_opt_props + i; + + switch (prop_now->type) { + case MT6370_PARSE_TYPE_BOOL: + if (device_property_read_bool(dev, prop_now->name)) + val = 1; + else + val = 0; + break; + case MT6370_PARSE_TYPE_U8: + ret = device_property_read_u8(dev, prop_now->name, + &prop_val); + /* Property not exist, keep value in default */ + if (ret) + continue; + + val = min_t(u8, prop_val, prop_now->max_val); + break; + default: + return -EINVAL; + } + + if (prop_now->invert) + val = prop_now->max_val - val; + + val <<= ffs(prop_now->mask) - 1; + + ret = regmap_update_bits(priv->regmap, prop_now->reg, + prop_now->mask, val); + if (ret) + return ret; + } + + /* common properties */ + ret = device_property_read_u32(dev, "max-brightness", &brightness); + if (ret) + brightness = MT6370_BL_MAX_BRIGHTNESS; + + props->max_brightness = min_t(u32, brightness, + MT6370_BL_MAX_BRIGHTNESS); + + ret = device_property_read_u32(dev, "default-brightness", &brightness); + if (ret) + brightness = props->max_brightness; + + props->brightness = min_t(u32, brightness, props->max_brightness); + + + ret = device_property_read_u8(dev, "mediatek,bled-channel-use", + &prop_val); + if (ret) { + dev_err(dev, "mediatek,bled-channel-use DT property missing\n"); + return ret; + } + + if (!prop_val) { + dev_err(dev, "No channel specified\n"); + return -EINVAL; + } + + mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK; + val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1); + + if (priv->enable_gpio) + val |= MT6370_BL_EXT_EN_MASK; + + return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + unsigned int dev_info, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENID_MASK, dev_info); + if (vid == 0x9 || vid == 0xb) + priv->vid_type = MT6370_VID_6372; + else + priv->vid_type = MT6370_VID_COMMON; + + return 0; +} + +static int mt6370_bl_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .scale = BACKLIGHT_SCALE_LINEAR, + }; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to get regmap\n"); + return -ENODEV; + } + + ret = mt6370_check_vendor_info(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to check vendor info (%d)\n", ret); + return ret; + } + + priv->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) { + dev_err(&pdev->dev, "Failed to get 'enable' gpio\n"); + return PTR_ERR(priv->enable_gpio); + } + + ret = mt6370_init_backlight_properties(priv, &props); + if (ret) { + dev_err(&pdev->dev, "Failed to init backlight properties\n"); + return ret; + } + + priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, + &pdev->dev, priv, + &mt6370_bl_ops, &props); + if (IS_ERR(priv->bl)) { + dev_err(&pdev->dev, "Failed to register backlight\n"); + return PTR_ERR(priv->bl); + } + + backlight_update_status(priv->bl); + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int mt6370_bl_remove(struct platform_device *pdev) +{ + struct mt6370_priv *priv = platform_get_drvdata(pdev); + struct backlight_device *bl_dev = priv->bl; + + bl_dev->props.brightness = 0; + backlight_update_status(priv->bl); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = { + { .compatible = "mediatek,mt6370-backlight", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_bl_of_match); + +static struct platform_driver mt6370_bl_driver = { + .driver = { + .name = "mt6370-backlight", + .of_match_table = mt6370_bl_of_match, + }, + .probe = mt6370_bl_probe, + .remove = mt6370_bl_remove, +}; +module_platform_driver(mt6370_bl_driver); + +MODULE_AUTHOR("ChiaEn Wu "); +MODULE_DESCRIPTION("Mediatek MT6370 Backlight Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Tue May 31 10:28:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577573 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0460C433F5 for ; Tue, 31 May 2022 12:07:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233781AbiEaMH0 (ORCPT ); Tue, 31 May 2022 08:07:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46322 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232790AbiEaMH0 (ORCPT ); Tue, 31 May 2022 08:07:26 -0400 Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 316A24EA2D; Tue, 31 May 2022 05:07:25 -0700 (PDT) Received: by mail-pl1-x644.google.com with SMTP id t2so5044407pld.4; Tue, 31 May 2022 05:07:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WjL5ChPbIi7K/V0MdTfM2rPQhvrdOuYsXgOFgMyivaI=; b=XUW9GdGy4TqDailNbK9B/jsEL99PnLrY7N6e/R0pDDK5Mj+ioTShKiwSiYxB9IrpFZ Mu3bFnjNhNRaCm4FfOxekdr+q7O7xZKCPbbEoseMPnqAarbIXgRmHW9h3DpetYJf7ROx Ja+9DYEYKdvr64YWdrTt4qJ11drlS3wdTSWTi7j13Ai0e/Q7DhS7yuAPTQlrJEyqP4Gk kDB08TOcStQLLZ1WkA02qea053UKUM83GOEnr0x5ERuvahMFRYEzMfEmWRCIc4LSeeS4 RBFRcPlfiABIdr9tYu6684lGowuRpNzZS7laB1vAZXldhJ6Huk82Yv+uPmFry5CRdKBf ZjSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WjL5ChPbIi7K/V0MdTfM2rPQhvrdOuYsXgOFgMyivaI=; b=mXzbOtLhdjEADiKnWrncmM7aqWioeiYEv2zChJKuGiTIqAib0sZwCbciZu32q+8zT5 VRDWkwABbI4qF4E5cW+3TrjbCT+Ob/jlCtpRMf7et1NDq/k10IVkN5TXqbDvkkbvxnfE ibGIPYm3Tz5jwRLv4Vlh3392P/8es4scVg1EBOifVQp8QiSyaqHeOguUT3DQz0L0HqrN eACwZoY6Qr087cEtCerozUySPXKILu20mbdnZYu7e7P+Mo2EYvrBbACFPgkJ2I1NgDAq fHGpNY08TGaS7T64M0WhmqwdvHJ5bOuq7hpdc2f6StbLK4QWgzxXGvrkdGQGCZdsFr3w mfNw== X-Gm-Message-State: AOAM532WVrEhNCzZdYw8pDrKKz7EgLpixm8QKFvgf8xC9rzJ+DDZHSXx Dr1BINUAXMoZ9Rb3xoJvRJdNwzBsCt8= X-Google-Smtp-Source: ABdhPJzhoIKkLqm77ivXQGmG9uiBv7avEg57jLy4emn49XKC6kCSn41nkMkpf9Cog5z8VCg8vYRfpg== X-Received: by 2002:a17:903:2310:b0:163:e054:9c0f with SMTP id d16-20020a170903231000b00163e0549c0fmr9477567plh.57.1653993044377; Tue, 31 May 2022 03:30:44 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:30:44 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 09/14] dt-bindings: usb: Add Mediatek MT6370 TCPC binding documentation Date: Tue, 31 May 2022 18:28:04 +0800 Message-Id: <20220531102809.11976-10-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add Mediatek MT6370 TCPC binding documentation. Signed-off-by: ChiYuan Huang --- .../bindings/usb/mediatek,mt6370-tcpc.yaml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml new file mode 100644 index 000000000000..49316633f92f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek MT6370 Type-C Port Switch and Power Delivery controller DT bindings + +maintainers: + - ChiYuan Huang + +description: | + Mediatek MT6370 is a multi-functional device. It integrates charger, ADC, flash, RGB indicators, + regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller. + This document only describes MT6370 Type-C Port Switch and Power Delivery controller. + +properties: + compatible: + enum: + - mediatek,mt6370-tcpc + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + description: + Properties for usb c connector. + +additionalProperties: false + +required: + - compatible + - interrupts From patchwork Tue May 31 10:28:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577985 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 29910C433EF for ; Tue, 31 May 2022 12:16:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344147AbiEaMQI (ORCPT ); Tue, 31 May 2022 08:16:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42594 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243140AbiEaMQH (ORCPT ); Tue, 31 May 2022 08:16:07 -0400 Received: from mail-qv1-xf44.google.com (mail-qv1-xf44.google.com [IPv6:2607:f8b0:4864:20::f44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B87C994C4; Tue, 31 May 2022 05:16:06 -0700 (PDT) Received: by mail-qv1-xf44.google.com with SMTP id h18so11765611qvj.11; Tue, 31 May 2022 05:16:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0sCP0jkvIeE07R1+RmlM9MygA92ez6zp1dtKYb5AvDE=; b=DM+UlGGCjjymtrinrTEP42yV6EtngTwfbFuO4RgI9RVddp2xprIV7OuizKvg7qBR4O yIiFxAwshb/oTw70/jqCpd8M2TuV0KBl489zPAW4HS5GHYOH6OuMyWh9l4U+i1CWb9wL RgN8AqpCbw+KLvXMfNKTnT+/CWROCAOo6uq8OJCg0fyxV4ZUXsaZlyER99RX44wfwpjf 3P14iT3Ut2atvcFu3hWGrzj4/iORfBfX60nHVWae2fwDsL6zle/FSBAeoO0UdB61etJK i6VtDrYTEG4JwdEnrXONYBo5IygUdxTfY31ykJ8Cb2KI+syC8Owu19/mTbYV23++OmYk Ll2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0sCP0jkvIeE07R1+RmlM9MygA92ez6zp1dtKYb5AvDE=; b=gVxM2L+mFGP5wEeIJPnX49e7U+W0/6NlvBj3TH69spKkc03dGiXTFdYXfKq7npzLZu bJgXczo/pk8PCVZY6k//0A/zscfPEtXWZaEYMi1Uo5gEeGbCNf2sOspc2eNSAVWyqeMn 8kS/pqa9xlRWLTI2HxIXkOFddGzam06EiPFLGLhlPdWmKjwpfRnRnKkcImY4A2Dl3IuO mPNo1MU/JRJCJXDf0Kr4lqXW44D/eys7OFZNRtUHyAOObT15e6p9rSu2bPfhJ82fT2E2 3WQyIotns146XN9UbCUBcHrpbVrrYDM1iGIAOt2A+acz9JLkDYqPNG1QgxaOtzFPsZ6Z mTAw== X-Gm-Message-State: AOAM530VQK1WxjWyF4OhlG81Bhh2kbyvRWYFEwCwn3XbwwuCYwwKqa9m IC+1XxboFx1ZMAg2okp4WCP2GfrRLdE= X-Google-Smtp-Source: ABdhPJxfRfYt0nV+dDr20o7LwUzTYTfaMj1alulfLmGKs8iiemw4ejZEwn2KjluWB+6QCEcQ6O5kpw== X-Received: by 2002:a62:d045:0:b0:518:404d:9dc8 with SMTP id p66-20020a62d045000000b00518404d9dc8mr59548174pfg.60.1653993053493; Tue, 31 May 2022 03:30:53 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:30:53 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 10/14] dt-bindings: power: supply: Add Mediatek MT6370 Charger binding documentation Date: Tue, 31 May 2022 18:28:05 +0800 Message-Id: <20220531102809.11976-11-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiaEn Wu Add Mediatek MT6370 Charger binding documentation. Signed-off-by: ChiaEn Wu --- .../power/supply/mediatek,mt6370-charger.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml new file mode 100644 index 000000000000..9d5c4487ca9c --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6370 Battery Charger + +maintainers: + - ChiaEn Wu + +description: | + This module is part of the MT6370 MFD device. + Provides Battery Charger, Boost for OTG devices and BC1.2 detection. + +properties: + compatible: + const: mediatek,mt6370-charger + + interrupts: + description: | + Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ + "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D" + are required. + items: + - description: BC1.2 done irq for mt6370 charger + - description: usb plug in irq for mt6370 charger + - description: mivr irq for mt6370 charger + + interrupt-names: + items: + - const: attach_i + - const: uvp_d_evt + - const: mivr + + io-channels: + description: | + Use ADC channel to read vbus, ibus, ibat, etc., info. Ibus ADC channel + is required. + + usb-otg-vbus: + type: object + description: OTG boost regulator. + $ref: /schemas/regulator/regulator.yaml# + + properties: + enable-gpio: + maxItems: 1 + description: | + Specify a valid 'enable' gpio for the regulator and it's optional + +required: + - compatible + - interrupts + - interrupt-names + - io-channels + +additionalProperties: false + +... From patchwork Tue May 31 10:28:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577572 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8BD4C43217 for ; Tue, 31 May 2022 12:15:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344121AbiEaMPT (ORCPT ); Tue, 31 May 2022 08:15:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344161AbiEaMPP (ORCPT ); Tue, 31 May 2022 08:15:15 -0400 Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BBED6994C0; Tue, 31 May 2022 05:15:13 -0700 (PDT) Received: by mail-pg1-x541.google.com with SMTP id v15so12652643pgk.11; Tue, 31 May 2022 05:15:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=NLlQWPmyPhz9LkYQh7iizThmB3DZjfxS2yfzbAOphFg=; b=I4w6+q3mrUIL109pwzpTze5IvWiG+1Sm6Q/7ihB35G4+4nU2YnPrXRziLx+TjwQPKJ 27v96U4XlLTj4qvRe1P7BgC7TeHdudGmcMfT8xhVbtoceFoPSsDrFiSspzWjKMLuZBJW NNPufZ9HklQcqk+CRGhV5CV3j//Lsh2GOI3ZrSJSChpHw4LFbutgxJNqUqN6lh3qf+xQ 3FMeYyOYJBXw4mgAWgYyBsEGP+9QcO74DD7r3ElXM/gBg5lFBlDhaRkqIxCfG86r2kGS qTg9vzWnm3t4x6/LXNTmuPN2mNUySP8cPOORTBWUclVtUSbi0DxWMAHxDg2PiIXQwtc3 IH7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NLlQWPmyPhz9LkYQh7iizThmB3DZjfxS2yfzbAOphFg=; b=Gcp6iF55zQAHt+OpeUOq4xwKnxD/IUZUe426fpOuFVp1aT1G/UZMPOyN/eTD17smnk 7gnP8MR0fUlON8NpEd+Icu0QLAEjgm22t2e1l4OBNRgne0PlIw8wZd6CpLnwNgxr2NoA vtHRKb+gRkucuC0U5oHleB+TgNtMwUUM/OMkTjGBXcVmZ6kXf1BwXx2mooo7D8+Susi6 nGLq1B0c+kbnFee12g3LJT8aW4ByU8nMsSSGgzjlUoqo4BBfM/Puh3hp83O1VtbOF9y6 yrPz8JAY6YJ0dqy06nYOAAy6phbtw++mQQ8TSyYkhjtCPzmvlqPJvFHsxGAMaxf2uD1Z K8vg== X-Gm-Message-State: AOAM530gQrbGWNk8injCAMOlB462s8jVhhVaavH1iGMWjk1cBu9bsFPu snQDhYgOmysThqOrctNFVcoeZGKhQm8= X-Google-Smtp-Source: ABdhPJyD1Fx7LBxTURdowjLzD5c7Yqcp9ob1xo5BIIaa0fHPSwQ8ngkBhpXhhcH/7b+MIEJs3XVqjw== X-Received: by 2002:a63:1009:0:b0:3fa:9996:386b with SMTP id f9-20020a631009000000b003fa9996386bmr31594847pgl.441.1653993061902; Tue, 31 May 2022 03:31:01 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.30.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:31:01 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 11/14] dt-bindings: leds: mt6370: Add Mediatek mt6370 indicator documentation Date: Tue, 31 May 2022 18:28:06 +0800 Message-Id: <20220531102809.11976-12-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add Mediatek mt6370 indicator documentation. Signed-off-by: ChiYuan Huang --- .../leds/mediatek,mt6370-indicator.yaml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml new file mode 100644 index 000000000000..823be3add097 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/mediatek,mt6370-indicator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LED driver for MT6370 PMIC from MediaTek Integrated. + +maintainers: + - Alice Chen + +description: | + This module is part of the MT6370 MFD device. + see Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml + Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode + +properties: + compatible: + const: mediatek,mt6370-indicator + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^(multi-)?led@[0-3]$": + description: | + Properties for a single LED. + $ref: common.yaml# + type: object + + properties: + reg: + description: | + Index of the LED. + enum: + - 0 # LED output ISINK1 + - 1 # LED output ISINK2 + - 2 # LED output ISINK3 + - 3 # LED output ISINK4 + + mediatek,soft-start: + description: | + soft start step control, support /0.5ms/1ms/1.5ms/2ms. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + + unevaluatedProperties: false + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Tue May 31 10:28:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577984 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F9B2C433F5 for ; Tue, 31 May 2022 12:20:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240521AbiEaMUV (ORCPT ); Tue, 31 May 2022 08:20:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232616AbiEaMUU (ORCPT ); Tue, 31 May 2022 08:20:20 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F9B3377D2; Tue, 31 May 2022 05:20:19 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id g184so12704683pgc.1; Tue, 31 May 2022 05:20:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=U7ahqBydDZnP+CjyjsQFK3suIZ5X/7W6Ul5AL8gL7a4=; b=V5itc85HJVOWLynsGAGbF1b5IIyjo0uTDnuVBTCCvpXUdjthi8sBYuyxa4mOI983QJ QRaZ23PoQwQuHk9R5/xKIoGSln9pltwe9Lb6AnFLQotGz1OZ4dGRMeT+wZp9RU2qFn0b lciRB2KdKxg4IWBsOWL2RR3ezr4cEzL5zf+aF41EqU9ySuL/2yKglUC/xzz9Xd8mMjDG 8chU43vxbt3ZkKn7/jcxCwm11FuTojBCXfq8Cr+A66YKjx++ANR8c/mpuuj/bNex/otj LeRysJHhBMTXapMxRzgaAlKfUP6g5WXMCrZvMYi5XjLOZBFPgxstIbP+1lR6a/81s6FX 1xTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=U7ahqBydDZnP+CjyjsQFK3suIZ5X/7W6Ul5AL8gL7a4=; b=SpgQMFiBu0lGYZyoHNUKlVtdR0DqacaUcQM5h1iEGulbivZKzR8dHWSYK48cqK6Fcd HKdhvXsDO5Lz4b0+MBspxlNHhKYOIxKJ3wyCjaptyyDRdUtW6R966IKGHVj+Gb1s150o s3jPQkVUaa1HimJbfZuXXSJxqh5IRkilBleNzOejAtfa/IQkjjsKg0/Jo7zbI/iovURy XRXf69TIh8i4A56wXbxfAV88T7wlweQr7oIiKT7Ly4tpg1kwMVbLOTStxI9L7ZPQR5Qb WZ1N/5RhD6d7tcnd13L8KtMOtkTypYJ9ye/MVoZfDj75YJwFfAMq3o+mpmmN+ZBo5V+U DJYw== X-Gm-Message-State: AOAM533SSx8RudZvW1QODGL0I6TN5uct8NKB8MdmKk3CyNhUo5ZHR9ZU JHfoZjCSAYVLTOlkQT0y0vn0btRvq0s= X-Google-Smtp-Source: ABdhPJzR0hOuFaR8Ft3dRJkMlyvX58IIHNvptaqVZwrijhZ0GTUJ0qsvccPRjoO36QbkdyU7o6Azrw== X-Received: by 2002:a63:6806:0:b0:3fc:3b43:52d5 with SMTP id d6-20020a636806000000b003fc3b4352d5mr4887737pgc.319.1653993071115; Tue, 31 May 2022 03:31:11 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.31.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:31:10 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 12/14] dt-bindings: leds: Add Mediatek MT6370 flashlight binding documentation Date: Tue, 31 May 2022 18:28:07 +0800 Message-Id: <20220531102809.11976-13-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Alice Chen Add Mediatek MT6370 flashlight binding documentation Signed-off-by: Alice Chen --- .../leds/mediatek,mt6370-flashlight.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml new file mode 100644 index 000000000000..b1b11bd3d410 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/leds-mt6370-flashlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Flash LED driver for MT6370 PMIC from MediaTek Integrated. + +maintainers: + - Alice Chen + +description: | + This module is part of the MT6370 MFD device. + see Documentation/devicetree/bindings/mfd/mt6370.yaml + Add MT6370 flash LED driver include 2-channel flash LED support Torch/Strobe Mode. + +properties: + compatible: + const: mediatek,mt6370-flashlight + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-1]$": + type: object + $ref: common.yaml# + description: + Properties for a single flash LED. + + properties: + reg: + description: Index of the flash LED. + enum: + - 0 #Address of LED1 + - 1 #Address of LED2 + + unevaluatedProperties: false + +required: + - compatible + - "#address-cells" + - "#size-cells" + +additionalProperties: false From patchwork Tue May 31 10:28:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaEn Wu X-Patchwork-Id: 577986 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02D8EC433EF for ; Tue, 31 May 2022 12:08:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244289AbiEaMIK (ORCPT ); Tue, 31 May 2022 08:08:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232790AbiEaMIJ (ORCPT ); Tue, 31 May 2022 08:08:09 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA11A5E145; Tue, 31 May 2022 05:08:08 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id y189so12988155pfy.10; Tue, 31 May 2022 05:08:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JSIsAVF9fVkTehhsFum2qIaOiKUkDyLxbABQD3He3l0=; b=ZU8iCU3NGySHmEgNB8okylg9eQ5lI0KHYoPEDovMwPLNuIfpUzHqoEhjpi9BJKg/bJ zAngyLyMA3z4pYX3LqBh1qxjZoM2W1GkbK9GyITchzsVUnf8ryBlQPvi1C44XzIX93zF MF8cQ1gatUVnjgAkHXhBK6VyQnvtc0BBYTuqsG4HsSquekVgAZPbaex6BWm95I+vCNUd LjS74zu8Z3pWHexb0xu12vsQhyh5emzSf79Rd/weIR9peek38k6X1HEN86n3wboMj/BC rtZjD3EKKyAAkiXsYqF/+/8SgDyKjrFZQA5r8/lBKF90Ek8uP3lISiT8XTKsg6QNKqpe VaFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=JSIsAVF9fVkTehhsFum2qIaOiKUkDyLxbABQD3He3l0=; b=uiC63rCvqHgvaDCssi7Mwqg8C0u7+DSYU+R0XimZsQCzha452JBLZNOxBFUe7xKRyc dRT4QIU7LCo/x7ZjYW3JQKlP8Q7g4Mc36oLSN1+eiCP6Pu1QZxuFAwC3mFVIs3SaFHjz diw9e48wSZDwHqnBtmHbKlz47/ilMO/sID1eUUwg0U4XWgcopCeBVIGoY1uDLxjQX7ba T0iHIJA7+sgevjxWQRXJS2FDVT/rwru4zNJNj3++GFYBaK4UKWAzhGpUOpKcXCiJow+t m1e0+0rs9XrMlYShANNYOLdTySIyFz2pvvghaB4MXv2OhF1D3135AwFnJeLeGVPZSccI Kw6Q== X-Gm-Message-State: AOAM533J6qVnQdmvLdMfF/dmS4wHitK2aDCfGKDr0O7wt1/reFBDC+aa k2mcoJMsi7zSCDZ+saHwg0xjupYPVTM= X-Google-Smtp-Source: ABdhPJyDlfCP92PgDUmyh/k1//oY0Or/x4nvlOLY8shtUR/BI5cISxpd1h8vbB3UfX7zOoEnvnEJZw== X-Received: by 2002:a05:6a00:1487:b0:518:b952:889b with SMTP id v7-20020a056a00148700b00518b952889bmr39184396pfu.43.1653993080595; Tue, 31 May 2022 03:31:20 -0700 (PDT) Received: from RD-3580-24288.rt.l (42-72-220-172.emome-ip.hinet.net. [42.72.220.172]) by smtp.gmail.com with ESMTPSA id c1-20020a63d501000000b003c14af50631sm10216519pgg.73.2022.05.31.03.31.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 03:31:20 -0700 (PDT) From: ChiaEn Wu To: lee.jones@linaro.org, daniel.thompson@linaro.org, jingoohan1@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, matthias.bgg@gmail.com, sre@kernel.org, chunfeng.yun@mediatek.com, gregkh@linuxfoundation.org, jic23@kernel.org, lars@metafoo.de, lgirdwood@gmail.com, broonie@kernel.org, linux@roeck-us.net, heikki.krogerus@linux.intel.com, deller@gmx.de Cc: cy_huang@richtek.com, alice_chen@richtek.com, chiaen_wu@richtek.com, dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-iio@vger.kernel.org, linux-fbdev@vger.kernel.org Subject: [PATCH 13/14] dt-bindings: backlight: Add Mediatek MT6370 backlight binding documentation Date: Tue, 31 May 2022 18:28:08 +0800 Message-Id: <20220531102809.11976-14-peterwu.pub@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220531102809.11976-1-peterwu.pub@gmail.com> References: <20220531102809.11976-1-peterwu.pub@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: ChiYuan Huang Add mt6370 backlight binding documentation. Signed-off-by: ChiYuan Huang --- .../backlight/mediatek,mt6370-backlight.yaml | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml new file mode 100644 index 000000000000..81d72ed44be4 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6370 Backlight + +maintainers: + - ChiaEn Wu + +description: | + MT6370 is a highly-integrated smart power management IC, which includes a + single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C & + Power Delivery (PD) controller, dual flash LED current sources, a RGB LED + driver, a backlight WLED driver, a display bias driver and a general LDO for + portable devices. + + For the LCD backlight, it can provide 4 channel WLED driving capability. + Each channel driving current is up to 30mA + +allOf: + - $ref: common.yaml# + +properties: + compatible: + const: mediatek,mt6370-backlight + + default-brightness: + minimum: 0 + maximum: 2048 + + max-brightness: + minimum: 0 + maximum: 2048 + + enable-gpios: + description: External backlight 'enable' pin + maxItems: 1 + + mediatek,bled-pwm-enable: + description: | + Enable external PWM input for backlight dimming + type: boolean + + mediatek,bled-pwm-hys-enable: + description: | + Enable the backlight input-hysteresis for PWM mode + type: boolean + + mediatek,bled-pwm-hys-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight PWM hysteresis input level selection. + value mapping: + - 0: 1bit + - 1: 2bit + - 2: 4bit + - 3: 6bit + + mediatek,bled-ovp-shutdown: + description: | + Enable the backlight shutdown when OVP level triggered + type: boolean + + mediatek,bled-ovp-level-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight OVP level selection. + value mapping: + - 0: 17V + - 1: 21V + - 2: 25V + - 3: 29V + + mediatek,bled-ocp-shutdown: + description: | + Enable the backlight shutdown when OCP level triggerred. + type: boolean + + mediatek,bled-ocp-level-sel: + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + description: | + Backlight OC level selection. + value mapping: + - 0: 900mA + - 1: 1200mA + - 2: 1500mA + - 3: 1800mA + + mediatek,bled-channel-use: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + Backlight LED channel to be used. + Each bit mapping to: + - 0: CH4 + - 1: CH3 + - 2: CH2 + - 3: CH1 + minimum: 1 + maximum: 15 + +required: + - compatible + - mediatek,bled-channel-use + +additionalProperties: false