Commit e6beda56 authored by Mark Brown's avatar Mark Brown

mfd/pinctrl/regulator: Add RK806 Support

Merge series from Sebastian Reichel <sebastian.reichel@collabora.com>:

All existing boards using RK3588/RK3588s use RK806 PMICs. This series is now
the main blocker for full upstream support of those boards and it would be good
to have it merged for 6.5 :) The patches have been tested on multiple different
platforms and are mainly missing an Ack from Mark or Liam for the rk808-regulator
changes.

Merging must happen through a single tree, since the pinctrl and regulator
drivers rely on the register definitions from the include file added by the MFD
patch. My suggested merge strategy is that Lee creates an immutable branch for
the regulator/pinctrl tree once all Acks have been collected.
parents 15a1cd24 f991a220
This diff is collapsed.
......@@ -82,7 +82,7 @@ config COMMON_CLK_MAX9485
config COMMON_CLK_RK808
tristate "Clock driver for RK805/RK808/RK809/RK817/RK818"
depends on MFD_RK808
depends on MFD_RK8XX
help
This driver supports RK805, RK809 and RK817, RK808 and RK818 crystal oscillator clock.
These multi-function devices have two fixed-rate oscillators, clocked at 32KHz each.
......
......@@ -12,10 +12,9 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mfd/rk808.h>
#include <linux/i2c.h>
struct rk808_clkout {
struct rk808 *rk808;
struct regmap *regmap;
struct clk_hw clkout1_hw;
struct clk_hw clkout2_hw;
};
......@@ -31,9 +30,8 @@ static int rk808_clkout2_enable(struct clk_hw *hw, bool enable)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
struct rk808 *rk808 = rk808_clkout->rk808;
return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG,
return regmap_update_bits(rk808_clkout->regmap, RK808_CLK32OUT_REG,
CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
}
......@@ -52,10 +50,9 @@ static int rk808_clkout2_is_prepared(struct clk_hw *hw)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
struct rk808 *rk808 = rk808_clkout->rk808;
uint32_t val;
int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val);
int ret = regmap_read(rk808_clkout->regmap, RK808_CLK32OUT_REG, &val);
if (ret < 0)
return ret;
......@@ -93,9 +90,8 @@ static int rk817_clkout2_enable(struct clk_hw *hw, bool enable)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
struct rk808 *rk808 = rk808_clkout->rk808;
return regmap_update_bits(rk808->regmap, RK817_SYS_CFG(1),
return regmap_update_bits(rk808_clkout->regmap, RK817_SYS_CFG(1),
RK817_CLK32KOUT2_EN,
enable ? RK817_CLK32KOUT2_EN : 0);
}
......@@ -115,10 +111,9 @@ static int rk817_clkout2_is_prepared(struct clk_hw *hw)
struct rk808_clkout *rk808_clkout = container_of(hw,
struct rk808_clkout,
clkout2_hw);
struct rk808 *rk808 = rk808_clkout->rk808;
unsigned int val;
int ret = regmap_read(rk808->regmap, RK817_SYS_CFG(1), &val);
int ret = regmap_read(rk808_clkout->regmap, RK817_SYS_CFG(1), &val);
if (ret < 0)
return 0;
......@@ -153,18 +148,21 @@ static const struct clk_ops *rkpmic_get_ops(long variant)
static int rk808_clkout_probe(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
struct i2c_client *client = rk808->i2c;
struct device_node *node = client->dev.of_node;
struct device *dev = &pdev->dev;
struct clk_init_data init = {};
struct rk808_clkout *rk808_clkout;
int ret;
rk808_clkout = devm_kzalloc(&client->dev,
dev->of_node = pdev->dev.parent->of_node;
rk808_clkout = devm_kzalloc(dev,
sizeof(*rk808_clkout), GFP_KERNEL);
if (!rk808_clkout)
return -ENOMEM;
rk808_clkout->rk808 = rk808;
rk808_clkout->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!rk808_clkout->regmap)
return -ENODEV;
init.parent_names = NULL;
init.num_parents = 0;
......@@ -173,10 +171,10 @@ static int rk808_clkout_probe(struct platform_device *pdev)
rk808_clkout->clkout1_hw.init = &init;
/* optional override of the clockname */
of_property_read_string_index(node, "clock-output-names",
of_property_read_string_index(dev->of_node, "clock-output-names",
0, &init.name);
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout1_hw);
ret = devm_clk_hw_register(dev, &rk808_clkout->clkout1_hw);
if (ret)
return ret;
......@@ -185,10 +183,10 @@ static int rk808_clkout_probe(struct platform_device *pdev)
rk808_clkout->clkout2_hw.init = &init;
/* optional override of the clockname */
of_property_read_string_index(node, "clock-output-names",
of_property_read_string_index(dev->of_node, "clock-output-names",
1, &init.name);
ret = devm_clk_hw_register(&client->dev, &rk808_clkout->clkout2_hw);
ret = devm_clk_hw_register(dev, &rk808_clkout->clkout2_hw);
if (ret)
return ret;
......
......@@ -609,7 +609,7 @@ config INPUT_PWM_VIBRA
config INPUT_RK805_PWRKEY
tristate "Rockchip RK805 PMIC power key support"
depends on MFD_RK808
depends on MFD_RK8XX
help
Select this option to enable power key driver for RK805.
......
......@@ -1183,12 +1183,17 @@ config MFD_RC5T583
Additional drivers must be enabled in order to use the
different functionality of the device.
config MFD_RK808
config MFD_RK8XX
bool
select MFD_CORE
config MFD_RK8XX_I2C
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip"
depends on I2C && OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select MFD_RK8XX
help
If you say yes here you get support for the RK805, RK808, RK809,
RK817 and RK818 Power Management chips.
......@@ -1196,6 +1201,20 @@ config MFD_RK808
through I2C interface. The device supports multiple sub-devices
including interrupts, RTC, LDO & DCDC regulators, and onkey.
config MFD_RK8XX_SPI
tristate "Rockchip RK806 Power Management Chip"
depends on SPI && OF
select MFD_CORE
select REGMAP_SPI
select REGMAP_IRQ
select MFD_RK8XX
help
If you say yes here you get support for the RK806 Power Management
chip.
This driver provides common support for accessing the device
through an SPI interface. The device supports multiple sub-devices
including interrupts, LDO & DCDC regulators, and power on-key.
config MFD_RN5T618
tristate "Ricoh RN5T567/618 PMIC"
depends on I2C
......
......@@ -214,7 +214,9 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_NTXEC) += ntxec.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_RK808) += rk808.o
obj-$(CONFIG_MFD_RK8XX) += rk8xx-core.o
obj-$(CONFIG_MFD_RK8XX_I2C) += rk8xx-i2c.o
obj-$(CONFIG_MFD_RK8XX_SPI) += rk8xx-spi.o
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
obj-$(CONFIG_MFD_SYSCON) += syscon.o
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip RK808/RK818 Core (I2C) driver
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
* Copyright (C) 2016 PHYTEC Messtechnik GmbH
*
* Author: Chris Zhong <zyw@rock-chips.com>
* Author: Zhang Qing <zhangqing@rock-chips.com>
* Author: Wadim Egorov <w.egorov@phytec.de>
*/
#include <linux/i2c.h>
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
struct rk8xx_i2c_platform_data {
const struct regmap_config *regmap_cfg;
int variant;
};
static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
{
/*
* Notes:
* - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
* we don't use that feature. It's better to cache.
* - It's unlikely we care that RK808_DEVCTRL_REG is volatile since
* bits are cleared in case when we shutoff anyway, but better safe.
*/
switch (reg) {
case RK808_SECONDS_REG ... RK808_WEEKS_REG:
case RK808_RTC_STATUS_REG:
case RK808_VB_MON_REG:
case RK808_THERMAL_REG:
case RK808_DCDC_UV_STS_REG:
case RK808_LDO_UV_STS_REG:
case RK808_DCDC_PG_REG:
case RK808_LDO_PG_REG:
case RK808_DEVCTRL_REG:
case RK808_INT_STS_REG1:
case RK808_INT_STS_REG2:
return true;
}
return false;
}
static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
{
/*
* Notes:
* - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
* we don't use that feature. It's better to cache.
*/
switch (reg) {
case RK817_SECONDS_REG ... RK817_WEEKS_REG:
case RK817_RTC_STATUS_REG:
case RK817_CODEC_DTOP_LPT_SRST:
case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0:
case RK817_PMIC_CHRG_STS:
case RK817_PMIC_CHRG_OUT:
case RK817_PMIC_CHRG_IN:
case RK817_INT_STS_REG0:
case RK817_INT_STS_REG1:
case RK817_INT_STS_REG2:
case RK817_SYS_STS:
return true;
}
return false;
}
static const struct regmap_config rk818_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RK818_USB_CTRL_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = rk808_is_volatile_reg,
};
static const struct regmap_config rk805_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RK805_OFF_SOURCE_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = rk808_is_volatile_reg,
};
static const struct regmap_config rk808_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RK808_IO_POL_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = rk808_is_volatile_reg,
};
static const struct regmap_config rk817_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RK817_GPIO_INT_CFG,
.cache_type = REGCACHE_NONE,
.volatile_reg = rk817_is_volatile_reg,
};
static const struct rk8xx_i2c_platform_data rk805_data = {
.regmap_cfg = &rk805_regmap_config,
.variant = RK805_ID,
};
static const struct rk8xx_i2c_platform_data rk808_data = {
.regmap_cfg = &rk808_regmap_config,
.variant = RK808_ID,
};
static const struct rk8xx_i2c_platform_data rk809_data = {
.regmap_cfg = &rk817_regmap_config,
.variant = RK809_ID,
};
static const struct rk8xx_i2c_platform_data rk817_data = {
.regmap_cfg = &rk817_regmap_config,
.variant = RK817_ID,
};
static const struct rk8xx_i2c_platform_data rk818_data = {
.regmap_cfg = &rk818_regmap_config,
.variant = RK818_ID,
};
static int rk8xx_i2c_probe(struct i2c_client *client)
{
const struct rk8xx_i2c_platform_data *data;
struct regmap *regmap;
data = device_get_match_data(&client->dev);
if (!data)
return -ENODEV;
regmap = devm_regmap_init_i2c(client, data->regmap_cfg);
if (IS_ERR(regmap))
return dev_err_probe(&client->dev, PTR_ERR(regmap),
"regmap initialization failed\n");
return rk8xx_probe(&client->dev, data->variant, client->irq, regmap);
}
static void rk8xx_i2c_shutdown(struct i2c_client *client)
{
rk8xx_shutdown(&client->dev);
}
static SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume);
static const struct of_device_id rk8xx_i2c_of_match[] = {
{ .compatible = "rockchip,rk805", .data = &rk805_data },
{ .compatible = "rockchip,rk808", .data = &rk808_data },
{ .compatible = "rockchip,rk809", .data = &rk809_data },
{ .compatible = "rockchip,rk817", .data = &rk817_data },
{ .compatible = "rockchip,rk818", .data = &rk818_data },
{ },
};
MODULE_DEVICE_TABLE(of, rk8xx_i2c_of_match);
static struct i2c_driver rk8xx_i2c_driver = {
.driver = {
.name = "rk8xx-i2c",
.of_match_table = rk8xx_i2c_of_match,
.pm = &rk8xx_i2c_pm_ops,
},
.probe_new = rk8xx_i2c_probe,
.shutdown = rk8xx_i2c_shutdown,
};
module_i2c_driver(rk8xx_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
MODULE_DESCRIPTION("RK8xx I2C PMIC driver");
// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip RK806 Core (SPI) driver
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
* Copyright (c) 2023 Collabora Ltd.
*
* Author: Xu Shengfei <xsf@rock-chips.com>
* Author: Sebastian Reichel <sebastian.reichel@collabora.com>
*/
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#define RK806_ADDR_SIZE 2
#define RK806_CMD_WITH_SIZE(CMD, VALUE_BYTES) \
(RK806_CMD_##CMD | RK806_CMD_CRC_DIS | (VALUE_BYTES - 1))
static const struct regmap_range rk806_volatile_ranges[] = {
regmap_reg_range(RK806_POWER_EN0, RK806_POWER_EN5),
regmap_reg_range(RK806_DVS_START_CTRL, RK806_INT_MSK1),
};
static const struct regmap_access_table rk806_volatile_table = {
.yes_ranges = rk806_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(rk806_volatile_ranges),
};
static const struct regmap_config rk806_regmap_config_spi = {
.reg_bits = 16,
.val_bits = 8,
.max_register = RK806_BUCK_RSERVE_REG5,
.cache_type = REGCACHE_RBTREE,
.volatile_table = &rk806_volatile_table,
};
static int rk806_spi_bus_write(void *context, const void *vdata, size_t count)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
struct spi_transfer xfer[2] = { 0 };
/* data and thus count includes the register address */
size_t val_size = count - RK806_ADDR_SIZE;
char cmd;
if (val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))
return -EINVAL;
cmd = RK806_CMD_WITH_SIZE(WRITE, val_size);
xfer[0].tx_buf = &cmd;
xfer[0].len = sizeof(cmd);
xfer[1].tx_buf = vdata;
xfer[1].len = count;
return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
}
static int rk806_spi_bus_read(void *context, const void *vreg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
char txbuf[3] = { 0 };
if (reg_size != RK806_ADDR_SIZE ||
val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))
return -EINVAL;
/* TX buffer contains command byte followed by two address bytes */
txbuf[0] = RK806_CMD_WITH_SIZE(READ, val_size);
memcpy(txbuf+1, vreg, reg_size);
return spi_write_then_read(spi, txbuf, sizeof(txbuf), val, val_size);
}
static const struct regmap_bus rk806_regmap_bus_spi = {
.write = rk806_spi_bus_write,
.read = rk806_spi_bus_read,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
static int rk8xx_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
regmap = devm_regmap_init(&spi->dev, &rk806_regmap_bus_spi,
&spi->dev, &rk806_regmap_config_spi);
if (IS_ERR(regmap))
return dev_err_probe(&spi->dev, PTR_ERR(regmap),
"Failed to init regmap\n");
return rk8xx_probe(&spi->dev, RK806_ID, spi->irq, regmap);
}
static const struct of_device_id rk8xx_spi_of_match[] = {
{ .compatible = "rockchip,rk806", },
{ }
};
MODULE_DEVICE_TABLE(of, rk8xx_spi_of_match);
static const struct spi_device_id rk8xx_spi_id_table[] = {
{ "rk806", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, rk8xx_spi_id_table);
static struct spi_driver rk8xx_spi_driver = {
.driver = {
.name = "rk8xx-spi",
.of_match_table = rk8xx_spi_of_match,
},
.probe = rk8xx_spi_probe,
.id_table = rk8xx_spi_id_table,
};
module_spi_driver(rk8xx_spi_driver);
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_DESCRIPTION("RK8xx SPI PMIC driver");
MODULE_LICENSE("GPL");
......@@ -407,7 +407,7 @@ config PINCTRL_PISTACHIO
config PINCTRL_RK805
tristate "Pinctrl and GPIO driver for RK805 PMIC"
depends on MFD_RK808
depends on MFD_RK8XX
select GPIOLIB
select PINMUX
select GENERIC_PINCONF
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Pinctrl driver for Rockchip RK805 PMIC
* Pinctrl driver for Rockchip RK805/RK806 PMIC
*
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*
* Author: Joseph Chen <chenjh@rock-chips.com>
* Author: Xu Shengfei <xsf@rock-chips.com>
*
* Based on the pinctrl-as3722 driver
*/
......@@ -44,6 +46,7 @@ struct rk805_pin_group {
/*
* @reg: gpio setting register;
* @fun_reg: functions select register;
* @fun_mask: functions select mask value, when set is gpio;
* @dir_mask: input or output mask value, when set is output, otherwise input;
* @val_mask: gpio set value, when set is level high, otherwise low;
......@@ -56,6 +59,7 @@ struct rk805_pin_group {
*/
struct rk805_pin_config {
u8 reg;
u8 fun_reg;
u8 fun_msk;
u8 dir_msk;
u8 val_msk;
......@@ -80,22 +84,50 @@ enum rk805_pinmux_option {
RK805_PINMUX_GPIO,
};
enum rk806_pinmux_option {
RK806_PINMUX_FUN0 = 0,
RK806_PINMUX_FUN1,
RK806_PINMUX_FUN2,
RK806_PINMUX_FUN3,
RK806_PINMUX_FUN4,
RK806_PINMUX_FUN5,
};
enum {
RK805_GPIO0,
RK805_GPIO1,
};
enum {
RK806_GPIO_DVS1,
RK806_GPIO_DVS2,
RK806_GPIO_DVS3
};
static const char *const rk805_gpio_groups[] = {
"gpio0",
"gpio1",
};
static const char *const rk806_gpio_groups[] = {
"gpio_pwrctrl1",
"gpio_pwrctrl2",
"gpio_pwrctrl3",
};
/* RK805: 2 output only GPIOs */
static const struct pinctrl_pin_desc rk805_pins_desc[] = {
PINCTRL_PIN(RK805_GPIO0, "gpio0"),
PINCTRL_PIN(RK805_GPIO1, "gpio1"),
};
/* RK806 */
static const struct pinctrl_pin_desc rk806_pins_desc[] = {
PINCTRL_PIN(RK806_GPIO_DVS1, "gpio_pwrctrl1"),
PINCTRL_PIN(RK806_GPIO_DVS2, "gpio_pwrctrl2"),
PINCTRL_PIN(RK806_GPIO_DVS3, "gpio_pwrctrl3"),
};
static const struct rk805_pin_function rk805_pin_functions[] = {
{
.name = "gpio",
......@@ -105,6 +137,45 @@ static const struct rk805_pin_function rk805_pin_functions[] = {
},
};
static const struct rk805_pin_function rk806_pin_functions[] = {
{
.name = "pin_fun0",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN0,
},
{
.name = "pin_fun1",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN1,
},
{
.name = "pin_fun2",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN2,
},
{
.name = "pin_fun3",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN3,
},
{
.name = "pin_fun4",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN4,
},
{
.name = "pin_fun5",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN5,
},
};
static const struct rk805_pin_group rk805_pin_groups[] = {
{
.name = "gpio0",
......@@ -118,6 +189,24 @@ static const struct rk805_pin_group rk805_pin_groups[] = {
},
};
static const struct rk805_pin_group rk806_pin_groups[] = {
{
.name = "gpio_pwrctrl1",
.pins = { RK806_GPIO_DVS1 },
.npins = 1,
},
{
.name = "gpio_pwrctrl2",
.pins = { RK806_GPIO_DVS2 },
.npins = 1,
},
{
.name = "gpio_pwrctrl3",
.pins = { RK806_GPIO_DVS3 },
.npins = 1,
}
};
#define RK805_GPIO0_VAL_MSK BIT(0)
#define RK805_GPIO1_VAL_MSK BIT(1)
......@@ -132,6 +221,40 @@ static const struct rk805_pin_config rk805_gpio_cfgs[] = {
},
};
#define RK806_PWRCTRL1_DR BIT(0)
#define RK806_PWRCTRL2_DR BIT(1)
#define RK806_PWRCTRL3_DR BIT(2)
#define RK806_PWRCTRL1_DATA BIT(4)
#define RK806_PWRCTRL2_DATA BIT(5)
#define RK806_PWRCTRL3_DATA BIT(6)
#define RK806_PWRCTRL1_FUN GENMASK(2, 0)
#define RK806_PWRCTRL2_FUN GENMASK(6, 4)
#define RK806_PWRCTRL3_FUN GENMASK(2, 0)
static struct rk805_pin_config rk806_gpio_cfgs[] = {
{
.fun_reg = RK806_SLEEP_CONFIG0,
.fun_msk = RK806_PWRCTRL1_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL1_DATA,
.dir_msk = RK806_PWRCTRL1_DR,
},
{
.fun_reg = RK806_SLEEP_CONFIG0,
.fun_msk = RK806_PWRCTRL2_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL2_DATA,
.dir_msk = RK806_PWRCTRL2_DR,
},
{
.fun_reg = RK806_SLEEP_CONFIG1,
.fun_msk = RK806_PWRCTRL3_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL3_DATA,
.dir_msk = RK806_PWRCTRL3_DR,
}
};
/* generic gpio chip */
static int rk805_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
......@@ -289,19 +412,13 @@ static int _rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev,
if (!pci->pin_cfg[offset].fun_msk)
return 0;
if (mux == RK805_PINMUX_GPIO) {
ret = regmap_update_bits(pci->rk808->regmap,
pci->pin_cfg[offset].reg,
pci->pin_cfg[offset].fun_msk,
pci->pin_cfg[offset].fun_msk);
if (ret) {
dev_err(pci->dev, "set gpio%d GPIO failed\n", offset);
return ret;
}
} else {
dev_err(pci->dev, "Couldn't find function mux %d\n", mux);
return -EINVAL;
}
mux <<= ffs(pci->pin_cfg[offset].fun_msk) - 1;
ret = regmap_update_bits(pci->rk808->regmap,
pci->pin_cfg[offset].fun_reg,
pci->pin_cfg[offset].fun_msk, mux);
if (ret)
dev_err(pci->dev, "set gpio%d func%d failed\n", offset, mux);
return 0;
}
......@@ -317,6 +434,22 @@ static int rk805_pinctrl_set_mux(struct pinctrl_dev *pctldev,
return _rk805_pinctrl_set_mux(pctldev, offset, mux);
}
static int rk805_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset)
{
struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
switch (pci->rk808->variant) {
case RK805_ID:
return _rk805_pinctrl_set_mux(pctldev, offset, RK805_PINMUX_GPIO);
case RK806_ID:
return _rk805_pinctrl_set_mux(pctldev, offset, RK806_PINMUX_FUN5);
}
return -ENOTSUPP;
}
static int rk805_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset, bool input)
......@@ -324,13 +457,6 @@ static int rk805_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct rk805_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
int ret;
/* switch to gpio function */
ret = _rk805_pinctrl_set_mux(pctldev, offset, RK805_PINMUX_GPIO);
if (ret) {
dev_err(pci->dev, "set gpio%d mux failed\n", offset);
return ret;
}
/* set direction */
if (!pci->pin_cfg[offset].dir_msk)
return 0;
......@@ -352,6 +478,7 @@ static const struct pinmux_ops rk805_pinmux_ops = {
.get_function_name = rk805_pinctrl_get_func_name,
.get_function_groups = rk805_pinctrl_get_func_groups,
.set_mux = rk805_pinctrl_set_mux,
.gpio_request_enable = rk805_pinctrl_gpio_request_enable,
.gpio_set_direction = rk805_pmx_gpio_set_direction,
};
......@@ -364,6 +491,7 @@ static int rk805_pinconf_get(struct pinctrl_dev *pctldev,
switch (param) {
case PIN_CONFIG_OUTPUT:
case PIN_CONFIG_INPUT_ENABLE:
arg = rk805_gpio_get(&pci->gpio_chip, pin);
break;
default:
......@@ -393,6 +521,12 @@ static int rk805_pinconf_set(struct pinctrl_dev *pctldev,
rk805_gpio_set(&pci->gpio_chip, pin, arg);
rk805_pmx_gpio_set_direction(pctldev, NULL, pin, false);
break;
case PIN_CONFIG_INPUT_ENABLE:
if (pci->rk808->variant != RK805_ID && arg) {
rk805_pmx_gpio_set_direction(pctldev, NULL, pin, true);
break;
}
fallthrough;
default:
dev_err(pci->dev, "Properties not supported\n");
return -ENOTSUPP;
......@@ -448,6 +582,18 @@ static int rk805_pinctrl_probe(struct platform_device *pdev)
pci->pin_cfg = rk805_gpio_cfgs;
pci->gpio_chip.ngpio = ARRAY_SIZE(rk805_gpio_cfgs);
break;
case RK806_ID:
pci->pins = rk806_pins_desc;
pci->num_pins = ARRAY_SIZE(rk806_pins_desc);
pci->functions = rk806_pin_functions;
pci->num_functions = ARRAY_SIZE(rk806_pin_functions);
pci->groups = rk806_pin_groups;
pci->num_pin_groups = ARRAY_SIZE(rk806_pin_groups);
pci->pinctrl_desc.pins = rk806_pins_desc;
pci->pinctrl_desc.npins = ARRAY_SIZE(rk806_pins_desc);
pci->pin_cfg = rk806_gpio_cfgs;
pci->gpio_chip.ngpio = ARRAY_SIZE(rk806_gpio_cfgs);
break;
default:
dev_err(&pdev->dev, "unsupported RK805 ID %lu\n",
pci->rk808->variant);
......@@ -488,5 +634,6 @@ static struct platform_driver rk805_pinctrl_driver = {
module_platform_driver(rk805_pinctrl_driver);
MODULE_DESCRIPTION("RK805 pin control and GPIO driver");
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>");
MODULE_LICENSE("GPL v2");
......@@ -706,7 +706,7 @@ config CHARGER_BQ256XX
config CHARGER_RK817
tristate "Rockchip RK817 PMIC Battery Charger"
depends on MFD_RK808
depends on MFD_RK8XX
help
Say Y to include support for Rockchip RK817 Battery Charger.
......
......@@ -1056,7 +1056,7 @@ config REGULATOR_RC5T583
config REGULATOR_RK808
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power regulators"
depends on MFD_RK808
depends on MFD_RK8XX
help
Select this option to enable the power regulator of ROCKCHIP
PMIC RK805,RK809&RK817,RK808 and RK818.
......
......@@ -902,8 +902,21 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2)
}
EXPORT_SYMBOL_GPL(regulator_is_equal);
static int find_closest_bigger(unsigned int target, const unsigned int *table,
unsigned int num_sel, unsigned int *sel)
/**
* regulator_find_closest_bigger - helper to find offset in ramp delay table
*
* @target: targeted ramp_delay
* @table: table with supported ramp delays
* @num_sel: number of entries in the table
* @sel: Pointer to store table offset
*
* This is the internal helper used by regulator_set_ramp_delay_regmap to
* map ramp delay to register value. It should only be used directly if
* regulator_set_ramp_delay_regmap cannot handle a specific device setup
* (e.g. because the value is split over multiple registers).
*/
int regulator_find_closest_bigger(unsigned int target, const unsigned int *table,
unsigned int num_sel, unsigned int *sel)
{
unsigned int s, tmp, max, maxsel = 0;
bool found = false;
......@@ -933,6 +946,7 @@ static int find_closest_bigger(unsigned int target, const unsigned int *table,
return 0;
}
EXPORT_SYMBOL_GPL(regulator_find_closest_bigger);
/**
* regulator_set_ramp_delay_regmap - set_ramp_delay() helper
......@@ -951,8 +965,8 @@ int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
if (WARN_ON(!rdev->desc->n_ramp_values || !rdev->desc->ramp_delay_table))
return -EINVAL;
ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
rdev->desc->n_ramp_values, &sel);
ret = regulator_find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
rdev->desc->n_ramp_values, &sel);
if (ret) {
dev_warn(rdev_get_dev(rdev),
......
This diff is collapsed.
......@@ -395,7 +395,7 @@ config RTC_DRV_NCT3018Y
config RTC_DRV_RK808
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
depends on MFD_RK808
depends on MFD_RK8XX
help
If you say yes here you will get support for the
RTC of RK805, RK809 and RK817, RK808 and RK818 PMIC.
......
This diff is collapsed.
......@@ -758,6 +758,8 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev,
int min_uA, int max_uA);
int regulator_get_current_limit_regmap(struct regulator_dev *rdev);
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
int regulator_find_closest_bigger(unsigned int target, const unsigned int *table,
unsigned int num_sel, unsigned int *sel);
int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay);
int regulator_sync_voltage_rdev(struct regulator_dev *rdev);
......
......@@ -1313,7 +1313,7 @@ config SND_SOC_RK3328
config SND_SOC_RK817
tristate "Rockchip RK817 audio CODEC"
depends on MFD_RK808 || COMPILE_TEST
depends on MFD_RK8XX || COMPILE_TEST
config SND_SOC_RL6231
tristate
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment