mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +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"
|
||||
depends on ROCKCHIP_EBC_DEV
|
||||
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_EPD_TPS65185_SENSOR) += tps65185.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;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{ .compatible = "silergy,sy7636a-pmic", .data = &silergy_sy7636a},
|
||||
{}
|
||||
};
|
||||
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