| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (c) 2021 MediaTek Inc. |
| */ |
| #include <linux/delay.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/of.h> |
| #include <linux/of_device.h> |
| #include <linux/platform_device.h> |
| #include <linux/regmap.h> |
| #include <linux/mfd/mt6685-audclk.h> |
| |
| /* PMIC EFUSE registers definition */ |
| #define MT6685_DCXO_EXTBUF5_CW0 0x79e |
| /* offset mask of OTP_CON0 */ |
| #define XO_BBCK5_MODE_SFT 0 |
| #define XO_BBCK5_MODE_MASK 0x3 |
| #define XO_BBCK5_MODE_MSK_SFT (0x3 << 0) |
| |
| #define XO_BBCK5_EN_M_SFT 2 |
| #define XO_BBCK5_EN_M_MASK 0x1 |
| #define XO_BBCK5_EN_M_MSK_SFT (0x1 << 2) |
| |
| struct clk_chip_data { |
| unsigned int reg_num; |
| unsigned int base; |
| }; |
| |
| struct mt6685_clk { |
| struct device *dev; |
| struct regmap *regmap; |
| struct mutex lock; |
| }; |
| |
| struct mt6685_clk *clk; |
| void mt6685_set_dcxo_mode(unsigned int mode) |
| { |
| if (!clk || !clk->regmap) |
| return; |
| |
| /* set BBCK5 mode to 0 |
| * Mode: |
| * 00: Register controlled by XO_BBCK5_EN_M |
| * 01: EN_BB |
| * 10: CLK_SEL |
| */ |
| |
| regmap_update_bits(clk->regmap, MT6685_DCXO_EXTBUF5_CW0, |
| XO_BBCK5_MODE_MSK_SFT, mode << XO_BBCK5_MODE_SFT); |
| } |
| EXPORT_SYMBOL(mt6685_set_dcxo_mode); |
| |
| void mt6685_set_dcxo(bool enable) |
| { |
| if (!clk || !clk->regmap) |
| return; |
| |
| if (enable) { |
| regmap_update_bits(clk->regmap, MT6685_DCXO_EXTBUF5_CW0, |
| XO_BBCK5_EN_M_MSK_SFT, 0x1 << XO_BBCK5_EN_M_SFT); |
| usleep_range(400, 420); |
| } else { |
| regmap_update_bits(clk->regmap, MT6685_DCXO_EXTBUF5_CW0, |
| XO_BBCK5_EN_M_MSK_SFT, 0x0 << XO_BBCK5_EN_M_SFT); |
| } |
| } |
| EXPORT_SYMBOL(mt6685_set_dcxo); |
| |
| static int mt6685_audclk_probe(struct platform_device *pdev) |
| { |
| clk = devm_kzalloc(&pdev->dev, sizeof(*clk), GFP_KERNEL); |
| if (!clk) |
| return -ENOMEM; |
| clk->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
| if (!clk->regmap) { |
| dev_info(&pdev->dev, "failed to get efuse regmap\n"); |
| return -ENODEV; |
| } |
| |
| mutex_init(&clk->lock); |
| clk->dev = &pdev->dev; |
| dev_info(&pdev->dev, "%s done\n", __func__); |
| return 0; |
| } |
| static const struct clk_chip_data mt6685_audclk_data = { |
| .reg_num = 128, |
| .base = MT6685_DCXO_EXTBUF5_CW0, |
| }; |
| static const struct of_device_id mt6338_of_match[] = { |
| {.compatible = "mediatek,mt6338_snd",}, |
| {}, |
| }; |
| |
| static const struct of_device_id mt6685_audclk_of_match[] = { |
| {.compatible = "mediatek,mt6685-audclk",}, |
| {/* sentinel */}, |
| }; |
| static struct platform_driver mt6685_audclk_driver = { |
| .probe = mt6685_audclk_probe, |
| .driver = { |
| .name = "mt6685-audclk", |
| .of_match_table = mt6685_audclk_of_match, |
| }, |
| }; |
| module_platform_driver(mt6685_audclk_driver); |
| |
| MODULE_LICENSE("GPL v2"); |
| MODULE_AUTHOR("Ting-Fang Hou <ting-fang.hou@mediatek.com>"); |
| MODULE_DESCRIPTION("MediaTek PMIC AUDCLK Driver for MT6685 PMIC"); |
| |