From d77feca3b97ecc525da287956cf5647ae016bc34 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Mon, 27 Apr 2020 09:19:41 +0800 Subject: [PATCH] mfd: Add RK630 mfd driver Change-Id: I03c127df4ec2ad80cbaf4b0d4ad540cb5b32a245 Signed-off-by: Algea Cao --- drivers/mfd/Kconfig | 23 ++++ drivers/mfd/Makefile | 3 + drivers/mfd/rk630-i2c.c | 79 ++++++++++++ drivers/mfd/rk630-spi.c | 249 ++++++++++++++++++++++++++++++++++++++ drivers/mfd/rk630.c | 110 +++++++++++++++++ include/linux/mfd/rk630.h | 180 +++++++++++++++++++++++++++ 6 files changed, 644 insertions(+) create mode 100644 drivers/mfd/rk630-i2c.c create mode 100644 drivers/mfd/rk630-spi.c create mode 100644 drivers/mfd/rk630.c create mode 100644 include/linux/mfd/rk630.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 69e9e1e03a06..3d249bf2293e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1017,6 +1017,29 @@ config MFD_RK628 help if you say yes here you get support for the RK628 from Rockchip. +config MFD_RK630 + tristate "RK630 CORE module support" + select MFD_CORE + help + if you say yes here you get support for the RK630, with func as + TVEncoder or CODEC. + +config MFD_RK630_I2C + tristate "RK630 I2C interface support" + select MFD_RK630 + select REGMAP_I2C + help + if you say yes here you get support for the RK630 when controlled + using I2C. + +config MFD_RK630_SPI + tristate "RK630 SPI interface support" + select MFD_RK630 + select REGMAP_SPI + help + if you say yes here you get support for the RK630 when controlled + using SPI. + config MFD_RK808 tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power Management Chip" depends on I2C && OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 7c0e7b365502..5ceba3e783d8 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -208,6 +208,9 @@ obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_RK618) += rk618.o obj-$(CONFIG_MFD_RK628) += rk628.o +obj-$(CONFIG_MFD_RK630) += rk630.o +obj-$(CONFIG_MFD_RK630_I2C) += rk630-i2c.o +obj-$(CONFIG_MFD_RK630_SPI) += rk630-spi.o obj-$(CONFIG_MFD_RK808) += rk808.o obj-$(CONFIG_MFD_RK1000) += rk1000-core.o obj-$(CONFIG_MFD_RN5T618) += rn5t618.o diff --git a/drivers/mfd/rk630-i2c.c b/drivers/mfd/rk630-i2c.c new file mode 100644 index 000000000000..e31a5b4314fb --- /dev/null +++ b/drivers/mfd/rk630-i2c.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Rockchip Electronics Co. Ltd. + * + * Author: Algea Cao + */ + +#include +#include +#include +#include +#include +#include + +static int +rk630_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct rk630 *rk630; + int ret; + + rk630 = devm_kzalloc(dev, sizeof(*rk630), GFP_KERNEL); + if (!rk630) + return -ENOMEM; + + rk630->dev = dev; + rk630->client = client; + i2c_set_clientdata(client, rk630); + + rk630->grf = devm_regmap_init_i2c(client, &rk630_grf_regmap_config); + if (IS_ERR(rk630->grf)) { + ret = PTR_ERR(rk630->grf); + dev_err(dev, "failed to allocate grf register map: %d\n", ret); + return ret; + } + + rk630->cru = devm_regmap_init_i2c(client, &rk630_cru_regmap_config); + if (IS_ERR(rk630->cru)) { + ret = PTR_ERR(rk630->cru); + dev_err(dev, "failed to allocate cru register map: %d\n", ret); + return ret; + } + + rk630->tve = devm_regmap_init_i2c(client, &rk630_tve_regmap_config); + if (IS_ERR(rk630->tve)) { + ret = PTR_ERR(rk630->tve); + dev_err(rk630->dev, "Failed to initialize tve regmap: %d\n", + ret); + return ret; + } + + return rk630_core_probe(rk630); +} + +static const struct of_device_id rk630_i2c_of_match[] = { + { .compatible = "rockchip,rk630", }, + {} +}; +MODULE_DEVICE_TABLE(of, rk630_i2c_of_match); + +static const struct i2c_device_id rk630_i2c_id[] = { + { "rk630", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, rk630_i2c_id); + +static struct i2c_driver rk630_i2c_driver = { + .driver = { + .name = "rk630", + .of_match_table = of_match_ptr(rk630_i2c_of_match), + }, + .probe = rk630_i2c_probe, + .id_table = rk630_i2c_id, +}; +module_i2c_driver(rk630_i2c_driver); + +MODULE_AUTHOR("Algea Cao "); +MODULE_DESCRIPTION("Rockchip rk630 MFD I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/rk630-spi.c b/drivers/mfd/rk630-spi.c new file mode 100644 index 000000000000..9475db99d0aa --- /dev/null +++ b/drivers/mfd/rk630-spi.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Rockchip Electronics Co. Ltd. + * + * Author: Algea Cao + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RK630_CMD_WRITE 0x00000011 +#define RK630_CMD_WRITE_REG0 0x00010011 +#define RK630_CMD_WRITE_REG1 0x00020011 +#define RK630_CMD_WRITE_CTRL0 0x00030011 +#define RK630_CMD_READ 0x00000077 +#define RK630_CMD_READ_BEGIN 0x000000AA +#define RK630_CMD_QUERY 0x000000FF +#define RK630_CMD_QUERY_REG2 0x000001FF +#define RK630_CMD_QUICK_WRITE 0x00030011 +#define RK630_OP_STATE_ID_MASK (0xffff0000) +#define RK630_OP_STATE_ID (0X16080000) +#define RK630_OP_STATE_MASK (0x0000ffff) +#define RK630_OP_STATE_WRITE_ERROR (0x01 << 0) +#define RK630_OP_STATE_WRITE_OVERFLOW (0x01 << 1) +#define RK630_OP_STATE_WRITE_UNFINISHED (0x01 << 2) +#define RK630_OP_STATE_READ_ERROR (0x01 << 8) +#define RK630_OP_STATE_READ_UNDERFLOW (0x01 << 9) +#define RK630_OP_STATE_PRE_READ_ERROR (0x01 << 10) +#define RK630_MAX_OP_BYTES (60000) + +static int rk630_spi_ctrl_init(struct spi_device *spi) +{ + u32 write_cmd = RK630_CMD_WRITE_CTRL0; + u32 buf = 0x00000008; + struct spi_transfer write_cmd_packet = { + .tx_buf = &write_cmd, + .len = 4, + }; + struct spi_transfer data_packet = { + .tx_buf = &buf, + .len = 4, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&write_cmd_packet, &m); + spi_message_add_tail(&data_packet, &m); + return spi_sync(spi, &m); +} + +static int rk630_spi_write(struct spi_device *spi, + u32 addr, const u32 *data, size_t data_len) +{ + int ret = 0; + u32 write_cmd = RK630_CMD_WRITE; + + struct spi_transfer write_cmd_packet = { + .tx_buf = &write_cmd, + .len = sizeof(write_cmd), + }; + struct spi_transfer addr_packet = { + .tx_buf = &addr, + .len = sizeof(addr), + }; + struct spi_transfer data_packet = { + .tx_buf = data, + .len = data_len, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&write_cmd_packet, &m); + spi_message_add_tail(&addr_packet, &m); + spi_message_add_tail(&data_packet, &m); + ret = spi_sync(spi, &m); + + return ret; +} + +static int rk630_regmap_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + u32 buf[count]; + + if (count < 8) { + dev_err(&spi->dev, "regmap write err!\n"); + return -EINVAL; + } + + memcpy(buf, data, count); + + return rk630_spi_write(spi, buf[0], &buf[1], (count - 4)); +} + +static int rk630_spi_read(struct spi_device *spi, + u32 addr, u32 *data, size_t data_len) +{ + int ret; + u32 read_cmd = RK630_CMD_READ | (1 << 16); + u32 read_begin_cmd = RK630_CMD_READ_BEGIN; + u32 dummy = 0; + struct spi_transfer read_cmd_packet = { + .tx_buf = &read_cmd, + .len = sizeof(read_cmd), + }; + struct spi_transfer addr_packet = { + .tx_buf = &addr, + .len = sizeof(addr), + }; + struct spi_transfer read_dummy_packet = { + .tx_buf = &dummy, + .len = sizeof(dummy), + }; + struct spi_transfer read_begin_cmd_packet = { + .tx_buf = &read_begin_cmd, + .len = sizeof(read_begin_cmd), + }; + struct spi_transfer data_packet = { + .rx_buf = data, + .len = data_len, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&read_cmd_packet, &m); + spi_message_add_tail(&addr_packet, &m); + spi_message_add_tail(&read_dummy_packet, &m); + spi_message_add_tail(&read_begin_cmd_packet, &m); + spi_message_add_tail(&data_packet, &m); + ret = spi_sync(spi, &m); + + return ret; +} + +static int rk630_regmap_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + u32 rx_buf[2] = { 0 }; + int ret; + + if (reg_size != sizeof(u32) || val_size != sizeof(u32)) + return -EINVAL; + + /* Copy address to read from into first element of SPI buffer. */ + memcpy(rx_buf, reg, sizeof(u32)); + ret = rk630_spi_read(spi, rx_buf[0], &rx_buf[1], val_size); + if (ret < 0) { + dev_err(&spi->dev, "rk630 spi read err\n"); + return ret; + } + + memcpy(val, &rx_buf[1], val_size); + return 0; +} + +static struct regmap_bus rk630_regmap = { + .write = rk630_regmap_write, + .read = rk630_regmap_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static int +rk630_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct rk630 *rk630; + int ret; + + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret < 0) + return ret; + + rk630 = devm_kzalloc(dev, sizeof(*rk630), GFP_KERNEL); + if (!rk630) + return -ENOMEM; + + rk630->dev = dev; + spi_set_drvdata(spi, rk630); + + rk630->grf = devm_regmap_init(&spi->dev, &rk630_regmap, + &spi->dev, &rk630_grf_regmap_config); + if (IS_ERR(rk630->grf)) { + ret = PTR_ERR(rk630->grf); + dev_err(dev, "failed to allocate grf register map: %d\n", ret); + return ret; + } + + rk630->cru = devm_regmap_init(&spi->dev, &rk630_regmap, + &spi->dev, &rk630_cru_regmap_config); + if (IS_ERR(rk630->cru)) { + ret = PTR_ERR(rk630->cru); + dev_err(dev, "failed to allocate cru register map: %d\n", ret); + return ret; + } + + rk630->tve = devm_regmap_init(&spi->dev, &rk630_regmap, + &spi->dev, &rk630_tve_regmap_config); + if (IS_ERR(rk630->tve)) { + ret = PTR_ERR(rk630->tve); + dev_err(rk630->dev, "Failed to initialize tve regmap: %d\n", + ret); + return ret; + } + + ret = rk630_core_probe(rk630); + if (ret) + return ret; + + rk630_spi_ctrl_init(spi); + + return 0; +} + +static const struct of_device_id rk630_spi_of_match[] = { + { .compatible = "rockchip,rk630", }, + {} +}; +MODULE_DEVICE_TABLE(of, rk630_spi_of_match); + +static const struct spi_device_id rk630_spi_id[] = { + { "rk630", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, rk630_spi_id); + +static struct spi_driver rk630_spi_driver = { + .driver = { + .name = "rk630", + .of_match_table = of_match_ptr(rk630_spi_of_match), + }, + .probe = rk630_spi_probe, + .id_table = rk630_spi_id, +}; +module_spi_driver(rk630_spi_driver); + +MODULE_AUTHOR("Algea Cao "); +MODULE_DESCRIPTION("Rockchip rk630 MFD SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/rk630.c b/drivers/mfd/rk630.c new file mode 100644 index 000000000000..c0da053366b0 --- /dev/null +++ b/drivers/mfd/rk630.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Rockchip Electronics Co. Ltd. + * + * Author: Algea Cao + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell rk630_devs[] = { + { + .name = "rk630-tve", + .of_compatible = "rockchip,rk630-tve", + }, +}; + +static const struct regmap_range rk630_grf_readable_ranges[] = { + regmap_reg_range(PLUMAGE_GRF_GPIO0A_IOMUX, PLUMAGE_GRF_GPIO0A_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO0B_IOMUX, PLUMAGE_GRF_GPIO0B_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO0C_IOMUX, PLUMAGE_GRF_GPIO0C_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO0D_IOMUX, PLUMAGE_GRF_GPIO0D_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO1A_IOMUX, PLUMAGE_GRF_GPIO1A_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO1B_IOMUX, PLUMAGE_GRF_GPIO1B_IOMUX), + regmap_reg_range(PLUMAGE_GRF_GPIO0A_P, PLUMAGE_GRF_GPIO1B_P), + regmap_reg_range(PLUMAGE_GRF_GPIO1B_SR, PLUMAGE_GRF_GPIO1B_SR), + regmap_reg_range(PLUMAGE_GRF_GPIO1B_E, PLUMAGE_GRF_GPIO1B_E), + regmap_reg_range(PLUMAGE_GRF_SOC_CON0, PLUMAGE_GRF_SOC_CON4), + regmap_reg_range(PLUMAGE_GRF_SOC_STATUS, PLUMAGE_GRF_SOC_STATUS), + regmap_reg_range(PLUMAGE_GRF_GPIO0_REN0, PLUMAGE_GRF_GPIO1_REN0), +}; + +static const struct regmap_access_table rk630_grf_readable_table = { + .yes_ranges = rk630_grf_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(rk630_grf_readable_ranges), +}; + +const struct regmap_config rk630_grf_regmap_config = { + .name = "grf", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = GRF_MAX_REGISTER, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .rd_table = &rk630_grf_readable_table, +}; +EXPORT_SYMBOL_GPL(rk630_grf_regmap_config); + +static const struct regmap_range rk630_cru_readable_ranges[] = { + regmap_reg_range(CRU_SPLL_CON0, CRU_SPLL_CON2), + regmap_reg_range(CRU_MODE_CON, CRU_MODE_CON), + regmap_reg_range(CRU_CLKSEL_CON0, CRU_CLKSEL_CON3), + regmap_reg_range(CRU_GATE_CON0, CRU_GATE_CON0), + regmap_reg_range(CRU_SOFTRST_CON0, CRU_SOFTRST_CON0), +}; + +static const struct regmap_access_table rk630_cru_readable_table = { + .yes_ranges = rk630_cru_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(rk630_cru_readable_ranges), +}; + +const struct regmap_config rk630_cru_regmap_config = { + .name = "cru", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = CRU_MAX_REGISTER, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .rd_table = &rk630_cru_readable_table, +}; + +int rk630_core_probe(struct rk630 *rk630) +{ + int ret; + + rk630->reset_gpio = devm_gpiod_get(rk630->dev, "reset", 0); + if (IS_ERR(rk630->reset_gpio)) { + ret = PTR_ERR(rk630->reset_gpio); + dev_err(rk630->dev, "failed to request reset GPIO: %d\n", ret); + return ret; + } + + gpiod_direction_output(rk630->reset_gpio, 0); + usleep_range(2000, 4000); + gpiod_direction_output(rk630->reset_gpio, 1); + usleep_range(50000, 60000); + gpiod_direction_output(rk630->reset_gpio, 0); + + ret = devm_mfd_add_devices(rk630->dev, PLATFORM_DEVID_NONE, + rk630_devs, ARRAY_SIZE(rk630_devs), + NULL, 0, NULL); + if (ret) { + dev_err(rk630->dev, "failed to add MFD children: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rk630_core_probe); + +MODULE_AUTHOR("Algea Cao "); +MODULE_DESCRIPTION("Rockchip rk630 MFD Core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/rk630.h b/include/linux/mfd/rk630.h new file mode 100644 index 000000000000..e97989414b54 --- /dev/null +++ b/include/linux/mfd/rk630.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Rockchip Electronics Co. Ltd. + * + * Author: Algea Cao + */ + +#ifndef _rk630_H +#define _rk630_H + +#include +#include +#include +#include + +#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) +#define HIWORD_MASK(h, l) ((GENMASK((h), (l)) << 16) | GENMASK((h), (l))) +#define HIWORD_UPDATE(v, h, l) ((((v) << (l)) & GENMASK((h), (l))) | (GENMASK((h), (l)) << 16)) + +#define GRF_REG(x) ((x) + 0x20000) +#define PLUMAGE_GRF_GPIO0A_IOMUX GRF_REG(0x0000) +#define GPIO0A0_SEL_MASK HIWORD_MASK(1, 0) +#define GPIO0A0_SEL(x) HIWORD_UPDATE(x, 1, 0) +#define GPIO0A1_SEL_MASK HIWORD_MASK(3, 2) +#define GPIO0A1_SEL(x) HIWORD_UPDATE(x, 3, 2) +#define GPIO0A2_SEL_MASK HIWORD_MASK(5, 4) +#define GPIO0A2_SEL(x) HIWORD_UPDATE(x, 5, 4) +#define GPIO0A3_SEL_MASK HIWORD_MASK(7, 6) +#define GPIO0A3_SEL(x) HIWORD_UPDATE(x, 7, 6) +#define GPIO0A4_SEL_MASK HIWORD_MASK(9, 8) +#define GPIO0A4_SEL(x) HIWORD_UPDATE(x, 9, 8) +#define GPIO0A5_SEL_MASK HIWORD_MASK(11, 10) +#define GPIO0A5_SEL(x) HIWORD_UPDATE(x, 11, 10) +#define GPIO0A6_SEL_MASK HIWORD_MASK(13, 12) +#define GPIO0A6_SEL(x) HIWORD_UPDATE(x, 13, 12) +#define GPIO0A7_SEL_MASK HIWORD_MASK(15, 14) +#define GPIO0A7_SEL(x) HIWORD_UPDATE(x, 15, 14) +#define PLUMAGE_GRF_GPIO0B_IOMUX GRF_REG(0x0008) +#define GPIO0B0_SEL_MASK HIWORD_MASK(1, 0) +#define GPIO0B0_SEL(x) HIWORD_UPDATE(x, 1, 0) +#define PLUMAGE_GRF_GPIO0C_IOMUX GRF_REG(0x0010) +#define PLUMAGE_GRF_GPIO0D_IOMUX GRF_REG(0x0018) +#define PLUMAGE_GRF_GPIO1A_IOMUX GRF_REG(0x0020) +#define PLUMAGE_GRF_GPIO1B_IOMUX GRF_REG(0x0028) +#define PLUMAGE_GRF_GPIO0A_P GRF_REG(0x0080) +#define PLUMAGE_GRF_GPIO0B_P GRF_REG(0x0084) +#define PLUMAGE_GRF_GPIO0C_P GRF_REG(0x0088) +#define PLUMAGE_GRF_GPIO0D_P GRF_REG(0x008C) +#define PLUMAGE_GRF_GPIO1A_P GRF_REG(0x0090) +#define PLUMAGE_GRF_GPIO1B_P GRF_REG(0x0094) +#define PLUMAGE_GRF_GPIO1B_SR GRF_REG(0x00D4) +#define PLUMAGE_GRF_GPIO1B_E GRF_REG(0x0154) +#define PLUMAGE_GRF_SOC_CON0 GRF_REG(0x0400) +#define SW_TVE_DCLK_POL_MASK HIWORD_MASK(4, 4) +#define SW_TVE_DCLK_POL(x) HIWORD_UPDATE(x, 4, 4) +#define SW_TVE_DCLK_EN_MASK HIWORD_MASK(3, 3) +#define SW_TVE_DCLK_EN(x) HIWORD_UPDATE(x, 3, 3) +#define SW_DCLK_UPSAMPLE_EN_MASK HIWORD_MASK(2, 2) +#define SW_DCLK_UPSAMPLE_EN(x) HIWORD_UPDATE(x, 2, 2) +#define SW_TVE_MODE_MASK HIWORD_MASK(1, 1) +#define SW_TVE_MODE(x) HIWORD_UPDATE(x, 1, 1) +#define SW_TVE_EN_MASK HIWORD_MASK(0, 0) +#define SW_TVE_EN(x) HIWORD_UPDATE(x, 0, 0) +#define PLUMAGE_GRF_SOC_CON1 GRF_REG(0x0404) +#define PLUMAGE_GRF_SOC_CON2 GRF_REG(0x0408) +#define PLUMAGE_GRF_SOC_CON3 GRF_REG(0x040C) +#define VDAC_ENVBG_MASK HIWORD_MASK(12, 12) +#define VDAC_ENVBG(x) HIWORD_UPDATE(x, 12, 12) +#define VDAC_ENSC0_MASK HIWORD_MASK(11, 11) +#define VDAC_ENSC0(x) HIWORD_UPDATE(x, 11, 11) +#define VDAC_ENEXTREF_MASK HIWORD_MASK(10, 10) +#define VDAC_ENEXTREF(x) HIWORD_UPDATE(x, 10, 10) +#define VDAC_ENDAC0_MASK HIWORD_MASK(9, 9) +#define VDAC_ENDAC0(x) HIWORD_UPDATE(x, 9, 9) +#define VDAC_ENCTR2_MASK HIWORD_MASK(8, 8) +#define VDAC_ENCTR2(x) HIWORD_UPDATE(x, 8, 8) +#define VDAC_ENCTR1_MASK HIWORD_MASK(7, 7) +#define VDAC_ENCTR1(x) HIWORD_UPDATE(x, 7, 7) +#define VDAC_ENCTR0_MASK HIWORD_MASK(6, 6) +#define VDAC_ENCTR0(x) HIWORD_UPDATE(x, 6, 6) +#define VDAC_GAIN_MASK GENMASK(x, 5, 0) +#define VDAC_GAIN(x) HIWORD_UPDATE(x, 5, 0) +#define PLUMAGE_GRF_SOC_CON4 GRF_REG(0x0410) +#define PLUMAGE_GRF_SOC_STATUS GRF_REG(0x0480) +#define PLUMAGE_GRF_GPIO0_REN0 GRF_REG(0x0500) +#define PLUMAGE_GRF_GPIO0_REN1 GRF_REG(0x0504) +#define PLUMAGE_GRF_GPIO1_REN0 GRF_REG(0x0508) +#define GRF_MAX_REGISTER PLUMAGE_GRF_GPIO1_REN0 + +#define CRU_REG(x) ((x) + 0x140000) +#define CRU_SPLL_CON0 CRU_REG(0x0000) +#define POSTDIV1_MASK HIWORD_MASK(14, 12) +#define POSTDIV1(x) HIWORD_UPDATE(x, 14, 12) +#define FBDIV_MASK HIWORD_MASK(14, 12) +#define FBDIV(x) HIWORD_UPDATE(x, 14, 12) +#define CRU_SPLL_CON1 CRU_REG(0x0004) +#define PLLPD0_MASK HIWORD_MASK(13, 13) +#define PLLPD0(x) HIWORD_UPDATE(x, 13, 13) +#define PLL_LOCK BIT(10) +#define POSTDIV2_MASK HIWORD_MASK(8, 6) +#define POSTDIV2(x) HIWORD_UPDATE(x, 8, 6) +#define REFDIV_MASK HIWORD_MASK(5, 0) +#define REFDIV(x) HIWORD_UPDATE(x, 5, 0) +#define CRU_SPLL_CON2 CRU_REG(0x0008) +#define CRU_MODE_CON CRU_REG(0x0020) +#define CLK_SPLL_MODE_MASK HIWORD_MASK(2, 0) +#define CLK_SPLL_MODE(x) HIWORD_UPDATE(x, 2, 0) +#define CRU_CLKSEL_CON0 CRU_REG(0x0030) +#define CRU_CLKSEL_CON1 CRU_REG(0x0034) +#define DCLK_CVBS_4X_DIV_CON_MASK HIWORD_MASK(12, 8) +#define DCLK_CVBS_4X_DIV_CON(x) HIWORD_UPDATE(x, 12, 8) +#define CRU_CLKSEL_CON2 CRU_REG(0x0038) +#define CRU_CLKSEL_CON3 CRU_REG(0x003c) +#define CRU_GATE_CON0 CRU_REG(0x0040) +#define CRU_SOFTRST_CON0 CRU_REG(0x0050) +#define DRESETN_CVBS_1X_MASK HIWORD_MASK(10, 10) +#define DRESETN_CVBS_1X(x) HIWORD_UPDATE(x, 10, 10) +#define DRESETN_CVBS_4X_MASK HIWORD_MASK(9, 9) +#define DRESETN_CVBS_4X(x) HIWORD_UPDATE(x, 9, 9) +#define PRESETN_CVBS_MASK HIWORD_MASK(8, 8) +#define PRESETN_CVBS(x) HIWORD_UPDATE(x, 8, 8) +#define PRESETN_GRF_MASK HIWORD_MASK(3, 3) +#define PRESETN_GRF(x) HIWORD_UPDATE(x, 3, 3) +#define CRU_MAX_REGISTER CRU_SOFTRST_CON0 + +#define TVE_REG(x) ((x) + 0x10000) +#define BT656_DECODER_CTRL TVE_REG(0x3D00) +#define BT656_DECODER_CROP TVE_REG(0x3D04) +#define BT656_DECODER_SIZE TVE_REG(0x3D08) +#define BT656_DECODER_HTOTAL_HS_END TVE_REG(0x3D0C) +#define BT656_DECODER_VACT_ST_HACT_ST TVE_REG(0x3D10) +#define BT656_DECODER_VTOTAL_VS_END TVE_REG(0x3D14) +#define BT656_DECODER_VS_ST_END_F1 TVE_REG(0x3D18) +#define BT656_DECODER_DBG_REG TVE_REG(0x3D1C) +#define TVE_MODE_CTRL TVE_REG(0x3E00) +#define TVE_HOR_TIMING1 TVE_REG(0x3E04) +#define TVE_HOR_TIMING2 TVE_REG(0x3E08) +#define TVE_HOR_TIMING3 TVE_REG(0x3E0C) +#define TVE_SUB_CAR_FRQ TVE_REG(0x3E10) +#define TVE_LUMA_FILTER1 TVE_REG(0x3E14) +#define TVE_LUMA_FILTER2 TVE_REG(0x3E18) +#define TVE_LUMA_FILTER3 TVE_REG(0x3E1C) +#define TVE_LUMA_FILTER4 TVE_REG(0x3E20) +#define TVE_LUMA_FILTER5 TVE_REG(0x3E24) +#define TVE_LUMA_FILTER6 TVE_REG(0x3E28) +#define TVE_LUMA_FILTER7 TVE_REG(0x3E2C) +#define TVE_LUMA_FILTER8 TVE_REG(0x3E30) +#define TVE_IMAGE_POSITION TVE_REG(0x3E34) +#define TVE_ROUTING TVE_REG(0x3E38) +#define TVE_SYNC_ADJUST TVE_REG(0x3E50) +#define TVE_STATUS TVE_REG(0x3E54) +#define TVE_CTRL TVE_REG(0x3E68) +#define TVE_INTR_STATUS TVE_REG(0x3E6C) +#define TVE_INTR_EN TVE_REG(0x3E70) +#define TVE_INTR_CLR TVE_REG(0x3E74) +#define TVE_COLOR_BUSRT_SAT TVE_REG(0x3E78) +#define TVE_CHROMA_BANDWIDTH TVE_REG(0x3E8C) +#define TVE_BRIGHTNESS_CONTRAST TVE_REG(0x3E90) +#define TVE_ID TVE_REG(0x3E98) +#define TVE_REVISION TVE_REG(0x3E9C) +#define TVE_CLAMP TVE_REG(0x3EA0) +#define TVE_MAX_REGISTER TVE_CLAMP + +struct rk630 { + struct device *dev; + struct i2c_client *client; + struct regmap *grf; + struct regmap *cru; + struct regmap *tve; + struct gpio_desc *reset_gpio; +}; + +extern const struct regmap_config rk630_grf_regmap_config; +extern const struct regmap_config rk630_cru_regmap_config; +extern const struct regmap_config rk630_tve_regmap_config; + +int rk630_core_probe(struct rk630 *rk630); +int rk630_core_remove(struct rk630 *rk630); + +#endif