mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
drm/rockchip: ebc: Add silergy sy7636a regulator driver
Change-Id: I76eea176a49d4a56e3f6a92c0aff5648ecbe5a4f Signed-off-by: Chaoyi Chen <chaoyi.chen@rock-chips.com>
This commit is contained in:
@@ -9,3 +9,9 @@ config EPD_TPS65185_SENSOR
|
|||||||
bool "eink pmic Tps65185"
|
bool "eink pmic Tps65185"
|
||||||
depends on ROCKCHIP_EBC_DEV
|
depends on ROCKCHIP_EBC_DEV
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config EPD_SY7636A_PMIC
|
||||||
|
bool "EINK PMIC SY7636A Support"
|
||||||
|
depends on ROCKCHIP_EBC_DEV
|
||||||
|
help
|
||||||
|
If you say yes here you get support for the Silergy SY7636A PMIC.
|
||||||
|
|||||||
@@ -3,3 +3,4 @@
|
|||||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += ebc_pmic.o
|
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += ebc_pmic.o
|
||||||
obj-$(CONFIG_EPD_TPS65185_SENSOR) += tps65185.o
|
obj-$(CONFIG_EPD_TPS65185_SENSOR) += tps65185.o
|
||||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += ebc_pmic_mfd.o
|
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += ebc_pmic_mfd.o
|
||||||
|
obj-$(CONFIG_EPD_SY7636A_PMIC) += sy7636a-regulator.o
|
||||||
|
|||||||
@@ -62,7 +62,17 @@ static int pmic_mfd_i2c_probe(struct i2c_client *i2c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct mfd_cell sy7636a_cells[] = {
|
||||||
|
{ .name = "sy7636a-regulator", },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pmic_mfd_data silergy_sy7636a = {
|
||||||
|
.mfd_cell = sy7636a_cells,
|
||||||
|
.mfd_cell_size = ARRAY_SIZE(sy7636a_cells),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id pmic_mfd_i2c_of_match[] = {
|
static const struct of_device_id pmic_mfd_i2c_of_match[] = {
|
||||||
|
{ .compatible = "silergy,sy7636a-pmic", .data = &silergy_sy7636a},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, pmic_mfd_i2c_of_match);
|
MODULE_DEVICE_TABLE(of, pmic_mfd_i2c_of_match);
|
||||||
|
|||||||
256
drivers/gpu/drm/rockchip/ebc-dev/pmic/sy7636a-regulator.c
Normal file
256
drivers/gpu/drm/rockchip/ebc-dev/pmic/sy7636a-regulator.c
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include "sy7636a.h"
|
||||||
|
|
||||||
|
#define SY7636A_MAX_ENABLE_GPIO_NUM 4
|
||||||
|
|
||||||
|
struct sy7636a_data {
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct gpio_descs *enable_gpio;
|
||||||
|
/*
|
||||||
|
* When registering a new regulator, regulator core will try to
|
||||||
|
* call "set_suspend_disable" to check whether regulator device
|
||||||
|
* working well.
|
||||||
|
* Just skip this suspend to avoid reconfiguring pinctrl.
|
||||||
|
*/
|
||||||
|
bool initial_suspend;
|
||||||
|
int vcom_uV;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int val, val_h;
|
||||||
|
|
||||||
|
ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
val |= (val_h << VCOM_ADJUST_CTRL_SHIFT);
|
||||||
|
|
||||||
|
return (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sy7636a_set_vcom_voltage_op(struct regulator_dev *rdev, int min_uV, int max_uV,
|
||||||
|
unsigned int *selector)
|
||||||
|
{
|
||||||
|
struct sy7636a_data *data = rdev->reg_data;
|
||||||
|
int min_mV = DIV_ROUND_UP(min_uV, 1000);
|
||||||
|
int max_mV = max_uV / 1000;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (max_mV < min_mV)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
val = min_mV / 10;
|
||||||
|
|
||||||
|
ret = regmap_write(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, val & 0xFF);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, (val >> 1) & 0x80);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
data->vcom_uV = min_uV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sy7636a_get_status(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sy7636a_set_suspend_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
DECLARE_BITMAP(values, SY7636A_MAX_ENABLE_GPIO_NUM);
|
||||||
|
struct sy7636a_data *data = rdev->reg_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bitmap_zero(values, SY7636A_MAX_ENABLE_GPIO_NUM);
|
||||||
|
|
||||||
|
/* Skip initial suspend */
|
||||||
|
if (data->initial_suspend) {
|
||||||
|
data->initial_suspend = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_write_bits(rdev->regmap, SY7636A_REG_OPERATION_MODE_CRL,
|
||||||
|
SY7636A_OPERATION_MODE_CRL_VCOMCTL, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (data->enable_gpio) {
|
||||||
|
ret = gpiod_set_array_value_cansleep(data->enable_gpio->ndescs,
|
||||||
|
data->enable_gpio->desc,
|
||||||
|
data->enable_gpio->info, values);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sy7636a_resume(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
DECLARE_BITMAP(values, SY7636A_MAX_ENABLE_GPIO_NUM);
|
||||||
|
struct sy7636a_data *data = rdev->reg_data;
|
||||||
|
int ret, val;
|
||||||
|
|
||||||
|
bitmap_fill(values, SY7636A_MAX_ENABLE_GPIO_NUM);
|
||||||
|
|
||||||
|
if (data->enable_gpio) {
|
||||||
|
ret = gpiod_set_array_value_cansleep(data->enable_gpio->ndescs,
|
||||||
|
data->enable_gpio->desc,
|
||||||
|
data->enable_gpio->info, values);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After enable, sy7636a needs 2.5ms to enter active mode from sleep mode. */
|
||||||
|
usleep_range(2500, 2600);
|
||||||
|
|
||||||
|
/* VCOM setting resume */
|
||||||
|
val = data->vcom_uV / VCOM_ADJUST_CTRL_SCAL;
|
||||||
|
|
||||||
|
ret = regmap_write(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, val & 0xFF);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, (val >> 1) & 0x80);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(rdev->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write_bits(rdev->regmap, SY7636A_REG_OPERATION_MODE_CRL,
|
||||||
|
SY7636A_OPERATION_MODE_CRL_VCOMCTL, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct regulator_ops sy7636a_vcom_volt_ops = {
|
||||||
|
.set_voltage = sy7636a_set_vcom_voltage_op,
|
||||||
|
.get_voltage = sy7636a_get_vcom_voltage_op,
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.get_status = sy7636a_get_status,
|
||||||
|
.set_suspend_disable = sy7636a_set_suspend_disable,
|
||||||
|
.resume = sy7636a_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_desc desc = {
|
||||||
|
.name = "vcom",
|
||||||
|
.id = 0,
|
||||||
|
.ops = &sy7636a_vcom_volt_ops,
|
||||||
|
.type = REGULATOR_VOLTAGE,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.enable_reg = SY7636A_REG_OPERATION_MODE_CRL,
|
||||||
|
.enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF,
|
||||||
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
|
.of_match = of_match_ptr("vcom"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sy7636a_regulator_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
struct sy7636a_data *data;
|
||||||
|
int ret, val, val_h;
|
||||||
|
|
||||||
|
if (!regmap)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
|
data = devm_kzalloc(&pdev->dev, sizeof(struct sy7636a_data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data->regmap = regmap;
|
||||||
|
data->initial_suspend = true;
|
||||||
|
|
||||||
|
data->enable_gpio = devm_gpiod_get_array_optional(pdev->dev.parent, "enable",
|
||||||
|
GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(data->enable_gpio)) {
|
||||||
|
dev_err(pdev->dev.parent, "Failed to get sy7636a enable gpio %ld\n",
|
||||||
|
PTR_ERR(data->enable_gpio));
|
||||||
|
return PTR_ERR(data->enable_gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sy7636a needs 2.5ms to enter active mode after enable */
|
||||||
|
usleep_range(2500, 2600);
|
||||||
|
|
||||||
|
ret = regmap_write(regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ret = regmap_read(regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ret = regmap_read(regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
val |= (val_h << VCOM_ADJUST_CTRL_SHIFT);
|
||||||
|
data->vcom_uV = (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
|
config.dev = &pdev->dev;
|
||||||
|
config.dev->of_node = pdev->dev.parent->of_node;
|
||||||
|
config.regmap = regmap;
|
||||||
|
config.driver_data = data;
|
||||||
|
|
||||||
|
rdev = devm_regulator_register(&pdev->dev, &desc, &config);
|
||||||
|
if (IS_ERR(rdev)) {
|
||||||
|
dev_err(pdev->dev.parent, "Failed to register %s regulator\n", pdev->name);
|
||||||
|
return PTR_ERR(rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
dev_err(pdev->dev.parent, "Failed to initialize regulator: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct platform_device_id sy7636a_regulator_id_table[] = {
|
||||||
|
{ "sy7636a-regulator", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table);
|
||||||
|
|
||||||
|
static struct platform_driver sy7636a_regulator_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "sy7636a-regulator",
|
||||||
|
},
|
||||||
|
.probe = sy7636a_regulator_probe,
|
||||||
|
.id_table = sy7636a_regulator_id_table,
|
||||||
|
};
|
||||||
|
module_platform_driver(sy7636a_regulator_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("SY7636A voltage regulator driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
32
drivers/gpu/drm/rockchip/ebc-dev/pmic/sy7636a.h
Normal file
32
drivers/gpu/drm/rockchip/ebc-dev/pmic/sy7636a.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SY7636A_H
|
||||||
|
#define SY7636A_H
|
||||||
|
|
||||||
|
#define SY7636A_REG_OPERATION_MODE_CRL 0x00
|
||||||
|
/* It is set if a gpio is used to control the regulator */
|
||||||
|
#define SY7636A_OPERATION_MODE_CRL_VCOMCTL BIT(6)
|
||||||
|
#define SY7636A_OPERATION_MODE_CRL_ONOFF BIT(7)
|
||||||
|
#define SY7636A_REG_VCOM_ADJUST_CTRL_L 0x01
|
||||||
|
#define SY7636A_REG_VCOM_ADJUST_CTRL_H 0x02
|
||||||
|
#define SY7636A_REG_VCOM_ADJUST_CTRL_MASK 0x01ff
|
||||||
|
#define SY7636A_REG_VLDO_VOLTAGE_ADJULST_CTRL 0x03
|
||||||
|
#define SY7636A_REG_POWER_ON_DELAY_TIME 0x06
|
||||||
|
#define SY7636A_REG_FAULT_FLAG 0x07
|
||||||
|
#define SY7636A_FAULT_FLAG_PG BIT(0)
|
||||||
|
#define SY7636A_REG_TERMISTOR_READOUT 0x08
|
||||||
|
|
||||||
|
#define SY7636A_REG_MAX 0x08
|
||||||
|
|
||||||
|
#define VCOM_ADJUST_CTRL_MASK 0x1ff
|
||||||
|
/* Used to shift the high byte */
|
||||||
|
#define VCOM_ADJUST_CTRL_SHIFT 8
|
||||||
|
/* Used to scale from VCOM_ADJUST_CTRL to mv */
|
||||||
|
#define VCOM_ADJUST_CTRL_SCAL 10000
|
||||||
|
|
||||||
|
#define FAULT_FLAG_SHIFT 1
|
||||||
|
|
||||||
|
#endif /* SY7636A_H */
|
||||||
Reference in New Issue
Block a user