Files
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

339 lines
8.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <mach/upmu_hw.h>
#include <upmu_common.h>
#define XO_CDAC_FPM_ADDR PMIC_XO_CDAC_FPM_ADDR
#define XO_CDAC_FPM_MASK PMIC_XO_CDAC_FPM_MASK
#define XO_CDAC_FPM_SHIFT PMIC_XO_CDAC_FPM_SHIFT
#define XO_COFST_FPM_ADDR PMIC_XO_COFST_FPM_ADDR
#define XO_COFST_FPM_MASK PMIC_XO_COFST_FPM_MASK
#define XO_COFST_FPM_SHIFT PMIC_XO_COFST_FPM_SHIFT
#define XO_CORE_IDAC_FPM_ADDR PMIC_XO_CORE_IDAC_FPM_ADDR
#define XO_CORE_IDAC_FPM_MASK PMIC_XO_CORE_IDAC_FPM_MASK
#define XO_CORE_IDAC_FPM_SHIFT PMIC_XO_CORE_IDAC_FPM_SHIFT
#define XO_AAC_FPM_SWEN_ADDR PMIC_XO_AAC_FPM_SWEN_ADDR
#define XO_AAC_FPM_SWEN_MASK PMIC_XO_AAC_FPM_SWEN_MASK
#define XO_AAC_FPM_SWEN_SHIFT PMIC_XO_AAC_FPM_SWEN_SHIFT
#define XO_CDAC_TOTAL_MASK 0xff
#define XO_CDAC_VALUE_MASK 0x7f
#define XO_CDAC_SIGN_BIT 7
#define XO_CDAC_FPM_RESET 0x88
#define XO_CDAC_FPM_DEFAULT 0x7d
struct mt6357_dcxo {
struct device *dev;
struct mutex lock;
uint32_t cur_dcxo_capid;
uint32_t ori_dcxo_capid;
uint32_t nvram_offset;
};
static const struct of_device_id mt6357_dcxo_of_match[] = {
{ .compatible = "mediatek,mt6357-dcxo", },
{ },
};
MODULE_DEVICE_TABLE(of, mt6357_dcxo_of_match);
static void dcxo_trim_write(uint32_t cap_code)
{
pmic_config_interface(XO_COFST_FPM_ADDR, 0x0, XO_COFST_FPM_MASK,
XO_COFST_FPM_SHIFT);
pmic_config_interface(XO_CDAC_FPM_ADDR, cap_code, XO_CDAC_FPM_MASK,
XO_CDAC_FPM_SHIFT);
pmic_config_interface(XO_CORE_IDAC_FPM_ADDR, 0x2, XO_CORE_IDAC_FPM_MASK,
XO_CORE_IDAC_FPM_SHIFT);
pmic_config_interface(XO_AAC_FPM_SWEN_ADDR, 0x0, XO_AAC_FPM_SWEN_MASK,
XO_AAC_FPM_SWEN_SHIFT);
mdelay(1);
pmic_config_interface(XO_AAC_FPM_SWEN_ADDR, 0x1, XO_AAC_FPM_SWEN_MASK,
XO_AAC_FPM_SWEN_SHIFT);
mdelay(5);
}
static uint32_t dcxo_trim_read(void)
{
uint32_t cap_code = 0;
pmic_read_interface(XO_CDAC_FPM_ADDR, &cap_code, XO_CDAC_FPM_MASK,
XO_CDAC_FPM_SHIFT);
return cap_code;
}
static uint32_t dcxo_capid_add_offset(uint32_t capid, uint32_t offset)
{
uint32_t capid_value;
uint32_t offset_sign, offset_value;
int32_t tmp_value;
uint32_t final_capid;
/* capid don't have sign bit, value from 0x00 to 0xFF */
capid_value = capid & XO_CDAC_TOTAL_MASK;
/* offset bit 7 is sign bit. bit7=1 means minus */
offset_sign = !!(offset & BIT(XO_CDAC_SIGN_BIT));
offset_value = offset & XO_CDAC_VALUE_MASK;
/* process plus/minus overflow */
if (offset_sign) { /* negetive offset sign, minus */
tmp_value = (int32_t)capid_value - (int32_t)offset_value;
if (tmp_value < 0)
tmp_value = 0;
final_capid = (uint32_t)tmp_value;
} else { /* positive offset sign, plus */
tmp_value = (int32_t)capid_value + (int32_t)offset_value;
if (tmp_value > XO_CDAC_TOTAL_MASK) /* value overflow */
tmp_value = XO_CDAC_TOTAL_MASK;
final_capid = (uint32_t)tmp_value;
}
return final_capid;
}
static uint32_t dcxo_capid_sub_offset(uint32_t cur_capid, uint32_t ori_capid)
{
uint32_t cur_capid_value;
uint32_t ori_capid_value;
int32_t tmp_value;
uint32_t final_offset;
cur_capid_value = cur_capid & XO_CDAC_TOTAL_MASK;
ori_capid_value = ori_capid & XO_CDAC_TOTAL_MASK;
/* process plus/minus error */
if (cur_capid_value >= ori_capid_value) {
/* offset sign bit is positive */
tmp_value = (int32_t)cur_capid_value - (int32_t)ori_capid_value;
if (tmp_value > XO_CDAC_VALUE_MASK) /* value overflow */
tmp_value = XO_CDAC_VALUE_MASK;
final_offset = (uint32_t)tmp_value;
} else {
/* offset sign bit is negative */
tmp_value = (int32_t)ori_capid_value - (int32_t)cur_capid_value;
if (tmp_value > XO_CDAC_VALUE_MASK) /* value overflow */
tmp_value = XO_CDAC_VALUE_MASK;
final_offset = BIT(XO_CDAC_SIGN_BIT) | (uint32_t)tmp_value;
}
return final_offset;
}
static ssize_t show_dcxo_capid(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint32_t capid;
capid = dcxo_trim_read();
return sprintf(buf, "dcxo capid: 0x%x\n", capid);
}
static ssize_t store_dcxo_capid(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct mt6357_dcxo *dcxo = dev_get_drvdata(dev);
uint32_t capid;
int ret;
if (buf != NULL && size != 0) {
ret = kstrtouint(buf, 0, &capid);
if (ret) {
pr_info("wrong format!\n");
return ret;
}
if (capid > XO_CDAC_TOTAL_MASK) {
pr_info("cap code should be within %x!\n",
XO_CDAC_TOTAL_MASK);
return -EINVAL;
}
pr_info("original cap code: 0x%x\n", dcxo->ori_dcxo_capid);
dcxo_trim_write(capid);
mdelay(1);
dcxo->cur_dcxo_capid = dcxo_trim_read();
pr_info("write capid 0x%x done. current capid: 0x%x\n",
capid, dcxo->cur_dcxo_capid);
}
return size;
}
static DEVICE_ATTR(dcxo_capid, 0664, show_dcxo_capid, store_dcxo_capid);
static ssize_t show_dcxo_board_offset(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mt6357_dcxo *dcxo = dev_get_drvdata(dev);
uint32_t offset;
offset = dcxo_capid_sub_offset(dcxo->cur_dcxo_capid,
dcxo->ori_dcxo_capid);
return sprintf(buf, "dcxo capid offset: 0x%x\n", offset);
}
static ssize_t store_dcxo_board_offset(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct mt6357_dcxo *dcxo = dev_get_drvdata(dev);
uint32_t offset, capid;
int ret;
if (buf != NULL && size != 0) {
ret = kstrtouint(buf, 0, &offset);
if (ret) {
pr_info("wrong format!\n");
return ret;
}
if (offset > XO_CDAC_TOTAL_MASK) {
pr_info("offset should be within %x!\n",
XO_CDAC_TOTAL_MASK);
return -EINVAL;
}
capid = dcxo->ori_dcxo_capid;
pr_info("original cap code: 0x%x\n", capid);
capid = dcxo_capid_add_offset(capid, offset);
dcxo_trim_write(capid);
mdelay(1);
dcxo->cur_dcxo_capid = dcxo_trim_read();
pr_info("write capid offset 0x%x done. current capid: 0x%x\n",
offset, dcxo->cur_dcxo_capid);
}
return size;
}
static DEVICE_ATTR(dcxo_board_offset, 0664, show_dcxo_board_offset,
store_dcxo_board_offset);
static ssize_t show_nvram_board_offset(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mt6357_dcxo *dcxo = dev_get_drvdata(dev);
/* Should not modify sprintf format. Otherwise DcxoSetCap will fail. */
return sprintf(buf, "0x%x", dcxo->nvram_offset);
}
static ssize_t store_nvram_board_offset(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct mt6357_dcxo *dcxo = dev_get_drvdata(dev);
uint32_t offset;
int ret;
if (buf != NULL && size != 0) {
ret = kstrtouint(buf, 0, &offset);
if (ret) {
pr_info("wrong format!\n");
return ret;
}
if (offset > XO_CDAC_TOTAL_MASK) {
pr_info("offset should be within %x!\n",
XO_CDAC_TOTAL_MASK);
return -EINVAL;
}
dcxo->nvram_offset = offset;
pr_info("write nvram_board_offset 0x%x\n", offset);
}
return size;
}
static DEVICE_ATTR(nvram_board_offset, 0664, show_nvram_board_offset,
store_nvram_board_offset);
static int mt_dcxo_probe(struct platform_device *pdev)
{
struct mt6357_dcxo *dcxo;
int ret;
uint32_t default_capid = 0;
dcxo = devm_kzalloc(&pdev->dev, sizeof(*dcxo), GFP_KERNEL);
if (!dcxo)
return -ENOMEM;
mutex_init(&dcxo->lock);
dcxo->dev = &pdev->dev;
platform_set_drvdata(pdev, dcxo);
ret = device_create_file(&pdev->dev, &dev_attr_dcxo_capid);
if (ret)
dev_info(&pdev->dev, "Failed to create capid file: %d\n", ret);
ret = device_create_file(&pdev->dev, &dev_attr_dcxo_board_offset);
if (ret)
dev_info(&pdev->dev, "Failed to create offset file: %d\n", ret);
ret = device_create_file(&pdev->dev, &dev_attr_nvram_board_offset);
if (ret)
dev_info(&pdev->dev, "Failed to create nvram file: %d\n", ret);
/* get original cap code */
dcxo->ori_dcxo_capid = dcxo_trim_read();
dev_info(&pdev->dev, "Original cap code: 0x%x\n", dcxo->ori_dcxo_capid);
/* get default cap code */
dcxo->ori_dcxo_capid = dcxo_trim_read();
dev_info(&pdev->dev, "Default cap code: 0x%x\n", dcxo->ori_dcxo_capid);
ret = of_property_read_u32(dcxo->dev->of_node, "default-capid",
&default_capid);
if (ret) {
dev_info(&pdev->dev,
"Failed to get default-capid from dts: %d\n", ret);
default_capid = 0;
ret = 0;
}
default_capid &= XO_CDAC_TOTAL_MASK;
dev_info(&pdev->dev, "Default dts capid: 0x%x\n", default_capid);
if (default_capid)
dcxo_trim_write(default_capid);
else
dcxo_trim_write(XO_CDAC_FPM_DEFAULT);
dcxo->cur_dcxo_capid = dcxo_trim_read();
dev_info(&pdev->dev, "Current cap code: 0x%x\n", dcxo->cur_dcxo_capid);
return ret;
}
static int mt_dcxo_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver mt_dcxo_driver = {
.remove = mt_dcxo_remove,
.probe = mt_dcxo_probe,
.driver = {
.name = "mt6357-dcxo",
.of_match_table = mt6357_dcxo_of_match,
},
};
module_platform_driver(mt_dcxo_driver);
MODULE_LICENSE("GPL");