diff --git a/Documentation/devicetree/bindings/mfd/rk1000-core.txt b/Documentation/devicetree/bindings/mfd/rk1000-core.txt new file mode 100644 index 000000000000..17851897037b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rk1000-core.txt @@ -0,0 +1,24 @@ +RK1000 Multi-functional device + +The RK1000-CORE are RK1000 control register block. +The chip is connected to an i2c bus. + + +Required properties: +- compatible : "rockchip,rk1000-ctl" +- reg: I2C slave address +- reset-gpios : the reset pin +- clocks : phandle and clock specifier +- clock-names : "mclk" + +Example: + rk1000-ctl@40 { + compatible = "rockchip,rk1000-ctl"; + reg = <0x40>; + reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + clocks = <&cru SCLK_I2S_8CH_OUT>; + clock-names = "mclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_8ch_bus>; + status = "okay"; + }; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f40ec41008d1..7b4c6044bf56 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1457,6 +1457,13 @@ config MFD_WM831X_SPI config MFD_WM8350 bool +config MFD_RK1000 + bool "RK1000 CORE module support" + select MFD_CORE + help + if you say yes here you get support for the RK1000, with func as + TVEncoder or CODEC. + config MFD_WM8350_I2C bool "Wolfson Microelectronics WM8350 with I2C" select MFD_WM8350 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 50a9a21976d7..f57ceffd7fc0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -195,3 +195,4 @@ intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_FUSB_30X) += fusb302.o +obj-$(CONFIG_MFD_RK1000) += rk1000-core.o diff --git a/drivers/mfd/rk1000-core.c b/drivers/mfd/rk1000-core.c old mode 100755 new mode 100644 index 36ad89fc6280..c003ab05a773 --- a/drivers/mfd/rk1000-core.c +++ b/drivers/mfd/rk1000-core.c @@ -1,322 +1,181 @@ -#include -#include -#include -#include -#include -#include +/* + * Driver for rockchip rk1000 core controller + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd + * Author: + * Algea Cao + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#define RK1000_CORE_DBG 0 - -#if RK1000_CORE_DBG -#define DBG(x...) pr_info(x) -#else -#define DBG(x...) -#endif - -#define CTRL_ADC 0x00 -#define CTRL_CODEC 0x01 -#define CTRL_I2C 0x02 -#define CTRL_TVE 0x03 -#define RGB2CCIR_RESET 0x04 -#define ADC_START 0x05 +#define CTRL_ADC 0x00 +#define ADC_OFF 0x88 +#define CTRL_CODEC 0x01 +#define CODEC_OFF 0x0d +#define CTRL_I2C 0x02 +#define I2C_TIMEOUT_PERIOD 0x22 +#define CTRL_TVE 0x03 +#define TVE_OFF 0x00 struct rk1000 { struct i2c_client *client; struct device *dev; - struct dentry *debugfs_dir; - struct ioctrl io_power; - struct ioctrl io_reset; + struct regmap *regmap; + struct gpio_desc *io_reset; + struct clk *mclk; }; -static struct rk1000 *rk1000; -int cvbsmode = -1; +static int cvbsmode = -1; -void rk1000_reset_ctrl(int enable) -{ - DBG("rk1000_reset_ctrl\n"); - if (rk1000 && gpio_is_valid(rk1000->io_reset.gpio)) { - if (enable) { - gpio_set_value(rk1000->io_reset.gpio, - !(rk1000->io_reset.active)); - } else { - DBG("rk1000 reset pull low\n"); - gpio_set_value(rk1000->io_reset.gpio, - (rk1000->io_reset.active)); - } - } -} +static const struct mfd_cell rk1000_devs[] = { + { + .name = "rk1000-tve", + .of_compatible = "rockchip,rk1000-tve", + }, +}; -int rk1000_i2c_send(const u8 addr, const u8 reg, const u8 value) -{ - struct i2c_adapter *adap; - struct i2c_msg msg; - int ret; - char buf[2]; +static const struct regmap_range rk1000_ctl_volatile_ranges[] = { + { .range_min = 0x00, .range_max = 0x05 }, +}; - if (rk1000 == NULL || rk1000->client == NULL) { - DBG("rk1000 not init!\n"); - return -1; - } - adap = rk1000->client->adapter; - buf[0] = reg; - buf[1] = value; - msg.addr = addr; - msg.flags = rk1000->client->flags; - msg.len = 2; - msg.buf = buf; - msg.scl_rate = RK1000_I2C_RATE; - ret = i2c_transfer(adap, &msg, 1); - if (ret != 1) { - DBG("rk1000 control i2c write err,ret =%d\n", ret); - return -1; - } - return 0; -} - -int rk1000_i2c_recv(const u8 addr, const u8 reg, const char *buf) -{ - struct i2c_adapter *adap; - struct i2c_msg msgs[2]; - int ret; - - if (rk1000 == NULL || rk1000->client == NULL) { - DBG("rk1000 not init!\n"); - return -1; - } - adap = rk1000->client->adapter; - msgs[0].addr = addr; - msgs[0].flags = rk1000->client->flags; - msgs[0].len = 1; - msgs[0].buf = (unsigned char *)(®); - msgs[0].scl_rate = RK1000_I2C_RATE; - msgs[1].addr = addr; - msgs[1].flags = rk1000->client->flags | I2C_M_RD; - msgs[1].len = 1; - msgs[1].buf = (unsigned char *)buf; - msgs[1].scl_rate = RK1000_I2C_RATE; - ret = i2c_transfer(adap, msgs, 2); - return (ret == 2) ? 0 : -1; -} - -static ssize_t rk1000_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret = -1; - int i = 0; - unsigned char tv_encoder_regs[] = {0x00, 0x00, 0x00, 0x03, 0x00, 0x00}; - unsigned char tv_encoder_control_regs[] = {0x43, 0x01}; - - for (i = 0; i < sizeof(tv_encoder_regs); i++) { - ret = rk1000_i2c_recv(I2C_ADDR_TVE, i, buf); - pr_info("---%x--\n", buf[0]); - if (ret < 0) { - pr_err("rk1000_tv_write_block err!\n"); - return ret; - } - } - - for (i = 0; i < sizeof(tv_encoder_control_regs); i++) { - ret = rk1000_i2c_recv(I2C_ADDR_CTRL, i + 3, buf); - pr_info("cntrl---%x--\n", buf[0]); - if (ret < 0) { - pr_err("rk1000_control_write_block err!\n"); - return ret; - } - } - return 0; -} - -static DEVICE_ATTR(rkcontrl, S_IRUGO, rk1000_show, NULL); +static const struct regmap_access_table rk1000_ctl_reg_table = { + .yes_ranges = rk1000_ctl_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(rk1000_ctl_volatile_ranges), +}; +struct regmap_config rk1000_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &rk1000_ctl_reg_table, +}; static int __init bootloader_cvbs_setup(char *str) { - static int ret; + int ret = 0; - if (str) { - pr_info("cvbs init tve.format is %s\n", str); + if (str) ret = kstrtoint(str, 0, &cvbsmode); - } - return 0; + + return ret; } + early_param("tve.format", bootloader_cvbs_setup); -#ifdef CONFIG_PM -static int rk1000_control_suspend(struct device *dev) -{ - int ret; - - DBG("rk1000_control_suspend\n"); - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x22); - DBG("ret=0x%x\n", ret); - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x00); - DBG("ret=0x%x\n", ret); - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x07); - DBG("ret=0x%x\n", ret); - /* rk1000_reset_ctrl(0); */ - return 0; -} - -static int rk1000_control_resume(struct device *dev) -{ - int ret; - - /* rk1000_reset_ctrl(1); */ - DBG("rk1000_control_resume\n"); - /* ADC power off */ - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_ADC, 0x88); - DBG("ret=0x%x\n", ret); - #ifdef CONFIG_SND_SOC_RK1000 - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x00); - #else - ret = rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x0d); - #endif - DBG("ret=0x%x\n", ret); - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_I2C, 0x22); - DBG("ret=0x%x\n", ret); - /* rk1000_codec_reg_set(); */ - return 0; -} -#endif - - - static int rk1000_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *rk1000_np; - enum of_gpio_flags flags; int ret; - - DBG("[%s] start\n", __func__); - rk1000 = kmalloc(sizeof(*rk1000), GFP_KERNEL); - if (!rk1000) { - dev_err(&client->dev, ">> rk1000 core inf kmalloc fail!"); + struct rk1000 *rk1000 = devm_kzalloc(&client->dev, sizeof(*rk1000), + GFP_KERNEL); + if (!rk1000) return -ENOMEM; - } - memset(rk1000, 0, sizeof(struct rk1000)); rk1000->client = client; rk1000->dev = &client->dev; rk1000_np = rk1000->dev->of_node; + rk1000->regmap = devm_regmap_init_i2c(client, &rk1000_regmap_config); + if (IS_ERR(rk1000->regmap)) + return PTR_ERR(rk1000->regmap); + if (cvbsmode < 0) { /********Get reset pin***********/ - rk1000->io_reset.gpio = of_get_named_gpio_flags(rk1000_np, - "gpio-reset", - 0, &flags); - if (!gpio_is_valid(rk1000->io_reset.gpio)) { - DBG("invalid rk1000->io_reset.gpio: %d\n", - rk1000->io_reset.gpio); - ret = -1; - goto err; + rk1000->io_reset = devm_gpiod_get_optional(rk1000->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(rk1000->io_reset)) { + dev_err(rk1000->dev, "can't get rk1000 reset gpio\n"); + return PTR_ERR(rk1000->io_reset); } - ret = gpio_request(rk1000->io_reset.gpio, "rk1000-reset-io"); - if (ret != 0) { - DBG("gpio_request rk1000->io_reset.gpio invalid: %d\n", - rk1000->io_reset.gpio); - goto err; - } - rk1000->io_reset.active = !(flags & OF_GPIO_ACTIVE_LOW); - gpio_direction_output(rk1000->io_reset.gpio, - !(rk1000->io_reset.active)); + + gpiod_set_value(rk1000->io_reset, 0); usleep_range(500, 1000); - /********Get power pin***********/ - rk1000->io_power.gpio = of_get_named_gpio_flags(rk1000_np, - "gpio-power", - 0, &flags); - if (gpio_is_valid(rk1000->io_power.gpio)) { - ret = gpio_request(rk1000->io_power.gpio, - "rk1000-power-io"); - if (ret != 0) { - DBG("request gpio for power invalid: %d\n", - rk1000->io_power.gpio); - goto err; - } - rk1000->io_power.active = - !(flags & OF_GPIO_ACTIVE_LOW); - gpio_direction_output(rk1000->io_power.gpio, - rk1000->io_power.active); - } - /********rk1000 reset***********/ - gpio_set_value(rk1000->io_reset.gpio, - rk1000->io_reset.active); - usleep_range(5000, 10000); - gpio_set_value(rk1000->io_reset.gpio, - !(rk1000->io_reset.active)); + gpiod_set_value(rk1000->io_reset, 1); + usleep_range(500, 1000); + gpiod_set_value(rk1000->io_reset, 0); } - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_ADC, 0x88); - #ifdef CONFIG_SND_SOC_RK1000 - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x00); - #else - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_CODEC, 0x0d); - #endif - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_I2C, 0x22); + rk1000->mclk = devm_clk_get(rk1000->dev, "mclk"); + if (IS_ERR(rk1000->mclk)) { + dev_err(rk1000->dev, "get mclk err\n"); + return PTR_ERR(rk1000->mclk); + } + + ret = clk_prepare_enable(rk1000->mclk); + if (ret < 0) { + dev_err(rk1000->dev, "prepare mclk err\n"); + goto clk_err; + } + + regmap_write(rk1000->regmap, CTRL_ADC, ADC_OFF); + regmap_write(rk1000->regmap, CTRL_CODEC, CODEC_OFF); + regmap_write(rk1000->regmap, CTRL_I2C, I2C_TIMEOUT_PERIOD); if (cvbsmode < 0) - rk1000_i2c_send(I2C_ADDR_CTRL, CTRL_TVE, 0x00); + regmap_write(rk1000->regmap, CTRL_TVE, TVE_OFF); - device_create_file(&client->dev, &dev_attr_rkcontrl); - DBG("rk1000 probe ok\n"); + ret = mfd_add_devices(rk1000->dev, -1, rk1000_devs, + ARRAY_SIZE(rk1000_devs), NULL, 0, NULL); + if (ret) { + dev_err(rk1000->dev, "rk1000 mfd_add_devices failed\n"); + goto mfd_add_err; + } + + i2c_set_clientdata(client, rk1000); + dev_dbg(rk1000->dev, "rk1000 probe ok!\n"); return 0; -err: - kfree(rk1000); - rk1000 = NULL; + +mfd_add_err: + mfd_remove_devices(rk1000->dev); +clk_err: + clk_disable_unprepare(rk1000->mclk); return ret; } static int rk1000_remove(struct i2c_client *client) { + struct rk1000 *rk1000 = i2c_get_clientdata(client); + + clk_disable_unprepare(rk1000->mclk); + mfd_remove_devices(rk1000->dev); + return 0; } static const struct i2c_device_id rk1000_id[] = { - { "rk1000_control", 0 }, + { "rk1000-ctl", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rk1000_id); -static const struct dev_pm_ops rockchip_rk1000_pm_ops = { - .suspend_late = rk1000_control_suspend, - .resume_early = rk1000_control_resume, +static const struct of_device_id rk1000_ctl_dt_ids[] = { + { .compatible = "rockchip,rk1000-ctl" }, + { } }; +MODULE_DEVICE_TABLE(of, rk1000_ctl_dt_ids); + static struct i2c_driver rk1000_driver = { .driver = { - .name = "rk1000_control", - #ifdef CONFIG_PM - .pm = &rockchip_rk1000_pm_ops, - #endif + .name = "rk1000-ctl", }, .probe = rk1000_probe, .remove = rk1000_remove, .id_table = rk1000_id, }; +module_i2c_driver(rk1000_driver); -static int __init rk1000_init(void) -{ - return i2c_add_driver(&rk1000_driver); -} - -static void __exit rk1000_exit(void) -{ - i2c_del_driver(&rk1000_driver); -} - -fs_initcall_sync(rk1000_init); -module_exit(rk1000_exit); - - -MODULE_DESCRIPTION("RK1000 control driver"); -MODULE_AUTHOR("Rock-chips, "); +MODULE_DESCRIPTION("RK1000 core control driver"); +MODULE_AUTHOR("Algea Cao "); MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/rk1000.h b/include/linux/mfd/rk1000.h deleted file mode 100755 index 606820da7489..000000000000 --- a/include/linux/mfd/rk1000.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __RK1000_H__ -#define __RK1000_H__ - -#define I2C_ADDR_CTRL 0x40 -#define I2C_ADDR_TVE 0x42 - -#define RK1000_I2C_RATE (100*1000) - -struct ioctrl { - int gpio; - int active; -}; - -int rk1000_i2c_send(const u8 addr, const u8 reg, const u8 value); -int rk1000_i2c_recv(const u8 addr, const u8 reg, const char *buf); - -#endif