From bce841cc7fc214761e7b3ef4ec5b3921ed264e07 Mon Sep 17 00:00:00 2001 From: "algea.cao" Date: Sat, 15 Jul 2017 12:08:49 +0800 Subject: [PATCH] mfd: rk1000: update mfd rk1000 core driver RK1000's control register block need mclk for i2c communication. So mclk should be enabled in advance. RK1000's control register block should be registered before RK1000 TVE. Change-Id: Iba9a2a410fe927666072f8d246995462a860ec3a Signed-off-by: Algea Cao --- .../devicetree/bindings/mfd/rk1000-core.txt | 24 ++ drivers/mfd/Kconfig | 7 + drivers/mfd/Makefile | 1 + drivers/mfd/rk1000-core.c | 371 ++++++------------ include/linux/mfd/rk1000.h | 17 - 5 files changed, 147 insertions(+), 273 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/rk1000-core.txt mode change 100755 => 100644 drivers/mfd/rk1000-core.c delete mode 100755 include/linux/mfd/rk1000.h 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