mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
- Core Frameworks
- 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, as3722
- 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
- Bug Fixes
- 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
-----BEGIN PGP SIGNATURE-----
iQIcBAABCAAGBQJX9giOAAoJEFGvii+H/Hdh8aEP/iiHosBZsksZ4we8KAdoXkxi
x5nnJvS9+4b5yaasSiN8e2xs9YMOlHu1CNZDZ3RJZ+rLusdVeg5ju5p5WED83pvi
ltiPMhyqruM3d0rieTRHxeJFmmEf2exwKV3Y+5lo9586dFfJrmGp2AxScId4TtwP
CcsjwYRx/WvVfWrv1xWsjd9b1RDlWglt3dcVhdKAQbvPPOy5O4ymXNMFs0DuFyZ+
2A16sw7hdYenXSvAHlZzS5IqXP9JEeosu3O/mUUZKF3PO55t+KbQBGZiwXoal4gp
1dwrdBjlrZaHcDa5Ra9x+jQ2kxIkyUT44CXKAHa7llTfZQkZIgnv/fWUhB8C5JxU
iaqnN9rWQ2MNjt3Us/n1TSJH2kEnSNbzrQixE0n8yjIBsZePWlW2ZpWYRF7GPG2i
2pB8oNz/NdDkKWdosR3ArnseNOKVcC+GtD+mHk0aKMPghPq+gDIRrdM0CFyWeIZE
w/Cf+HHZPR0O1VuYZ9bHIhbgnEbz5xUADOtBAdppIBQiNEI/G9lJpG6Ft4FTQoPi
CIbnnB/wxxMaEl85rUPYGkxQniuUI5f0tMv3k2ZtAZMKcqn6iXtiIOuXceM2vUdy
ze1uddH4HuHLcrJT5x+J72XJL6RXzZKxOqd0b7BcXnvMVFJrWgleH1JQ2WqazAEW
il1u28IkFusm/BW/0dps
=Ja7p
-----END PGP SIGNATURE-----
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
...
This commit is contained in:
commit
d042380886
80 changed files with 3111 additions and 445 deletions
|
|
@ -50,7 +50,7 @@ config MFD_AS3711
|
|||
Support for the AS3711 PMIC from AMS
|
||||
|
||||
config MFD_AS3722
|
||||
bool "ams AS3722 Power Management IC"
|
||||
tristate "ams AS3722 Power Management IC"
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
|
|
@ -112,6 +112,16 @@ config MFD_BCM590XX
|
|||
help
|
||||
Support for the BCM590xx PMUs from Broadcom
|
||||
|
||||
config MFD_AC100
|
||||
tristate "X-Powers AC100"
|
||||
select MFD_CORE
|
||||
depends on SUNXI_RSB
|
||||
help
|
||||
If you say Y here you get support for the X-Powers AC100 audio codec
|
||||
IC.
|
||||
This driver include only the core APIs. You have to select individual
|
||||
components like codecs or RTC under the corresponding menus.
|
||||
|
||||
config MFD_AXP20X
|
||||
tristate
|
||||
select MFD_CORE
|
||||
|
|
@ -281,6 +291,14 @@ config MFD_DLN2
|
|||
etc. must be enabled in order to use the functionality of
|
||||
the device.
|
||||
|
||||
config MFD_EXYNOS_LPASS
|
||||
tristate "Samsung Exynos SoC Low Power Audio Subsystem"
|
||||
select MFD_CORE
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Select this option to enable support for Samsung Exynos Low Power
|
||||
Audio Subsystem.
|
||||
|
||||
config MFD_MC13XXX
|
||||
tristate
|
||||
depends on (SPI_MASTER || I2C)
|
||||
|
|
@ -844,13 +862,13 @@ config MFD_RC5T583
|
|||
different functionality of the device.
|
||||
|
||||
config MFD_RK808
|
||||
tristate "Rockchip RK808 Power Management chip"
|
||||
tristate "Rockchip RK808/RK818 Power Management Chip"
|
||||
depends on I2C && OF
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
If you say yes here you get support for the RK808
|
||||
If you say yes here you get support for the RK808 and RK818
|
||||
Power Management chips.
|
||||
This driver provides common support for accessing the device
|
||||
through I2C interface. The device supports multiple sub-devices
|
||||
|
|
@ -1206,6 +1224,7 @@ config MFD_TPS65217
|
|||
depends on I2C
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
If you say yes here you get support for the TPS65217 series of
|
||||
Power Management / White LED chips.
|
||||
|
|
@ -1555,6 +1574,7 @@ config MFD_WM8350
|
|||
config MFD_WM8350_I2C
|
||||
bool "Wolfson Microelectronics WM8350 with I2C"
|
||||
select MFD_WM8350
|
||||
select REGMAP_I2C
|
||||
depends on I2C=y
|
||||
help
|
||||
The WM8350 is an integrated audio and power management
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
|||
obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
|
||||
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
|
||||
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
|
||||
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
|
||||
|
|
@ -114,6 +115,8 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
|
|||
obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
|
||||
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
|
||||
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
|
||||
|
||||
obj-$(CONFIG_MFD_AC100) += ac100.o
|
||||
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
|
||||
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
|
||||
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
|
||||
|
|
|
|||
|
|
@ -153,14 +153,14 @@ static struct hwreg_cfg hwreg_cfg = {
|
|||
|
||||
#define AB8500_NAME_STRING "ab8500"
|
||||
#define AB8500_ADC_NAME_STRING "gpadc"
|
||||
#define AB8500_NUM_BANKS 24
|
||||
#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
|
||||
|
||||
#define AB8500_REV_REG 0x80
|
||||
|
||||
static struct ab8500_prcmu_ranges *debug_ranges;
|
||||
|
||||
static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
||||
[0x0] = {
|
||||
[AB8500_M_FSM_RANK] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
|
|
@ -315,7 +315,7 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
|||
},
|
||||
},
|
||||
},
|
||||
[0x9] = {
|
||||
[AB8500_RESERVED] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
|
|
@ -386,24 +386,6 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
|||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEVELOPMENT] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x00,
|
||||
.last = 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEBUG] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x05,
|
||||
.last = 0x07,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_AUDIO] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
|
|
@ -463,19 +445,29 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
|||
},
|
||||
},
|
||||
},
|
||||
[0x11] = {
|
||||
[AB8500_DEVELOPMENT] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x00,
|
||||
.last = 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEBUG] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x05,
|
||||
.last = 0x07,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_PROD_TEST] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x12] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x13] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x14] = {
|
||||
[AB8500_STE_TEST] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
|
|
@ -1382,60 +1374,6 @@ void ab8500_dump_all_banks(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Space for 500 registers. */
|
||||
#define DUMP_MAX_REGS 700
|
||||
static struct ab8500_register_dump
|
||||
{
|
||||
u8 bank;
|
||||
u8 reg;
|
||||
u8 value;
|
||||
} ab8500_complete_register_dump[DUMP_MAX_REGS];
|
||||
|
||||
/* This shall only be called upon kernel panic! */
|
||||
void ab8500_dump_all_banks_to_mem(void)
|
||||
{
|
||||
int i, r = 0;
|
||||
u8 bank;
|
||||
int err = 0;
|
||||
|
||||
pr_info("Saving all ABB registers for crash analysis.\n");
|
||||
|
||||
for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
|
||||
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
|
||||
u8 reg;
|
||||
|
||||
for (reg = debug_ranges[bank].range[i].first;
|
||||
reg <= debug_ranges[bank].range[i].last;
|
||||
reg++) {
|
||||
u8 value;
|
||||
|
||||
err = prcmu_abb_read(bank, reg, &value, 1);
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
ab8500_complete_register_dump[r].bank = bank;
|
||||
ab8500_complete_register_dump[r].reg = reg;
|
||||
ab8500_complete_register_dump[r].value = value;
|
||||
|
||||
r++;
|
||||
|
||||
if (r >= DUMP_MAX_REGS) {
|
||||
pr_err("%s: too many register to dump!\n",
|
||||
__func__);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (err >= 0)
|
||||
pr_info("Saved all ABB registers.\n");
|
||||
else
|
||||
pr_info("Failed to save all ABB registers.\n");
|
||||
}
|
||||
|
||||
static int ab8500_all_banks_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *s;
|
||||
|
|
@ -1584,18 +1522,10 @@ static u32 num_interrupts[AB8500_MAX_NR_IRQS];
|
|||
static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
|
||||
static int num_interrupt_lines;
|
||||
|
||||
bool __attribute__((weak)) suspend_test_wake_cause_interrupt_is_mine(u32 my_int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ab8500_debug_register_interrupt(int line)
|
||||
{
|
||||
if (line < num_interrupt_lines) {
|
||||
if (line < num_interrupt_lines)
|
||||
num_interrupts[line]++;
|
||||
if (suspend_test_wake_cause_interrupt_is_mine(irq_ab8500))
|
||||
num_wake_interrupts[line]++;
|
||||
}
|
||||
}
|
||||
|
||||
static int ab8500_interrupts_print(struct seq_file *s, void *p)
|
||||
|
|
|
|||
137
drivers/mfd/ac100.c
Normal file
137
drivers/mfd/ac100.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* MFD core driver for X-Powers' AC100 Audio Codec IC
|
||||
*
|
||||
* The AC100 is a highly integrated audio codec and RTC subsystem designed
|
||||
* for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
|
||||
* a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
|
||||
* 3 clock outputs.
|
||||
*
|
||||
* The audio codec and RTC parts are completely separate, sharing only the
|
||||
* host interface for access to its registers.
|
||||
*
|
||||
* Copyright (2016) Chen-Yu Tsai
|
||||
*
|
||||
* Author: Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ac100.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sunxi-rsb.h>
|
||||
|
||||
static const struct regmap_range ac100_writeable_ranges[] = {
|
||||
regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_I2S_SR_CTRL),
|
||||
regmap_reg_range(AC100_I2S1_CLK_CTRL, AC100_I2S1_MXR_GAIN),
|
||||
regmap_reg_range(AC100_I2S2_CLK_CTRL, AC100_I2S2_MXR_GAIN),
|
||||
regmap_reg_range(AC100_I2S3_CLK_CTRL, AC100_I2S3_SIG_PATH_CTRL),
|
||||
regmap_reg_range(AC100_ADC_DIG_CTRL, AC100_ADC_VOL_CTRL),
|
||||
regmap_reg_range(AC100_HMIC_CTRL1, AC100_HMIC_STATUS),
|
||||
regmap_reg_range(AC100_DAC_DIG_CTRL, AC100_DAC_MXR_GAIN),
|
||||
regmap_reg_range(AC100_ADC_APC_CTRL, AC100_LINEOUT_CTRL),
|
||||
regmap_reg_range(AC100_ADC_DAP_L_CTRL, AC100_ADC_DAP_OPT),
|
||||
regmap_reg_range(AC100_DAC_DAP_CTRL, AC100_DAC_DAP_OPT),
|
||||
regmap_reg_range(AC100_ADC_DAP_ENA, AC100_DAC_DAP_ENA),
|
||||
regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL2),
|
||||
regmap_reg_range(AC100_SRC2_CTRL1, AC100_SRC2_CTRL2),
|
||||
regmap_reg_range(AC100_CLK32K_ANALOG_CTRL, AC100_CLKOUT_CTRL3),
|
||||
regmap_reg_range(AC100_RTC_RST, AC100_RTC_UPD),
|
||||
regmap_reg_range(AC100_ALM_INT_ENA, AC100_ALM_INT_STA),
|
||||
regmap_reg_range(AC100_ALM_SEC, AC100_RTC_GP(15)),
|
||||
};
|
||||
|
||||
static const struct regmap_range ac100_volatile_ranges[] = {
|
||||
regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_PLL_CTRL2),
|
||||
regmap_reg_range(AC100_HMIC_STATUS, AC100_HMIC_STATUS),
|
||||
regmap_reg_range(AC100_ADC_DAP_L_STA, AC100_ADC_DAP_L_STA),
|
||||
regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL1),
|
||||
regmap_reg_range(AC100_SRC1_CTRL3, AC100_SRC2_CTRL1),
|
||||
regmap_reg_range(AC100_SRC2_CTRL3, AC100_SRC2_CTRL4),
|
||||
regmap_reg_range(AC100_RTC_RST, AC100_RTC_RST),
|
||||
regmap_reg_range(AC100_RTC_SEC, AC100_ALM_INT_STA),
|
||||
regmap_reg_range(AC100_ALM_SEC, AC100_ALM_UPD),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ac100_writeable_table = {
|
||||
.yes_ranges = ac100_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ac100_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ac100_volatile_table = {
|
||||
.yes_ranges = ac100_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ac100_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config ac100_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.wr_table = &ac100_writeable_table,
|
||||
.volatile_table = &ac100_volatile_table,
|
||||
.max_register = AC100_RTC_GP(15),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static struct mfd_cell ac100_cells[] = {
|
||||
{
|
||||
.name = "ac100-codec",
|
||||
.of_compatible = "x-powers,ac100-codec",
|
||||
}, {
|
||||
.name = "ac100-rtc",
|
||||
.of_compatible = "x-powers,ac100-rtc",
|
||||
},
|
||||
};
|
||||
|
||||
static int ac100_rsb_probe(struct sunxi_rsb_device *rdev)
|
||||
{
|
||||
struct ac100_dev *ac100;
|
||||
int ret;
|
||||
|
||||
ac100 = devm_kzalloc(&rdev->dev, sizeof(*ac100), GFP_KERNEL);
|
||||
if (!ac100)
|
||||
return -ENOMEM;
|
||||
|
||||
ac100->dev = &rdev->dev;
|
||||
sunxi_rsb_device_set_drvdata(rdev, ac100);
|
||||
|
||||
ac100->regmap = devm_regmap_init_sunxi_rsb(rdev, &ac100_regmap_config);
|
||||
if (IS_ERR(ac100->regmap)) {
|
||||
ret = PTR_ERR(ac100->regmap);
|
||||
dev_err(ac100->dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(ac100->dev, PLATFORM_DEVID_NONE, ac100_cells,
|
||||
ARRAY_SIZE(ac100_cells), NULL, 0, NULL);
|
||||
if (ret) {
|
||||
dev_err(ac100->dev, "failed to add MFD devices: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ac100_of_match[] = {
|
||||
{ .compatible = "x-powers,ac100" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ac100_of_match);
|
||||
|
||||
static struct sunxi_rsb_driver ac100_rsb_driver = {
|
||||
.driver = {
|
||||
.name = "ac100",
|
||||
.of_match_table = of_match_ptr(ac100_of_match),
|
||||
},
|
||||
.probe = ac100_rsb_probe,
|
||||
};
|
||||
module_sunxi_rsb_driver(ac100_rsb_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
|
||||
MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -23,6 +23,7 @@ static const struct mfd_cell act8945a_devs[] = {
|
|||
},
|
||||
{
|
||||
.name = "act8945a-charger",
|
||||
.of_compatible = "active-semi,act8945a-charger",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* Altera Arria10 DevKit System Resource MFD Driver
|
||||
*
|
||||
* Author: Thor Thayer <tthayer@opensource.altera.com>
|
||||
*
|
||||
* Copyright Intel Corporation (C) 2014-2016. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
|
@ -20,7 +24,7 @@
|
|||
|
||||
#include <linux/mfd/altera-a10sr.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
|
|
@ -94,7 +98,7 @@ static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg)
|
|||
}
|
||||
}
|
||||
|
||||
const struct regmap_config altr_a10sr_regmap_config = {
|
||||
static const struct regmap_config altr_a10sr_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
|
|
@ -152,7 +156,6 @@ static const struct of_device_id altr_a10sr_spi_of_match[] = {
|
|||
{ .compatible = "altr,a10sr" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match);
|
||||
|
||||
static struct spi_driver altr_a10sr_spi_driver = {
|
||||
.probe = altr_a10sr_spi_probe,
|
||||
|
|
@ -161,9 +164,4 @@ static struct spi_driver altr_a10sr_spi_driver = {
|
|||
.of_match_table = of_match_ptr(altr_a10sr_spi_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_spi_driver(altr_a10sr_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Thor Thayer <[email protected]>");
|
||||
MODULE_DESCRIPTION("Altera Arria10 DevKit System Resource MFD Driver");
|
||||
builtin_driver(altr_a10sr_spi_driver, spi_register_driver)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
|
|
@ -49,7 +50,15 @@ int arizona_clk32k_enable(struct arizona *arizona)
|
|||
case ARIZONA_32KZ_MCLK1:
|
||||
ret = pm_runtime_get_sync(arizona->dev);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
goto err_ref;
|
||||
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
|
||||
if (ret != 0)
|
||||
goto err_pm;
|
||||
break;
|
||||
case ARIZONA_32KZ_MCLK2:
|
||||
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
|
||||
if (ret != 0)
|
||||
goto err_ref;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +67,9 @@ int arizona_clk32k_enable(struct arizona *arizona)
|
|||
ARIZONA_CLK_32K_ENA);
|
||||
}
|
||||
|
||||
out:
|
||||
err_pm:
|
||||
pm_runtime_put_sync(arizona->dev);
|
||||
err_ref:
|
||||
if (ret != 0)
|
||||
arizona->clk32k_ref--;
|
||||
|
||||
|
|
@ -83,6 +94,10 @@ int arizona_clk32k_disable(struct arizona *arizona)
|
|||
switch (arizona->pdata.clk32k_src) {
|
||||
case ARIZONA_32KZ_MCLK1:
|
||||
pm_runtime_put_sync(arizona->dev);
|
||||
clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
|
||||
break;
|
||||
case ARIZONA_32KZ_MCLK2:
|
||||
clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -735,7 +750,7 @@ static int arizona_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int arizona_suspend_late(struct device *dev)
|
||||
static int arizona_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
|
|
@ -759,7 +774,7 @@ static int arizona_resume(struct device *dev)
|
|||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
|
||||
dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
|
||||
enable_irq(arizona->irq);
|
||||
|
||||
return 0;
|
||||
|
|
@ -771,10 +786,8 @@ const struct dev_pm_ops arizona_pm_ops = {
|
|||
arizona_runtime_resume,
|
||||
NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_late = arizona_suspend_late,
|
||||
.resume_noirq = arizona_resume_noirq,
|
||||
#endif
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
|
||||
arizona_resume_noirq)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_pm_ops);
|
||||
|
||||
|
|
@ -790,35 +803,25 @@ unsigned long arizona_of_get_type(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_of_get_type);
|
||||
|
||||
int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
|
||||
bool mandatory)
|
||||
{
|
||||
int gpio;
|
||||
|
||||
gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
|
||||
if (gpio < 0) {
|
||||
if (mandatory)
|
||||
dev_err(arizona->dev,
|
||||
"Mandatory DT gpio %s missing/malformed: %d\n",
|
||||
prop, gpio);
|
||||
|
||||
gpio = 0;
|
||||
}
|
||||
|
||||
return gpio;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
|
||||
|
||||
static int arizona_of_get_core_pdata(struct arizona *arizona)
|
||||
{
|
||||
struct arizona_pdata *pdata = &arizona->pdata;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
u32 val;
|
||||
u32 pdm_val[ARIZONA_MAX_PDM_SPK];
|
||||
int ret, i;
|
||||
int count = 0;
|
||||
|
||||
pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
|
||||
pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
|
||||
if (pdata->reset == -EPROBE_DEFER) {
|
||||
return pdata->reset;
|
||||
} else if (pdata->reset < 0) {
|
||||
dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n",
|
||||
pdata->reset);
|
||||
|
||||
pdata->reset = 0;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,gpio-defaults",
|
||||
|
|
@ -871,6 +874,35 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
|
|||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
of_property_for_each_u32(arizona->dev->of_node,
|
||||
"wlf,max-channels-clocked",
|
||||
prop, cur, val) {
|
||||
if (count == ARRAY_SIZE(pdata->max_channels_clocked))
|
||||
break;
|
||||
|
||||
pdata->max_channels_clocked[count] = val;
|
||||
count++;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,spk-fmt",
|
||||
pdm_val,
|
||||
ARRAY_SIZE(pdm_val));
|
||||
|
||||
if (ret >= 0)
|
||||
for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
|
||||
pdata->spk_fmt[count] = pdm_val[count];
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,spk-mute",
|
||||
pdm_val,
|
||||
ARRAY_SIZE(pdm_val));
|
||||
|
||||
if (ret >= 0)
|
||||
for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
|
||||
pdata->spk_mute[count] = pdm_val[count];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1000,6 +1032,7 @@ static const struct mfd_cell wm8998_devs[] = {
|
|||
|
||||
int arizona_dev_init(struct arizona *arizona)
|
||||
{
|
||||
const char * const mclk_name[] = { "mclk1", "mclk2" };
|
||||
struct device *dev = arizona->dev;
|
||||
const char *type_name = NULL;
|
||||
unsigned int reg, val, mask;
|
||||
|
|
@ -1010,11 +1043,24 @@ int arizona_dev_init(struct arizona *arizona)
|
|||
dev_set_drvdata(arizona->dev, arizona);
|
||||
mutex_init(&arizona->clk_lock);
|
||||
|
||||
if (dev_get_platdata(arizona->dev))
|
||||
if (dev_get_platdata(arizona->dev)) {
|
||||
memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
|
||||
sizeof(arizona->pdata));
|
||||
else
|
||||
arizona_of_get_core_pdata(arizona);
|
||||
} else {
|
||||
ret = arizona_of_get_core_pdata(arizona);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
|
||||
for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
|
||||
arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
|
||||
if (IS_ERR(arizona->mclk[i])) {
|
||||
dev_info(arizona->dev, "Failed to get %s: %ld\n",
|
||||
mclk_name[i], PTR_ERR(arizona->mclk[i]));
|
||||
arizona->mclk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
regcache_cache_only(arizona->regmap, true);
|
||||
|
||||
|
|
@ -1035,7 +1081,7 @@ int arizona_dev_init(struct arizona *arizona)
|
|||
default:
|
||||
dev_err(arizona->dev, "Unknown device type %d\n",
|
||||
arizona->type);
|
||||
return -EINVAL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Mark DCVDD as external, LDO1 driver will clear if internal */
|
||||
|
|
@ -1121,6 +1167,7 @@ int arizona_dev_init(struct arizona *arizona)
|
|||
break;
|
||||
default:
|
||||
dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
|
|
@ -1280,12 +1327,14 @@ int arizona_dev_init(struct arizona *arizona)
|
|||
break;
|
||||
default:
|
||||
dev_err(arizona->dev, "Unknown device ID %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
if (!subdevs) {
|
||||
dev_err(arizona->dev,
|
||||
"No kernel support for device ID %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,9 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
|
|||
if (reg <= ATMEL_HLCDC_DIS) {
|
||||
u32 status;
|
||||
|
||||
readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status,
|
||||
!(status & ATMEL_HLCDC_SIP), 1, 100);
|
||||
readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
|
||||
status, !(status & ATMEL_HLCDC_SIP),
|
||||
1, 100);
|
||||
}
|
||||
|
||||
writel(val, hregmap->regs + reg);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev)
|
|||
|
||||
static const struct of_device_id axp20x_rsb_of_match[] = {
|
||||
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
|
||||
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
|
||||
{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
|
||||
{ },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ static const char * const axp20x_model_names[] = {
|
|||
"AXP221",
|
||||
"AXP223",
|
||||
"AXP288",
|
||||
"AXP806",
|
||||
"AXP809",
|
||||
};
|
||||
|
||||
|
|
@ -129,6 +130,27 @@ static const struct regmap_access_table axp288_volatile_table = {
|
|||
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp806_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_DATACACHE(3)),
|
||||
regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
|
||||
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
|
||||
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp806_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp806_writeable_table = {
|
||||
.yes_ranges = axp806_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp806_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp806_volatile_table = {
|
||||
.yes_ranges = axp806_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges),
|
||||
};
|
||||
|
||||
static struct resource axp152_pek_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
|
|
@ -278,6 +300,15 @@ static const struct regmap_config axp288_regmap_config = {
|
|||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct regmap_config axp806_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.wr_table = &axp806_writeable_table,
|
||||
.volatile_table = &axp806_volatile_table,
|
||||
.max_register = AXP806_VREF_TEMP_WARN_L,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
|
||||
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
|
||||
|
||||
|
|
@ -409,6 +440,21 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
|
|||
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
|
||||
};
|
||||
|
||||
static const struct regmap_irq axp806_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV1, 0, 0),
|
||||
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV2, 0, 1),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCA_V_LOW, 0, 3),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCB_V_LOW, 0, 4),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCC_V_LOW, 0, 5),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCD_V_LOW, 0, 6),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCE_V_LOW, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_LONG, 1, 0),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_SHORT, 1, 1),
|
||||
INIT_REGMAP_IRQ(AXP806, WAKEUP, 1, 4),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_FALL, 1, 5),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_RISE, 1, 6),
|
||||
};
|
||||
|
||||
static const struct regmap_irq axp809_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP809, ACIN_OVER_V, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP809, ACIN_PLUGIN, 0, 6),
|
||||
|
|
@ -494,6 +540,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
|
|||
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip axp806_regmap_irq_chip = {
|
||||
.name = "axp806",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
.ack_base = AXP20X_IRQ1_STATE,
|
||||
.mask_base = AXP20X_IRQ1_EN,
|
||||
.mask_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.irqs = axp806_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(axp806_regmap_irqs),
|
||||
.num_regs = 2,
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip axp809_regmap_irq_chip = {
|
||||
.name = "axp809",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
|
|
@ -508,6 +566,9 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = {
|
|||
|
||||
static struct mfd_cell axp20x_cells[] = {
|
||||
{
|
||||
.name = "axp20x-gpio",
|
||||
.of_compatible = "x-powers,axp209-gpio",
|
||||
}, {
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp20x_pek_resources),
|
||||
.resources = axp20x_pek_resources,
|
||||
|
|
@ -660,12 +721,20 @@ static struct mfd_cell axp288_cells[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp806_cells[] = {
|
||||
{
|
||||
.id = 2,
|
||||
.name = "axp20x-regulator",
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp809_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp809_pek_resources),
|
||||
.resources = axp809_pek_resources,
|
||||
}, {
|
||||
.id = 1,
|
||||
.name = "axp20x-regulator",
|
||||
},
|
||||
};
|
||||
|
|
@ -732,6 +801,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
|
|||
axp20x->regmap_cfg = &axp288_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
|
||||
break;
|
||||
case AXP806_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
|
||||
axp20x->cells = axp806_cells;
|
||||
axp20x->regmap_cfg = &axp806_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp806_regmap_irq_chip;
|
||||
break;
|
||||
case AXP809_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
|
||||
axp20x->cells = axp809_cells;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
#define CROS_EC_DEV_PD_INDEX 1
|
||||
|
|
@ -49,11 +50,28 @@ static const struct mfd_cell ec_pd_cell = {
|
|||
.pdata_size = sizeof(pd_p),
|
||||
};
|
||||
|
||||
static irqreturn_t ec_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = data;
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(ec_dev->dev))
|
||||
pm_wakeup_event(ec_dev->dev, 0);
|
||||
|
||||
ret = cros_ec_get_next_event(ec_dev);
|
||||
if (ret > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
0, ec_dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
int err = 0;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
|
||||
|
||||
ec_dev->max_request = sizeof(struct ec_params_hello);
|
||||
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
|
||||
ec_dev->max_passthru = 0;
|
||||
|
|
@ -70,13 +88,24 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
|||
|
||||
cros_ec_query_all(ec_dev);
|
||||
|
||||
if (ec_dev->irq) {
|
||||
err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"chromeos-ec", ec_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d",
|
||||
ec_dev->irq, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1,
|
||||
NULL, ec_dev->irq, NULL);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"Failed to register Embedded Controller subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
|
||||
if (ec_dev->max_passthru) {
|
||||
|
|
@ -94,7 +123,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
|||
dev_err(dev,
|
||||
"Failed to register Power Delivery subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,13 +132,18 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
|||
if (err) {
|
||||
mfd_remove_devices(dev);
|
||||
dev_err(dev, "Failed to register sub-devices\n");
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_mfd:
|
||||
if (ec_dev->irq)
|
||||
free_irq(ec_dev->irq, ec_dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_register);
|
||||
|
||||
|
|
@ -136,13 +170,31 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
|
|||
}
|
||||
EXPORT_SYMBOL(cros_ec_suspend);
|
||||
|
||||
static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
while (cros_ec_get_next_event(ec_dev) > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
1, ec_dev);
|
||||
}
|
||||
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
enable_irq(ec_dev->irq);
|
||||
|
||||
/*
|
||||
* In some cases, we need to distinguish between events that occur
|
||||
* during suspend if the EC is not a wake source. For example,
|
||||
* keypresses during suspend should be discarded if it does not wake
|
||||
* the system.
|
||||
*
|
||||
* If the EC is not a wake source, drain the event queue and mark them
|
||||
* as "queued during suspend".
|
||||
*/
|
||||
if (ec_dev->wake_enabled) {
|
||||
disable_irq_wake(ec_dev->irq);
|
||||
ec_dev->wake_enabled = 0;
|
||||
} else {
|
||||
cros_ec_drain_events(ec_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -366,7 +366,6 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
|||
static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *ec_msg)
|
||||
{
|
||||
struct ec_host_request *request;
|
||||
struct ec_host_response *response;
|
||||
struct cros_ec_spi *ec_spi = ec_dev->priv;
|
||||
struct spi_transfer trans, trans_delay;
|
||||
|
|
@ -378,7 +377,6 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
|||
int ret = 0, final_ret;
|
||||
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
request = (struct ec_host_request *)ec_dev->dout;
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
/* If it's too soon to do another transaction, wait */
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ static bool da9052_reg_writeable(struct device *dev, unsigned int reg)
|
|||
case DA9052_EVENT_B_REG:
|
||||
case DA9052_EVENT_C_REG:
|
||||
case DA9052_EVENT_D_REG:
|
||||
case DA9052_FAULTLOG_REG:
|
||||
case DA9052_IRQ_MASK_A_REG:
|
||||
case DA9052_IRQ_MASK_B_REG:
|
||||
case DA9052_IRQ_MASK_C_REG:
|
||||
|
|
@ -541,6 +542,52 @@ const struct regmap_config da9052_regmap_config = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(da9052_regmap_config);
|
||||
|
||||
static int da9052_clear_fault_log(struct da9052 *da9052)
|
||||
{
|
||||
int ret = 0;
|
||||
int fault_log = 0;
|
||||
|
||||
fault_log = da9052_reg_read(da9052, DA9052_FAULTLOG_REG);
|
||||
if (fault_log < 0) {
|
||||
dev_err(da9052->dev,
|
||||
"Cannot read FAULT_LOG %d\n", fault_log);
|
||||
return fault_log;
|
||||
}
|
||||
|
||||
if (fault_log) {
|
||||
if (fault_log & DA9052_FAULTLOG_TWDERROR)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: TWD_ERROR\n");
|
||||
if (fault_log & DA9052_FAULTLOG_VDDFAULT)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: VDD_FAULT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_VDDSTART)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: VDD_START\n");
|
||||
if (fault_log & DA9052_FAULTLOG_TEMPOVER)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: TEMP_OVER\n");
|
||||
if (fault_log & DA9052_FAULTLOG_KEYSHUT)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: KEY_SHUT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_NSDSET)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: nSD_SHUT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_WAITSET)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: WAIT_SHUT\n");
|
||||
|
||||
ret = da9052_reg_write(da9052,
|
||||
DA9052_FAULTLOG_REG,
|
||||
0xFF);
|
||||
if (ret < 0)
|
||||
dev_err(da9052->dev,
|
||||
"Cannot reset FAULT_LOG values %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int da9052_device_init(struct da9052 *da9052, u8 chip_id)
|
||||
{
|
||||
struct da9052_pdata *pdata = dev_get_platdata(da9052->dev);
|
||||
|
|
@ -549,6 +596,10 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id)
|
|||
mutex_init(&da9052->auxadc_lock);
|
||||
init_completion(&da9052->done);
|
||||
|
||||
ret = da9052_clear_fault_log(da9052);
|
||||
if (ret < 0)
|
||||
dev_warn(da9052->dev, "Cannot clear FAULT_LOG\n");
|
||||
|
||||
if (pdata && pdata->init != NULL)
|
||||
pdata->init(da9052);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
* Copyright 2012 Dialog Semiconductors Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>,
|
||||
* Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
*
|
||||
* 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
|
||||
|
|
@ -242,5 +242,6 @@ void da9063_device_exit(struct da9063 *da9063)
|
|||
}
|
||||
|
||||
MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
|
||||
MODULE_AUTHOR("Krystian Garbaciak <[email protected]>, Michal Hajduk <[email protected]>");
|
||||
MODULE_AUTHOR("Krystian Garbaciak");
|
||||
MODULE_AUTHOR("Michal Hajduk");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -938,25 +938,6 @@ int db8500_prcmu_get_ddr_opp(void)
|
|||
return readb(PRCM_DDR_SUBSYS_APE_MINBW);
|
||||
}
|
||||
|
||||
/**
|
||||
* db8500_set_ddr_opp - set the appropriate DDR OPP
|
||||
* @opp: The new DDR operating point to which transition is to be made
|
||||
* Returns: 0 on success, non-zero on failure
|
||||
*
|
||||
* This function sets the operating point of the DDR.
|
||||
*/
|
||||
static bool enable_set_ddr_opp;
|
||||
int db8500_prcmu_set_ddr_opp(u8 opp)
|
||||
{
|
||||
if (opp < DDR_100_OPP || opp > DDR_25_OPP)
|
||||
return -EINVAL;
|
||||
/* Changing the DDR OPP can hang the hardware pre-v21 */
|
||||
if (enable_set_ddr_opp)
|
||||
writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
|
||||
static void request_even_slower_clocks(bool enable)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ static struct device *add_child(struct i2c_client *client, const char *name,
|
|||
status = platform_device_add_data(pdev, pdata, pdata_len);
|
||||
if (status < 0) {
|
||||
dev_dbg(&pdev->dev, "can't add platform_data\n");
|
||||
goto err;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,19 +222,20 @@ static struct device *add_child(struct i2c_client *client, const char *name,
|
|||
status = platform_device_add_resources(pdev, &r, 1);
|
||||
if (status < 0) {
|
||||
dev_dbg(&pdev->dev, "can't add irq\n");
|
||||
goto err;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
status = platform_device_add(pdev);
|
||||
if (status)
|
||||
goto put_device;
|
||||
|
||||
err:
|
||||
if (status < 0) {
|
||||
platform_device_put(pdev);
|
||||
dev_err(&client->dev, "can't add %s dev\n", name);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
return &pdev->dev;
|
||||
|
||||
put_device:
|
||||
platform_device_put(pdev);
|
||||
dev_err(&client->dev, "failed to add device %s\n", name);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
||||
static int add_children(struct i2c_client *client)
|
||||
|
|
|
|||
185
drivers/mfd/exynos-lpass.c
Normal file
185
drivers/mfd/exynos-lpass.c
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Authors: Inha Song <ideal.song@samsung.com>
|
||||
* Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
*
|
||||
* Samsung Exynos SoC series Low Power Audio Subsystem driver.
|
||||
*
|
||||
* This module provides regmap for the Top SFR region and instantiates
|
||||
* devices for IP blocks like DMAC, I2S, UART.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* LPASS Top register definitions */
|
||||
#define SFR_LPASS_CORE_SW_RESET 0x08
|
||||
#define LPASS_SB_SW_RESET BIT(11)
|
||||
#define LPASS_UART_SW_RESET BIT(10)
|
||||
#define LPASS_PCM_SW_RESET BIT(9)
|
||||
#define LPASS_I2S_SW_RESET BIT(8)
|
||||
#define LPASS_WDT1_SW_RESET BIT(4)
|
||||
#define LPASS_WDT0_SW_RESET BIT(3)
|
||||
#define LPASS_TIMER_SW_RESET BIT(2)
|
||||
#define LPASS_MEM_SW_RESET BIT(1)
|
||||
#define LPASS_DMA_SW_RESET BIT(0)
|
||||
|
||||
#define SFR_LPASS_INTR_CA5_MASK 0x48
|
||||
#define SFR_LPASS_INTR_CPU_MASK 0x58
|
||||
#define LPASS_INTR_APM BIT(9)
|
||||
#define LPASS_INTR_MIF BIT(8)
|
||||
#define LPASS_INTR_TIMER BIT(7)
|
||||
#define LPASS_INTR_DMA BIT(6)
|
||||
#define LPASS_INTR_GPIO BIT(5)
|
||||
#define LPASS_INTR_I2S BIT(4)
|
||||
#define LPASS_INTR_PCM BIT(3)
|
||||
#define LPASS_INTR_SLIMBUS BIT(2)
|
||||
#define LPASS_INTR_UART BIT(1)
|
||||
#define LPASS_INTR_SFR BIT(0)
|
||||
|
||||
struct exynos_lpass {
|
||||
/* pointer to the Power Management Unit regmap */
|
||||
struct regmap *pmu;
|
||||
/* pointer to the LPASS TOP regmap */
|
||||
struct regmap *top;
|
||||
};
|
||||
|
||||
static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
regmap_read(lpass->top, SFR_LPASS_CORE_SW_RESET, &val);
|
||||
|
||||
val &= ~mask;
|
||||
regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
val |= mask;
|
||||
regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
|
||||
}
|
||||
|
||||
static void exynos_lpass_enable(struct exynos_lpass *lpass)
|
||||
{
|
||||
/* Unmask SFR, DMA and I2S interrupt */
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
|
||||
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
|
||||
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
|
||||
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
|
||||
|
||||
/* Activate related PADs from retention state */
|
||||
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
|
||||
EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
|
||||
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
|
||||
}
|
||||
|
||||
static void exynos_lpass_disable(struct exynos_lpass *lpass)
|
||||
{
|
||||
/* Mask any unmasked IP interrupt sources */
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
|
||||
|
||||
/* Deactivate related PADs from retention state */
|
||||
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 0);
|
||||
}
|
||||
|
||||
static const struct regmap_config exynos_lpass_reg_conf = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0xfc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int exynos_lpass_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct exynos_lpass *lpass;
|
||||
void __iomem *base_top;
|
||||
struct resource *res;
|
||||
|
||||
lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
|
||||
if (!lpass)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base_top = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base_top))
|
||||
return PTR_ERR(base_top);
|
||||
|
||||
lpass->top = regmap_init_mmio(dev, base_top,
|
||||
&exynos_lpass_reg_conf);
|
||||
if (IS_ERR(lpass->top)) {
|
||||
dev_err(dev, "LPASS top regmap initialization failed\n");
|
||||
return PTR_ERR(lpass->top);
|
||||
}
|
||||
|
||||
lpass->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"samsung,pmu-syscon");
|
||||
if (IS_ERR(lpass->pmu)) {
|
||||
dev_err(dev, "Failed to lookup PMU regmap\n");
|
||||
return PTR_ERR(lpass->pmu);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, lpass);
|
||||
exynos_lpass_enable(lpass);
|
||||
|
||||
return of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_lpass_suspend(struct device *dev)
|
||||
{
|
||||
struct exynos_lpass *lpass = dev_get_drvdata(dev);
|
||||
|
||||
exynos_lpass_disable(lpass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_lpass_resume(struct device *dev)
|
||||
{
|
||||
struct exynos_lpass *lpass = dev_get_drvdata(dev);
|
||||
|
||||
exynos_lpass_enable(lpass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(lpass_pm_ops, exynos_lpass_suspend,
|
||||
exynos_lpass_resume);
|
||||
|
||||
static const struct of_device_id exynos_lpass_of_match[] = {
|
||||
{ .compatible = "samsung,exynos5433-lpass" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_lpass_of_match);
|
||||
|
||||
static struct platform_driver exynos_lpass_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-lpass",
|
||||
.pm = &lpass_pm_ops,
|
||||
.of_match_table = exynos_lpass_of_match,
|
||||
},
|
||||
.probe = exynos_lpass_probe,
|
||||
};
|
||||
module_platform_driver(exynos_lpass_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Samsung Low Power Audio Subsystem driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -52,6 +52,18 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
|
|||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
|
||||
/* SPT */
|
||||
{ "INT3446", (kernel_ulong_t)&spt_i2c_info },
|
||||
|
|
@ -61,7 +73,7 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
|
|||
{ "80860ABC", (kernel_ulong_t)&bxt_info },
|
||||
{ "80860AC2", (kernel_ulong_t)&bxt_info },
|
||||
/* APL */
|
||||
{ "80865AAC", (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ "80865AAC", (kernel_ulong_t)&apl_i2c_info },
|
||||
{ "80865ABC", (kernel_ulong_t)&bxt_info },
|
||||
{ "80865AC2", (kernel_ulong_t)&bxt_info },
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -111,6 +111,31 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
|
|||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_info = {
|
||||
.clk_rate = 120000000,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_uart_info = {
|
||||
.clk_rate = 120000000,
|
||||
.clk_con_id = "baudclk",
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
};
|
||||
|
||||
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
/* BXT A-Step */
|
||||
{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
|
|
@ -146,14 +171,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
|
||||
|
||||
/* APL */
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info },
|
||||
|
|
@ -181,6 +206,16 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
|
||||
/* KBL-H */
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&kbl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&kbl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/intel_msic.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -449,9 +449,4 @@ static struct platform_driver intel_msic_driver = {
|
|||
.name = "intel_msic",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(intel_msic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for Intel MSIC");
|
||||
MODULE_AUTHOR("Mika Westerberg <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_platform_driver(intel_msic_driver);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@
|
|||
#define BXTWC_MIRQLVL1 0x4E0E
|
||||
#define BXTWC_MPWRTNIRQ 0x4E0F
|
||||
|
||||
#define BXTWC_MIRQLVL1_MCHGR BIT(5)
|
||||
|
||||
#define BXTWC_MTHRM0IRQ 0x4E12
|
||||
#define BXTWC_MTHRM1IRQ 0x4E13
|
||||
#define BXTWC_MTHRM2IRQ 0x4E14
|
||||
|
|
@ -109,7 +111,7 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
|
|||
REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x3f),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f),
|
||||
|
|
@ -143,6 +145,10 @@ static struct resource adc_resources[] = {
|
|||
DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"),
|
||||
};
|
||||
|
||||
static struct resource usbc_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "USBC"),
|
||||
};
|
||||
|
||||
static struct resource charger_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"),
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"),
|
||||
|
|
@ -169,6 +175,11 @@ static struct mfd_cell bxt_wc_dev[] = {
|
|||
.num_resources = ARRAY_SIZE(thermal_resources),
|
||||
.resources = thermal_resources,
|
||||
},
|
||||
{
|
||||
.name = "bxt_wcove_usbc",
|
||||
.num_resources = ARRAY_SIZE(usbc_resources),
|
||||
.resources = usbc_resources,
|
||||
},
|
||||
{
|
||||
.name = "bxt_wcove_ext_charger",
|
||||
.num_resources = ARRAY_SIZE(charger_resources),
|
||||
|
|
@ -403,6 +414,16 @@ static int bxtwc_probe(struct platform_device *pdev)
|
|||
goto err_sysfs;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is known hw bug. Upon reset BIT 5 of register
|
||||
* BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However,
|
||||
* later it's set to 1(masked) automatically by hardware. So we
|
||||
* have the software workaround here to unmaksed it in order to let
|
||||
* charger interrutp work.
|
||||
*/
|
||||
regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1,
|
||||
BXTWC_MIRQLVL1_MCHGR, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ static int lp873x_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&lp873->lock);
|
||||
|
||||
ret = regmap_read(lp873->regmap, LP873X_REG_OTP_REV, &otpid);
|
||||
if (ret) {
|
||||
dev_err(lp873->dev, "Failed to read OTP ID\n");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2014 Samsung Electronics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
* Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* 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
|
||||
|
|
@ -569,6 +569,6 @@ static void __exit max14577_i2c_exit(void)
|
|||
}
|
||||
module_exit(max14577_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Chanwoo Choi <[email protected]>, Krzysztof Kozlowski <k[email protected]>");
|
||||
MODULE_AUTHOR("Chanwoo Choi <[email protected]>, Krzysztof Kozlowski <k[email protected]>");
|
||||
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
|
|||
mutex_unlock(&max8997->irqlock);
|
||||
}
|
||||
|
||||
static const inline struct max8997_irq_data *
|
||||
inline static const struct max8997_irq_data *
|
||||
irq_to_max8997_irq(struct max8997_dev *max8997, struct irq_data *data)
|
||||
{
|
||||
return &max8997_irqs[data->hwirq];
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ static const char * const port_modes[] = {
|
|||
* provided port mode string as per the port_modes table.
|
||||
* If no match is found it returns -ENODEV
|
||||
*/
|
||||
static const int omap_usbhs_get_dt_port_mode(const char *mode)
|
||||
static int omap_usbhs_get_dt_port_mode(const char *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ static const struct regmap_config ssbi_regmap_config = {
|
|||
};
|
||||
|
||||
static const struct of_device_id pm8921_id_table[] = {
|
||||
{ .compatible = "qcom,pm8018", },
|
||||
{ .compatible = "qcom,pm8058", },
|
||||
{ .compatible = "qcom,pm8921", },
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/mfd/qcom_rpm.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/mfd/qcom-rpm.h>
|
||||
|
||||
|
|
@ -48,6 +49,7 @@ struct qcom_rpm {
|
|||
struct regmap *ipc_regmap;
|
||||
unsigned ipc_offset;
|
||||
unsigned ipc_bit;
|
||||
struct clk *ramclk;
|
||||
|
||||
struct completion ack;
|
||||
struct mutex lock;
|
||||
|
|
@ -388,11 +390,62 @@ static const struct qcom_rpm_data ipq806x_template = {
|
|||
.ack_sel_size = 7,
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_resource mdm9615_rpm_resource_table[] = {
|
||||
[QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
|
||||
[QCOM_RPM_SYS_FABRIC_CLK] = { 26, 10, 9, 1 },
|
||||
[QCOM_RPM_DAYTONA_FABRIC_CLK] = { 27, 11, 11, 1 },
|
||||
[QCOM_RPM_SFPB_CLK] = { 28, 12, 12, 1 },
|
||||
[QCOM_RPM_CFPB_CLK] = { 29, 13, 13, 1 },
|
||||
[QCOM_RPM_EBI1_CLK] = { 30, 14, 16, 1 },
|
||||
[QCOM_RPM_APPS_FABRIC_HALT] = { 31, 15, 22, 2 },
|
||||
[QCOM_RPM_APPS_FABRIC_MODE] = { 33, 16, 23, 3 },
|
||||
[QCOM_RPM_APPS_FABRIC_IOCTL] = { 36, 17, 24, 1 },
|
||||
[QCOM_RPM_APPS_FABRIC_ARB] = { 37, 18, 25, 27 },
|
||||
[QCOM_RPM_PM8018_SMPS1] = { 64, 19, 30, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS2] = { 66, 21, 31, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS3] = { 68, 23, 32, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS4] = { 70, 25, 33, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS5] = { 72, 27, 34, 2 },
|
||||
[QCOM_RPM_PM8018_LDO1] = { 74, 29, 35, 2 },
|
||||
[QCOM_RPM_PM8018_LDO2] = { 76, 31, 36, 2 },
|
||||
[QCOM_RPM_PM8018_LDO3] = { 78, 33, 37, 2 },
|
||||
[QCOM_RPM_PM8018_LDO4] = { 80, 35, 38, 2 },
|
||||
[QCOM_RPM_PM8018_LDO5] = { 82, 37, 39, 2 },
|
||||
[QCOM_RPM_PM8018_LDO6] = { 84, 39, 40, 2 },
|
||||
[QCOM_RPM_PM8018_LDO7] = { 86, 41, 41, 2 },
|
||||
[QCOM_RPM_PM8018_LDO8] = { 88, 43, 42, 2 },
|
||||
[QCOM_RPM_PM8018_LDO9] = { 90, 45, 43, 2 },
|
||||
[QCOM_RPM_PM8018_LDO10] = { 92, 47, 44, 2 },
|
||||
[QCOM_RPM_PM8018_LDO11] = { 94, 49, 45, 2 },
|
||||
[QCOM_RPM_PM8018_LDO12] = { 96, 51, 46, 2 },
|
||||
[QCOM_RPM_PM8018_LDO13] = { 98, 53, 47, 2 },
|
||||
[QCOM_RPM_PM8018_LDO14] = { 100, 55, 48, 2 },
|
||||
[QCOM_RPM_PM8018_LVS1] = { 102, 57, 49, 1 },
|
||||
[QCOM_RPM_PM8018_NCP] = { 103, 58, 80, 2 },
|
||||
[QCOM_RPM_CXO_BUFFERS] = { 105, 60, 81, 1 },
|
||||
[QCOM_RPM_USB_OTG_SWITCH] = { 106, 61, 82, 1 },
|
||||
[QCOM_RPM_HDMI_SWITCH] = { 107, 62, 83, 1 },
|
||||
[QCOM_RPM_VOLTAGE_CORNER] = { 109, 64, 87, 1 },
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_data mdm9615_template = {
|
||||
.version = 3,
|
||||
.resource_table = mdm9615_rpm_resource_table,
|
||||
.n_resources = ARRAY_SIZE(mdm9615_rpm_resource_table),
|
||||
.req_ctx_off = 3,
|
||||
.req_sel_off = 11,
|
||||
.ack_ctx_off = 15,
|
||||
.ack_sel_off = 23,
|
||||
.req_sel_size = 4,
|
||||
.ack_sel_size = 7,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_rpm_of_match[] = {
|
||||
{ .compatible = "qcom,rpm-apq8064", .data = &apq8064_template },
|
||||
{ .compatible = "qcom,rpm-msm8660", .data = &msm8660_template },
|
||||
{ .compatible = "qcom,rpm-msm8960", .data = &msm8960_template },
|
||||
{ .compatible = "qcom,rpm-ipq8064", .data = &ipq806x_template },
|
||||
{ .compatible = "qcom,rpm-mdm9615", .data = &mdm9615_template },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_rpm_of_match);
|
||||
|
|
@ -501,6 +554,20 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
|||
mutex_init(&rpm->lock);
|
||||
init_completion(&rpm->ack);
|
||||
|
||||
/* Enable message RAM clock */
|
||||
rpm->ramclk = devm_clk_get(&pdev->dev, "ram");
|
||||
if (IS_ERR(rpm->ramclk)) {
|
||||
ret = PTR_ERR(rpm->ramclk);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
/*
|
||||
* Fall through in all other cases, as the clock is
|
||||
* optional. (Does not exist on all platforms.)
|
||||
*/
|
||||
rpm->ramclk = NULL;
|
||||
}
|
||||
clk_prepare_enable(rpm->ramclk); /* Accepts NULL */
|
||||
|
||||
irq_ack = platform_get_irq_byname(pdev, "ack");
|
||||
if (irq_ack < 0) {
|
||||
dev_err(&pdev->dev, "required ack interrupt missing\n");
|
||||
|
|
@ -538,6 +605,7 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
rpm->ipc_regmap = syscon_node_to_regmap(syscon_np);
|
||||
of_node_put(syscon_np);
|
||||
if (IS_ERR(rpm->ipc_regmap))
|
||||
return PTR_ERR(rpm->ipc_regmap);
|
||||
|
||||
|
|
@ -620,7 +688,11 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
|||
|
||||
static int qcom_rpm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_rpm *rpm = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
clk_disable_unprepare(rpm->ramclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
|
||||
if (!rk808)
|
||||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 <[email protected]>");
|
||||
MODULE_AUTHOR("Zhang Qing <[email protected]>");
|
||||
MODULE_DESCRIPTION("RK808 PMIC driver");
|
||||
MODULE_AUTHOR("Wadim Egorov <[email protected]>");
|
||||
MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
|
||||
|
|
|
|||
|
|
@ -46,9 +46,6 @@ static void rtsx_usb_sg_timed_out(unsigned long data)
|
|||
|
||||
dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
|
||||
usb_sg_cancel(&ucr->current_sg);
|
||||
|
||||
/* we know the cancellation is caused by time-out */
|
||||
ucr->current_sg.status = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
|
||||
|
|
@ -67,12 +64,15 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
|
|||
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
|
||||
add_timer(&ucr->sg_timer);
|
||||
usb_sg_wait(&ucr->current_sg);
|
||||
del_timer_sync(&ucr->sg_timer);
|
||||
if (!del_timer_sync(&ucr->sg_timer))
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
ret = ucr->current_sg.status;
|
||||
|
||||
if (act_len)
|
||||
*act_len = ucr->current_sg.bytes;
|
||||
|
||||
return ucr->current_sg.status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
|
||||
|
|
|
|||
|
|
@ -1001,7 +1001,7 @@ static int sm501_gpio_output(struct gpio_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip gpio_chip_template = {
|
||||
static const struct gpio_chip gpio_chip_template = {
|
||||
.ngpio = 32,
|
||||
.direction_input = sm501_gpio_input,
|
||||
.direction_output = sm501_gpio_output,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
|
|
@ -81,7 +80,6 @@ static const struct i2c_device_id smsc_i2c_id[] = {
|
|||
{ "smscece1099", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smsc_i2c_id);
|
||||
|
||||
static struct i2c_driver smsc_i2c_driver = {
|
||||
.driver = {
|
||||
|
|
@ -90,9 +88,4 @@ static struct i2c_driver smsc_i2c_driver = {
|
|||
.probe = smsc_i2c_probe,
|
||||
.id_table = smsc_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(smsc_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Sourav Poddar <[email protected]>");
|
||||
MODULE_DESCRIPTION("SMSC chip multi-function driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_i2c_driver(smsc_i2c_driver);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct prcm_data {
|
||||
|
|
@ -170,8 +170,4 @@ static struct platform_driver sun6i_prcm_driver = {
|
|||
},
|
||||
.probe = sun6i_prcm_probe,
|
||||
};
|
||||
module_platform_driver(sun6i_prcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Boris BREZILLON <[email protected]>");
|
||||
MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_platform_driver(sun6i_prcm_driver);
|
||||
|
|
|
|||
|
|
@ -15,22 +15,103 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps65217.h>
|
||||
|
||||
static const struct mfd_cell tps65217s[] = {
|
||||
static struct resource charger_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_AC, "AC"),
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_USB, "USB"),
|
||||
};
|
||||
|
||||
static struct resource pb_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
|
||||
};
|
||||
|
||||
struct tps65217_irq {
|
||||
int mask;
|
||||
int interrupt;
|
||||
};
|
||||
|
||||
static const struct tps65217_irq tps65217_irqs[] = {
|
||||
[TPS65217_IRQ_PB] = {
|
||||
.mask = TPS65217_INT_PBM,
|
||||
.interrupt = TPS65217_INT_PBI,
|
||||
},
|
||||
[TPS65217_IRQ_AC] = {
|
||||
.mask = TPS65217_INT_ACM,
|
||||
.interrupt = TPS65217_INT_ACI,
|
||||
},
|
||||
[TPS65217_IRQ_USB] = {
|
||||
.mask = TPS65217_INT_USBM,
|
||||
.interrupt = TPS65217_INT_USBI,
|
||||
},
|
||||
};
|
||||
|
||||
static void tps65217_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&tps->irq_lock);
|
||||
}
|
||||
|
||||
static void tps65217_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
int ret;
|
||||
|
||||
ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (ret != 0)
|
||||
dev_err(tps->dev, "Failed to sync IRQ masks\n");
|
||||
|
||||
mutex_unlock(&tps->irq_lock);
|
||||
}
|
||||
|
||||
static inline const struct tps65217_irq *
|
||||
irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
|
||||
{
|
||||
return &tps65217_irqs[data->hwirq];
|
||||
}
|
||||
|
||||
static void tps65217_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
|
||||
|
||||
tps->irq_mask &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void tps65217_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
|
||||
|
||||
tps->irq_mask |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip tps65217_irq_chip = {
|
||||
.irq_bus_lock = tps65217_irq_lock,
|
||||
.irq_bus_sync_unlock = tps65217_irq_sync_unlock,
|
||||
.irq_enable = tps65217_irq_enable,
|
||||
.irq_disable = tps65217_irq_disable,
|
||||
};
|
||||
|
||||
static struct mfd_cell tps65217s[] = {
|
||||
{
|
||||
.name = "tps65217-pmic",
|
||||
.of_compatible = "ti,tps65217-pmic",
|
||||
|
|
@ -41,10 +122,96 @@ static const struct mfd_cell tps65217s[] = {
|
|||
},
|
||||
{
|
||||
.name = "tps65217-charger",
|
||||
.num_resources = ARRAY_SIZE(charger_resources),
|
||||
.resources = charger_resources,
|
||||
.of_compatible = "ti,tps65217-charger",
|
||||
},
|
||||
{
|
||||
.name = "tps65217-pwrbutton",
|
||||
.num_resources = ARRAY_SIZE(pb_resources),
|
||||
.resources = pb_resources,
|
||||
.of_compatible = "ti,tps65217-pwrbutton",
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t tps65217_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct tps65217 *tps = data;
|
||||
unsigned int status;
|
||||
bool handled = false;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = tps65217_reg_read(tps, TPS65217_REG_INT, &status);
|
||||
if (ret < 0) {
|
||||
dev_err(tps->dev, "Failed to read IRQ status: %d\n",
|
||||
ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
|
||||
if (status & tps65217_irqs[i].interrupt) {
|
||||
handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int tps65217_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct tps65217 *tps = h->host_data;
|
||||
|
||||
irq_set_chip_data(virq, tps);
|
||||
irq_set_chip_and_handler(virq, &tps65217_irq_chip, handle_edge_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
irq_set_parent(virq, tps->irq);
|
||||
irq_set_noprobe(virq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops tps65217_irq_domain_ops = {
|
||||
.map = tps65217_irq_map,
|
||||
};
|
||||
|
||||
static int tps65217_irq_init(struct tps65217 *tps, int irq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_init(&tps->irq_lock);
|
||||
tps->irq = irq;
|
||||
|
||||
/* Mask all interrupt sources */
|
||||
tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
|
||||
| TPS65217_INT_ACM | TPS65217_INT_USBM);
|
||||
tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
|
||||
TPS65217_PROTECT_NONE);
|
||||
|
||||
tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
|
||||
TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
|
||||
if (!tps->irq_domain) {
|
||||
dev_err(tps->dev, "Could not create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(tps->dev, irq, NULL,
|
||||
tps65217_irq_thread, IRQF_ONESHOT,
|
||||
"tps65217-irq", tps);
|
||||
if (ret) {
|
||||
dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tps65217_reg_read: Read a single tps65217 register.
|
||||
*
|
||||
|
|
@ -149,11 +316,22 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
|
||||
|
||||
static bool tps65217_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TPS65217_REG_INT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config tps65217_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = TPS65217_REG_MAX,
|
||||
.volatile_reg = tps65217_volatile_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id tps65217_of_match[] = {
|
||||
|
|
@ -205,8 +383,19 @@ static int tps65217_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq) {
|
||||
tps65217_irq_init(tps, client->irq);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* Don't tell children about IRQ resources which won't fire */
|
||||
for (i = 0; i < ARRAY_SIZE(tps65217s); i++)
|
||||
tps65217s[i].num_resources = 0;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
|
||||
ARRAY_SIZE(tps65217s), NULL, 0, NULL);
|
||||
ARRAY_SIZE(tps65217s), NULL, 0,
|
||||
tps->irq_domain);
|
||||
if (ret < 0) {
|
||||
dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
|
|
@ -1258,7 +1257,6 @@ static const struct i2c_device_id twl_ids[] = {
|
|||
{ "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, twl_ids);
|
||||
|
||||
/* One Client Driver , 4 Clients */
|
||||
static struct i2c_driver twl_driver = {
|
||||
|
|
@ -1267,9 +1265,4 @@ static struct i2c_driver twl_driver = {
|
|||
.probe = twl_probe,
|
||||
.remove = twl_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(twl_driver);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments, Inc.");
|
||||
MODULE_DESCRIPTION("I2C Core interface for TWL");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_i2c_driver(twl_driver);
|
||||
|
|
|
|||
|
|
@ -609,6 +609,7 @@ static const struct regmap_config twl6040_regmap_config = {
|
|||
.writeable_reg = twl6040_writeable_reg,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.use_single_rw = true,
|
||||
};
|
||||
|
||||
static const struct regmap_irq twl6040_irqs[] = {
|
||||
|
|
@ -782,6 +783,11 @@ static int twl6040_probe(struct i2c_client *client,
|
|||
cell->name = "twl6040-gpo";
|
||||
children++;
|
||||
|
||||
/* PDM clock support */
|
||||
cell = &twl6040->cells[children];
|
||||
cell->name = "twl6040-pdmclk";
|
||||
children++;
|
||||
|
||||
/* The chip is powered down so mark regmap to cache only and dirty */
|
||||
regcache_cache_only(twl6040->regmap, true);
|
||||
regcache_mark_dirty(twl6040->regmap);
|
||||
|
|
|
|||
|
|
@ -446,10 +446,6 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
|
|||
unsigned long mask;
|
||||
|
||||
mask = probe_irq_on();
|
||||
if (!mask) {
|
||||
probe_irq_off(mask);
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the ADC interrupt.
|
||||
|
|
@ -541,7 +537,7 @@ static int ucb1x00_probe(struct mcp *mcp)
|
|||
ucb1x00_enable(ucb);
|
||||
ucb->irq = ucb1x00_detect_irq(ucb);
|
||||
ucb1x00_disable(ucb);
|
||||
if (ucb->irq == NO_IRQ) {
|
||||
if (!ucb->irq) {
|
||||
dev_err(&ucb->dev, "IRQ probe failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_no_irq;
|
||||
|
|
|
|||
Loading…
Reference in a new issue