diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 15:35:35 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 15:35:35 (GMT) |
commit | d042380886fb2fc6c4b0fcfe1214ba473769a8e9 (patch) | |
tree | 61e29ff167e0f83f67930ee9911062415030e1ef /drivers/mfd/rk808.c | |
parent | 3477d168ba61c5b0ca42d3d4642f3463609a5417 (diff) | |
parent | b8d336ed90f541097a2ce583be430bb3e895dfbd (diff) | |
download | linux-d042380886fb2fc6c4b0fcfe1214ba473769a8e9.tar.xz |
Merge tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core framework:
- Add the MFD bindings doc to MAINTAINERS
New drivers:
- X-Powers AC100 Audio CODEC and RTC
- TI LP873x PMIC
- Rockchip RK808 PMIC
- Samsung Exynos Low Power Audio
New device support:
- Add support for STMPE1600 variant to stmpe
- Add support for PM8018 PMIC to pm8921-core
- Add support for AXP806 PMIC in axp20x
- Add support for AXP209 GPIO in axp20x
New functionality:
- Add support for Reset to all STMPE variants
- Add support for MKBP event support to cros_ec
- Add support for USB to intel_soc_pmic_bxtwc
- Add support for IRQs and Power Button to tps65217
Fix-ups:
- Clean-up defunct author emails (da9063, max14577)
- Kconfig fixups (wm8350-i2c, as37220
- Constify (altera-a10sr, sm501)
- Supply PCI IDs (intel-lpss-pci)
- Improve clocking (qcom_rpm)
- Fix IRQ probing (ucb1x00-core)
- Ensure fault log is cleared (da9052)
- Remove NO_IRQ check (ucb1x00-core)
- Supply I2C properties (intel-lpss-acpi, intel-lpss-pci)
- Non standard declaration (tps65217, max8997-irq)
- Remove unused code (lp873x, db8500-prcmu, ab8500-debugfs,
cros_ec_spi)
- Make non-modular (altera-a10sr, intel_msic, smsc-ece1099,
sun6i-prcm, twl-core)
- OF bindings (ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x,
lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona)
Bugfixes:
- Release OF pointer (qcom_rpm)
- Avoid double shifting in suspend/resume (88pm80x)
- Fix 'defined but not used' error (exynos-lpass)
- Fix 'sleeping whilst attomic' (atmel-hlcdc)"
* tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits)
mfd: arizona: Handle probe deferral for reset GPIO
mfd: arizona: Remove arizona_of_get_named_gpio helper function
mfd: arizona: Add DT options for max_channels_clocked and PDM speaker config
mfd: twl6040: Register child device for twl6040-pdmclk
mfd: cros_ec_spi: Remove unused variable 'request'
mfd: omap-usb-host: Return value is not 'const int'
mfd: ab8500-debugfs: Remove 'weak' function suspend_test_wake_cause_interrupt_is_mine()
mfd: ab8500-debugfs: Remove ab8500_dump_all_banks_to_mem()
mfd: db8500-prcmu: Remove unused *prcmu_set_ddr_opp() calls
mfd: ab8500-debugfs: Prevent initialised field from being over-written
mfd: max8997-irq: 'inline' should be at the beginning of the declaration
mfd: rk808: Fix RK818_IRQ_DISCHG_ILIM initializer
mfd: tps65217: Fix nonstandard declaration
mfd: lp873x: Remove unused mutex lock from struct lp873x
mfd: atmel-hlcdc: Do not sleep in atomic context
mfd: exynos-lpass: Mark PM functions as __maybe_unused
mfd: intel-lpss: Add default I2C device properties for Apollo Lake
mfd: twl-core: Make it explicitly non-modular
mfd: sun6i-prcm: Make it explicitly non-modular
mfd: smsc-ece1099: Make it explicitly non-modular
...
Diffstat (limited to 'drivers/mfd/rk808.c')
-rw-r--r-- | drivers/mfd/rk808.c | 226 |
1 files changed, 195 insertions, 31 deletions
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 49d7f62..0f8acc5 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -1,11 +1,15 @@ /* - * MFD core driver for Rockchip RK808 + * MFD core driver for Rockchip RK808/RK818 * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * * Author: Chris Zhong <zyw@rock-chips.com> * Author: Zhang Qing <zhangqing@rock-chips.com> * + * Copyright (C) 2016 PHYTEC Messtechnik GmbH + * + * Author: Wadim Egorov <w.egorov@phytec.de> + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -21,6 +25,7 @@ #include <linux/mfd/rk808.h> #include <linux/mfd/core.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/regmap.h> struct rk808_reg_data { @@ -57,6 +62,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg) 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 rk808_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -79,11 +92,21 @@ static const struct mfd_cell rk808s[] = { { .name = "rk808-rtc", .num_resources = ARRAY_SIZE(rtc_resources), - .resources = &rtc_resources[0], + .resources = rtc_resources, }, }; -static const struct rk808_reg_data pre_init_reg[] = { +static const struct mfd_cell rk818s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = rtc_resources, + }, +}; + +static const struct rk808_reg_data rk808_pre_init_reg[] = { { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA }, { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA }, { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA }, @@ -94,6 +117,24 @@ static const struct rk808_reg_data pre_init_reg[] = { VB_LO_SEL_3500MV }, }; +static const struct rk808_reg_data rk818_pre_init_reg[] = { + /* improve efficiency */ + { RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA }, + { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA }, + { RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA }, + { RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK, + RK818_USB_ILMIN_2000MA }, + /* close charger when usb lower then 3.4V */ + { RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK, + (0x7 << 4) }, + /* no action when vref */ + { RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL }, + /* enable HDMI 5V */ + { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN }, + { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT | + VB_LO_SEL_3500MV }, +}; + static const struct regmap_irq rk808_irqs[] = { /* INT_STS */ [RK808_IRQ_VOUT_LO] = { @@ -136,6 +177,76 @@ static const struct regmap_irq rk808_irqs[] = { }, }; +static const struct regmap_irq rk818_irqs[] = { + /* INT_STS */ + [RK818_IRQ_VOUT_LO] = { + .mask = RK818_IRQ_VOUT_LO_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_VB_LO] = { + .mask = RK818_IRQ_VB_LO_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_PWRON] = { + .mask = RK818_IRQ_PWRON_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_PWRON_LP] = { + .mask = RK818_IRQ_PWRON_LP_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_HOTDIE] = { + .mask = RK818_IRQ_HOTDIE_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_RTC_ALARM] = { + .mask = RK818_IRQ_RTC_ALARM_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_RTC_PERIOD] = { + .mask = RK818_IRQ_RTC_PERIOD_MSK, + .reg_offset = 0, + }, + [RK818_IRQ_USB_OV] = { + .mask = RK818_IRQ_USB_OV_MSK, + .reg_offset = 0, + }, + + /* INT_STS2 */ + [RK818_IRQ_PLUG_IN] = { + .mask = RK818_IRQ_PLUG_IN_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_PLUG_OUT] = { + .mask = RK818_IRQ_PLUG_OUT_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_CHG_OK] = { + .mask = RK818_IRQ_CHG_OK_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_CHG_TE] = { + .mask = RK818_IRQ_CHG_TE_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_CHG_TS1] = { + .mask = RK818_IRQ_CHG_TS1_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_TS2] = { + .mask = RK818_IRQ_TS2_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_CHG_CVTLIM] = { + .mask = RK818_IRQ_CHG_CVTLIM_MSK, + .reg_offset = 1, + }, + [RK818_IRQ_DISCHG_ILIM] = { + .mask = RK818_IRQ_DISCHG_ILIM_MSK, + .reg_offset = 1, + }, +}; + static struct regmap_irq_chip rk808_irq_chip = { .name = "rk808", .irqs = rk808_irqs, @@ -148,6 +259,18 @@ static struct regmap_irq_chip rk808_irq_chip = { .init_ack_masked = true, }; +static struct regmap_irq_chip rk818_irq_chip = { + .name = "rk818", + .irqs = rk818_irqs, + .num_irqs = ARRAY_SIZE(rk818_irqs), + .num_regs = 2, + .irq_reg_stride = 2, + .status_base = RK818_INT_STS_REG1, + .mask_base = RK818_INT_STS_MSK_REG1, + .ack_base = RK818_INT_STS_REG1, + .init_ack_masked = true, +}; + static struct i2c_client *rk808_i2c_client; static void rk808_device_shutdown(void) { @@ -167,55 +290,100 @@ static void rk808_device_shutdown(void) dev_err(&rk808_i2c_client->dev, "power off error!\n"); } +static const struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk808" }, + { .compatible = "rockchip,rk818" }, + { }, +}; +MODULE_DEVICE_TABLE(of, rk808_of_match); + static int rk808_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *np = client->dev.of_node; struct rk808 *rk808; + const struct rk808_reg_data *pre_init_reg; + const struct mfd_cell *cells; + int nr_pre_init_regs; + int nr_cells; int pm_off = 0; int ret; int i; - if (!client->irq) { - dev_err(&client->dev, "No interrupt support, no core IRQ\n"); - return -EINVAL; - } - rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL); if (!rk808) return -ENOMEM; - rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config); + rk808->variant = i2c_smbus_read_word_data(client, RK808_ID_MSB); + if (rk808->variant < 0) { + dev_err(&client->dev, "Failed to read the chip id at 0x%02x\n", + RK808_ID_MSB); + return rk808->variant; + } + + dev_dbg(&client->dev, "Chip id: 0x%x\n", (unsigned int)rk808->variant); + + switch (rk808->variant) { + case RK808_ID: + rk808->regmap_cfg = &rk808_regmap_config; + rk808->regmap_irq_chip = &rk808_irq_chip; + pre_init_reg = rk808_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg); + cells = rk808s; + nr_cells = ARRAY_SIZE(rk808s); + break; + case RK818_ID: + rk808->regmap_cfg = &rk818_regmap_config; + rk808->regmap_irq_chip = &rk818_irq_chip; + pre_init_reg = rk818_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg); + cells = rk818s; + nr_cells = ARRAY_SIZE(rk818s); + break; + default: + dev_err(&client->dev, "Unsupported RK8XX ID %lu\n", + rk808->variant); + return -EINVAL; + } + + rk808->i2c = client; + i2c_set_clientdata(client, rk808); + + rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg); if (IS_ERR(rk808->regmap)) { dev_err(&client->dev, "regmap initialization failed\n"); return PTR_ERR(rk808->regmap); } - for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) { - ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr, - pre_init_reg[i].mask, - pre_init_reg[i].value); - if (ret) { - dev_err(&client->dev, - "0x%x write err\n", pre_init_reg[i].addr); - return ret; - } + if (!client->irq) { + dev_err(&client->dev, "No interrupt support, no core IRQ\n"); + return -EINVAL; } ret = regmap_add_irq_chip(rk808->regmap, client->irq, IRQF_ONESHOT, -1, - &rk808_irq_chip, &rk808->irq_data); + rk808->regmap_irq_chip, &rk808->irq_data); if (ret) { dev_err(&client->dev, "Failed to add irq_chip %d\n", ret); return ret; } - rk808->i2c = client; - i2c_set_clientdata(client, rk808); + for (i = 0; i < nr_pre_init_regs; i++) { + ret = regmap_update_bits(rk808->regmap, + pre_init_reg[i].addr, + pre_init_reg[i].mask, + pre_init_reg[i].value); + if (ret) { + dev_err(&client->dev, + "0x%x write err\n", + pre_init_reg[i].addr); + return ret; + } + } - ret = devm_mfd_add_devices(&client->dev, -1, - rk808s, ARRAY_SIZE(rk808s), NULL, 0, - regmap_irq_get_domain(rk808->irq_data)); + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + cells, nr_cells, NULL, 0, + regmap_irq_get_domain(rk808->irq_data)); if (ret) { dev_err(&client->dev, "failed to add MFD devices %d\n", ret); goto err_irq; @@ -245,14 +413,9 @@ static int rk808_remove(struct i2c_client *client) return 0; } -static const struct of_device_id rk808_of_match[] = { - { .compatible = "rockchip,rk808" }, - { }, -}; -MODULE_DEVICE_TABLE(of, rk808_of_match); - static const struct i2c_device_id rk808_ids[] = { { "rk808" }, + { "rk818" }, { }, }; MODULE_DEVICE_TABLE(i2c, rk808_ids); @@ -272,4 +435,5 @@ module_i2c_driver(rk808_i2c_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>"); -MODULE_DESCRIPTION("RK808 PMIC driver"); +MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>"); +MODULE_DESCRIPTION("RK808/RK818 PMIC driver"); |