Hi Linus,

Changes to the core:
  - Honour PLATFORM_DEVID_NONE and PLATFORM_DEVID_AUTO dev IDs
 
 Changes to existing drivers:
  - IRQ additions/fixes; axp20x, da9063-core
  - Code simplification; i2c-dln2
  - Regmap additions/fixes; max77693
  - Error checking/handling improvements; dln2, db8500-prcmu
  - Bug fixes; dln2, wm8350-core
  - DT support/documentation; max77693, max77686, tps65217, twl4030-power,
                              gpio-tc3589x
  - Decouple syscon interface from platform devices
  - Use MFD hotplug registration; rtsx_usb, viperboard, hid-sensor-hub
  - Regulator fixups; sec-core
  - Power Management additions/fixes; rts5227, tc6393xb
  - Remove relic/redundant code; ab8500-sysctrl, lpc_sch, max77693-private
  - Clean-up/coding style changes; tps65090
  - Clk additions/fixes; tc6393xb, tc6387xb, t7l66xb
  - Add USB-SPI support; dln2
  - Trivial changes; max14577, arizona-spi, lpc_sch, wm8997-tables, wm5102-tables
                     wm5110-tables, axp20x, atmel-hlcdc, rtsx_pci
 
 New drivers/supported devices:
  - axp288 PMIC support added to axp20x
  - s2mps13 support added to sec-core
  - New support for Diolan DLN-2
  - New support for atmel-hlcdc
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJUhZDaAAoJEFGvii+H/HdhEY4P+gOlEIU+LYDdKmRjXLp85+ZS
 zrkLQdxvRp61LzzcIMGnduPFAOk8ixb3nRqSJv7P5WQG26I6qoI44zeTF2iSmLTp
 iVLtXRFSlo/lRyWT+2jXwL5iC47PCoJuJajNeM/YEbMERR3sWWAPrATZrQSPoKcZ
 D3qtXge3d+zq2rqpSvNAFNPEC4i9xawwa9GHMte9T/XhaoyVhaK6ITMsh0RK4B0p
 RRc2zy9BGEkuZMu3aC7P/qhfu3uSrxzI6FCHNSbZt/p5aq8klMBGqpK9Tgg4UHUG
 jqAd2lCXHVSVI07CO0YvVUDWV+5NlB1kAeRddohJujV9o5ciaqKCGPKK1Fz0PMxf
 u30t0X4Fb4QCAZVeo1hX9KWKQaQinUzPhANT4Sz0DY1S7arZ6PlJO/obGIys5JCf
 ElJuYNSRqRp6DcaoTHf19DUcxJXnqk73PU3hmsdS4UkweBWDYeagK2gqDwjIhAY6
 DJZ5uqaa829fx/Jj8sUo0EgWZs/Cahf/td7y35fM4bMgU+vHd1xeBvMeltiJ2kuC
 OoZwtyHbV29sMCL2i5VQMkTkLJz49hPOEZolDKUxsV1QEPhi62DRmiHZlKABh3+D
 wzTkTRLfDhlrNedY529/1i3IxIlnzWXfInohe+WadapTFXuISIv6dyAyh9eNKnfd
 ZVf+1NwaCGbZbbPkSBqK
 =dJJd
 -----END PGP SIGNATURE-----

Merge tag 'mfd-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "Changes to the core:
   - Honour PLATFORM_DEVID_NONE and PLATFORM_DEVID_AUTO dev IDs

  Changes to existing drivers:
   - IRQ additions/fixes; axp20x, da9063-core
   - Code simplification; i2c-dln2
   - Regmap additions/fixes; max77693
   - Error checking/handling improvements; dln2, db8500-prcmu
   - Bug fixes; dln2, wm8350-core
   - DT support/documentation; max77693, max77686, tps65217, twl4030-power,
                               gpio-tc3589x
   - Decouple syscon interface from platform devices
   - Use MFD hotplug registration; rtsx_usb, viperboard, hid-sensor-hub
   - Regulator fixups; sec-core
   - Power Management additions/fixes; rts5227, tc6393xb
   - Remove relic/redundant code; ab8500-sysctrl, lpc_sch, max77693-private
   - Clean-up/coding style changes; tps65090
   - Clk additions/fixes; tc6393xb, tc6387xb, t7l66xb
   - Add USB-SPI support; dln2
   - Trivial changes; max14577, arizona-spi, lpc_sch, wm8997-tables, wm5102-tables
                      wm5110-tables, axp20x, atmel-hlcdc, rtsx_pci

  New drivers/supported devices:
   - axp288 PMIC support added to axp20x
   - s2mps13 support added to sec-core
   - New support for Diolan DLN-2
   - New support for atmel-hlcdc"

* tag 'mfd-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (55 commits)
  mfd: rtsx: Add func to split u32 into register
  mfd: atmel-hlcdc: Add Kconfig option description and name
  mfd: da9063: Get irq base dynamically before registering device
  mfd: max14577: Fix obvious typo in company name in copyright
  mfd: axp20x: Constify axp20x_acpi_match and rid unused warning
  mfd: t7l66xb: prepare/unprepare clocks
  mfd: tc6387xb: prepare/unprepare clocks
  mfd: dln2: add support for USB-SPI module
  mfd: wm5110: Add missing registers for AIF2 channels 3-6
  mfd: tc3589x: get rid of static base
  mfd: arizona: Document HP_CTRL_1L and HP_CTRL_1R registers
  mfd: wm8997: Mark INTERRUPT_STATUS_2_MASK as readable
  mfd: tc6393xb: Prepare/unprepare clocks
  mfd: tps65090: Fix bonkers indenting strategy
  mfd: tc6393xb: Fail ohci suspend if full state restore is required
  mfd: lpc_sch: Don't call mfd_remove_devices()
  mfd: wm8350-core: Fix probable mask then right shift defect
  mfd: ab8500-sysctrl: Drop ab8500_restart
  mfd: db8500-prcmu: Provide sane error path values
  mfd: db8500-prcmu: Check return of devm_ioremap for error
  ...
This commit is contained in:
Linus Torvalds 2014-12-08 20:02:54 -08:00
commit 3a7dbed7f2
63 changed files with 3431 additions and 273 deletions

View file

@ -59,6 +59,17 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_ATMEL_HLCDC
tristate "Atmel HLCDC (High-end LCD Controller)"
select MFD_CORE
select REGMAP_MMIO
depends on OF
help
If you say yes here you get support for the HLCDC block.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_BCM590XX
tristate "Broadcom BCM590xx PMUs"
select MFD_CORE
@ -74,7 +85,8 @@ config MFD_AXP20X
select REGMAP_IRQ
depends on I2C=y
help
If you say Y here you get support for the X-Powers AXP202 and AXP209.
If you say Y here you get support for the X-Powers AXP202, AXP209 and
AXP288 power management IC (PMIC).
This driver include only the core APIs. You have to select individual
components like regulators or the PEK (Power Enable Key) under the
corresponding menus.
@ -183,6 +195,16 @@ config MFD_DA9063
Additional drivers must be enabled in order to use the functionality
of the device.
config MFD_DLN2
tristate "Diolan DLN2 support"
select MFD_CORE
depends on USB
help
This adds support for Diolan USB-I2C/SPI/GPIO Master Adapter
DLN-2. Additional drivers such as I2C_DLN2, GPIO_DLN2,
etc. must be enabled in order to use the functionality of
the device.
config MFD_MC13XXX
tristate
depends on (SPI_MASTER || I2C)
@ -655,7 +677,6 @@ config MFD_SEC_CORE
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select REGULATOR
help
Support for the Samsung Electronics MFD series.
This driver provides common support for accessing the device,

View file

@ -13,7 +13,7 @@ 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
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
rtsx_pci-objs := rtsx_pcr.o rtsx_gops.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o
@ -157,6 +157,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
@ -174,6 +175,7 @@ obj-$(CONFIG_MFD_STW481X) += stw481x.o
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o

View file

@ -85,63 +85,6 @@ shutdown:
}
}
/*
* Use the AB WD to reset the platform. It will perform a hard
* reset instead of a soft reset. Write the reset reason to
* the AB before reset, which can be read upon restart.
*/
void ab8500_restart(char mode, const char *cmd)
{
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
u16 reason = 0;
u8 val;
if (sysctrl_dev == NULL) {
pr_err("%s: sysctrl not initialized\n", __func__);
return;
}
plat = dev_get_platdata(sysctrl_dev->parent);
pdata = plat->sysctrl;
if (pdata && pdata->reboot_reason_code)
reason = pdata->reboot_reason_code(cmd);
else
pr_warn("[%s] No reboot reason set. Default reason %d\n",
__func__, reason);
/*
* Disable RTC alarm, just a precaution so that no alarm
* is running when WD reset is executed.
*/
abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
RTC_CTRL , &val);
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
/*
* Android is not using the RTC alarm registers during reboot
* so we borrow them for writing the reason of reset
*/
/* reason[8 LSB] */
val = reason & 0xFF;
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
AB8500_ALARM_MIN_LOW , val);
/* reason[8 MSB] */
val = (reason>>8) & 0xFF;
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
AB8500_ALARM_MIN_MID , val);
/* Setting WD timeout to 0 */
ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
/* Setting the parameters to AB8500 WD*/
ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
}
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||

View file

@ -75,7 +75,9 @@ static int arizona_spi_probe(struct spi_device *spi)
static int arizona_spi_remove(struct spi_device *spi)
{
struct arizona *arizona = spi_get_drvdata(spi);
arizona_dev_exit(arizona);
return 0;
}

122
drivers/mfd/atmel-hlcdc.c Normal file
View file

@ -0,0 +1,122 @@
/*
* Copyright (C) 2014 Free Electrons
* Copyright (C) 2014 Atmel
*
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/mfd/atmel-hlcdc.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4)
static const struct mfd_cell atmel_hlcdc_cells[] = {
{
.name = "atmel-hlcdc-pwm",
.of_compatible = "atmel,hlcdc-pwm",
},
{
.name = "atmel-hlcdc-dc",
.of_compatible = "atmel,hlcdc-display-controller",
},
};
static const struct regmap_config atmel_hlcdc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = ATMEL_HLCDC_REG_MAX,
};
static int atmel_hlcdc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct atmel_hlcdc *hlcdc;
struct resource *res;
void __iomem *regs;
hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
if (!hlcdc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
hlcdc->irq = platform_get_irq(pdev, 0);
if (hlcdc->irq < 0)
return hlcdc->irq;
hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
if (IS_ERR(hlcdc->periph_clk)) {
dev_err(dev, "failed to get peripheral clock\n");
return PTR_ERR(hlcdc->periph_clk);
}
hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
if (IS_ERR(hlcdc->sys_clk)) {
dev_err(dev, "failed to get system clock\n");
return PTR_ERR(hlcdc->sys_clk);
}
hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
if (IS_ERR(hlcdc->slow_clk)) {
dev_err(dev, "failed to get slow clock\n");
return PTR_ERR(hlcdc->slow_clk);
}
hlcdc->regmap = devm_regmap_init_mmio(dev, regs,
&atmel_hlcdc_regmap_config);
if (IS_ERR(hlcdc->regmap))
return PTR_ERR(hlcdc->regmap);
dev_set_drvdata(dev, hlcdc);
return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
ARRAY_SIZE(atmel_hlcdc_cells),
NULL, 0, NULL);
}
static int atmel_hlcdc_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
return 0;
}
static const struct of_device_id atmel_hlcdc_match[] = {
{ .compatible = "atmel,sama5d3-hlcdc" },
{ /* sentinel */ },
};
static struct platform_driver atmel_hlcdc_driver = {
.probe = atmel_hlcdc_probe,
.remove = atmel_hlcdc_remove,
.driver = {
.name = "atmel-hlcdc",
.of_match_table = atmel_hlcdc_match,
},
};
module_platform_driver(atmel_hlcdc_driver);
MODULE_ALIAS("platform:atmel-hlcdc");
MODULE_AUTHOR("Boris Brezillon <[email protected]>");
MODULE_DESCRIPTION("Atmel HLCDC driver");
MODULE_LICENSE("GPL v2");

View file

@ -1,9 +1,9 @@
/*
* axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
* axp20x.c - MFD core driver for the X-Powers' Power Management ICs
*
* AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
* converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
* as well as 4 configurable GPIOs.
* AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
* converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
* as well as configurable GPIOs.
*
* Author: Carlo Caione <carlo@caione.org>
*
@ -25,9 +25,16 @@
#include <linux/mfd/core.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/acpi.h>
#define AXP20X_OFF 0x80
static const char const *axp20x_model_names[] = {
"AXP202",
"AXP209",
"AXP288",
};
static const struct regmap_range axp20x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
@ -47,6 +54,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
static const struct regmap_range axp288_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
};
static const struct regmap_range axp288_volatile_ranges[] = {
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
};
static const struct regmap_access_table axp288_writeable_table = {
.yes_ranges = axp288_writeable_ranges,
.n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges),
};
static const struct regmap_access_table axp288_volatile_table = {
.yes_ranges = axp288_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
};
static struct resource axp20x_pek_resources[] = {
{
.name = "PEK_DBR",
@ -61,6 +87,39 @@ static struct resource axp20x_pek_resources[] = {
},
};
static struct resource axp288_battery_resources[] = {
{
.start = AXP288_IRQ_QWBTU,
.end = AXP288_IRQ_QWBTU,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_WBTU,
.end = AXP288_IRQ_WBTU,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_QWBTO,
.end = AXP288_IRQ_QWBTO,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_WBTO,
.end = AXP288_IRQ_WBTO,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_WL2,
.end = AXP288_IRQ_WL2,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_WL1,
.end = AXP288_IRQ_WL1,
.flags = IORESOURCE_IRQ,
},
};
static const struct regmap_config axp20x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@ -70,47 +129,96 @@ static const struct regmap_config axp20x_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
#define AXP20X_IRQ(_irq, _off, _mask) \
[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
static const struct regmap_config axp288_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.wr_table = &axp288_writeable_table,
.volatile_table = &axp288_volatile_table,
.max_register = AXP288_FG_TUNE5,
.cache_type = REGCACHE_RBTREE,
};
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
static const struct regmap_irq axp20x_regmap_irqs[] = {
AXP20X_IRQ(ACIN_OVER_V, 0, 7),
AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
AXP20X_IRQ(VBUS_OVER_V, 0, 4),
AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
AXP20X_IRQ(VBUS_V_LOW, 0, 1),
AXP20X_IRQ(BATT_PLUGIN, 1, 7),
AXP20X_IRQ(BATT_REMOVAL, 1, 6),
AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
AXP20X_IRQ(CHARG, 1, 3),
AXP20X_IRQ(CHARG_DONE, 1, 2),
AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
AXP20X_IRQ(CHARG_I_LOW, 2, 6),
AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
AXP20X_IRQ(PEK_SHORT, 2, 1),
AXP20X_IRQ(PEK_LONG, 2, 0),
AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
AXP20X_IRQ(VBUS_VALID, 3, 5),
AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
AXP20X_IRQ(VBUS_SESS_END, 3, 2),
AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
AXP20X_IRQ(TIMER, 4, 7),
AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
AXP20X_IRQ(GPIO3_INPUT, 4, 3),
AXP20X_IRQ(GPIO2_INPUT, 4, 2),
AXP20X_IRQ(GPIO1_INPUT, 4, 1),
AXP20X_IRQ(GPIO0_INPUT, 4, 0),
INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5),
INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1),
INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5),
INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4),
INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1),
INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0),
INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7),
INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6),
INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5),
INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4),
INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3),
INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1),
INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0),
INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7),
INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6),
INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5),
INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4),
INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3),
INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2),
INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1),
INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0),
INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6),
INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5),
INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3),
INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2),
INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1),
INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
};
/* some IRQs are compatible with axp20x models */
static const struct regmap_irq axp288_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2),
INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3),
INIT_REGMAP_IRQ(AXP288, OV, 0, 4),
INIT_REGMAP_IRQ(AXP288, DONE, 1, 2),
INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6),
INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7),
INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0),
INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1),
INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2),
INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3),
INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4),
INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5),
INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6),
INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7),
INIT_REGMAP_IRQ(AXP288, WL2, 3, 0),
INIT_REGMAP_IRQ(AXP288, WL1, 3, 1),
INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2),
INIT_REGMAP_IRQ(AXP288, OT, 3, 7),
INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0),
INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1),
INIT_REGMAP_IRQ(AXP288, POKO, 4, 2),
INIT_REGMAP_IRQ(AXP288, POKL, 4, 3),
INIT_REGMAP_IRQ(AXP288, POKS, 4, 4),
INIT_REGMAP_IRQ(AXP288, POKN, 4, 5),
INIT_REGMAP_IRQ(AXP288, POKP, 4, 6),
INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7),
INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0),
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
static const struct of_device_id axp20x_of_match[] = {
@ -128,16 +236,39 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
static const struct acpi_device_id axp20x_acpi_match[] = {
{
.id = "INT33F4",
.driver_data = AXP288_ID,
},
{ },
};
MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
.name = "axp20x_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
.ack_base = AXP20X_IRQ1_STATE,
.mask_base = AXP20X_IRQ1_EN,
.num_regs = 5,
.irqs = axp20x_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
.mask_invert = true,
.init_ack_masked = true,
.irqs = axp20x_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
.num_regs = 5,
};
static const struct regmap_irq_chip axp288_regmap_irq_chip = {
.name = "axp288_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
.ack_base = AXP20X_IRQ1_STATE,
.mask_base = AXP20X_IRQ1_EN,
.mask_invert = true,
.init_ack_masked = true,
.irqs = axp288_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp288_regmap_irqs),
.num_regs = 6,
};
static struct mfd_cell axp20x_cells[] = {
@ -150,36 +281,155 @@ static struct mfd_cell axp20x_cells[] = {
},
};
static struct resource axp288_adc_resources[] = {
{
.name = "GPADC",
.start = AXP288_IRQ_GPADC,
.end = AXP288_IRQ_GPADC,
.flags = IORESOURCE_IRQ,
},
};
static struct resource axp288_charger_resources[] = {
{
.start = AXP288_IRQ_OV,
.end = AXP288_IRQ_OV,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_DONE,
.end = AXP288_IRQ_DONE,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_CHARGING,
.end = AXP288_IRQ_CHARGING,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_SAFE_QUIT,
.end = AXP288_IRQ_SAFE_QUIT,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_SAFE_ENTER,
.end = AXP288_IRQ_SAFE_ENTER,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_QCBTU,
.end = AXP288_IRQ_QCBTU,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_CBTU,
.end = AXP288_IRQ_CBTU,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_QCBTO,
.end = AXP288_IRQ_QCBTO,
.flags = IORESOURCE_IRQ,
},
{
.start = AXP288_IRQ_CBTO,
.end = AXP288_IRQ_CBTO,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell axp288_cells[] = {
{
.name = "axp288_adc",
.num_resources = ARRAY_SIZE(axp288_adc_resources),
.resources = axp288_adc_resources,
},
{
.name = "axp288_charger",
.num_resources = ARRAY_SIZE(axp288_charger_resources),
.resources = axp288_charger_resources,
},
{
.name = "axp288_battery",
.num_resources = ARRAY_SIZE(axp288_battery_resources),
.resources = axp288_battery_resources,
},
};
static struct axp20x_dev *axp20x_pm_power_off;
static void axp20x_power_off(void)
{
if (axp20x_pm_power_off->variant == AXP288_ID)
return;
regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
AXP20X_OFF);
}
static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
{
const struct acpi_device_id *acpi_id;
const struct of_device_id *of_id;
if (dev->of_node) {
of_id = of_match_device(axp20x_of_match, dev);
if (!of_id) {
dev_err(dev, "Unable to match OF ID\n");
return -ENODEV;
}
axp20x->variant = (long) of_id->data;
} else {
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!acpi_id || !acpi_id->driver_data) {
dev_err(dev, "Unable to match ACPI ID and data\n");
return -ENODEV;
}
axp20x->variant = (long) acpi_id->driver_data;
}
switch (axp20x->variant) {
case AXP202_ID:
case AXP209_ID:
axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
axp20x->cells = axp20x_cells;
axp20x->regmap_cfg = &axp20x_regmap_config;
axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
break;
case AXP288_ID:
axp20x->cells = axp288_cells;
axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
axp20x->regmap_cfg = &axp288_regmap_config;
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
break;
default:
dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
return -EINVAL;
}
dev_info(dev, "AXP20x variant %s found\n",
axp20x_model_names[axp20x->variant]);
return 0;
}
static int axp20x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct axp20x_dev *axp20x;
const struct of_device_id *of_id;
int ret;
axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
if (!axp20x)
return -ENOMEM;
of_id = of_match_device(axp20x_of_match, &i2c->dev);
if (!of_id) {
dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
return -ENODEV;
}
axp20x->variant = (long) of_id->data;
ret = axp20x_match_device(axp20x, &i2c->dev);
if (ret)
return ret;
axp20x->i2c_client = i2c;
axp20x->dev = &i2c->dev;
dev_set_drvdata(axp20x->dev, axp20x);
axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
if (IS_ERR(axp20x->regmap)) {
ret = PTR_ERR(axp20x->regmap);
dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
@ -188,15 +438,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
IRQF_ONESHOT | IRQF_SHARED, -1,
&axp20x_regmap_irq_chip,
axp20x->regmap_irq_chip,
&axp20x->regmap_irqc);
if (ret) {
dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
return ret;
}
ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
axp20x->nr_cells, NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
@ -234,6 +484,7 @@ static struct i2c_driver axp20x_i2c_driver = {
.name = "axp20x",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(axp20x_of_match),
.acpi_match_table = ACPI_PTR(axp20x_acpi_match),
},
.probe = axp20x_i2c_probe,
.remove = axp20x_i2c_remove,

View file

@ -118,7 +118,7 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
da9063->irq_base = pdata->irq_base;
} else {
da9063->flags = 0;
da9063->irq_base = 0;
da9063->irq_base = -1;
}
da9063->chip_irq = irq;
@ -168,6 +168,8 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
return ret;
}
da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
NULL);

View file

@ -3150,23 +3150,28 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu");
if (!res) {
dev_err(&pdev->dev, "no prcmu memory region provided\n");
return -ENOENT;
return -EINVAL;
}
prcmu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!prcmu_base) {
dev_err(&pdev->dev,
"failed to ioremap prcmu register memory\n");
return -ENOENT;
return -ENOMEM;
}
init_prcm_registers();
dbx500_fw_version_init(pdev, pdata->version_offset);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
if (!res) {
dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
return -ENOENT;
return -EINVAL;
}
tcdm_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!tcdm_base) {
dev_err(&pdev->dev,
"failed to ioremap prcmu-tcdm register memory\n");
return -ENOMEM;
}
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
@ -3174,15 +3179,14 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "no prcmu irq provided\n");
return -ENOENT;
return irq;
}
err = request_threaded_irq(irq, prcmu_irq_handler,
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
if (err < 0) {
pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
err = -EBUSY;
goto no_irq_return;
return err;
}
db8500_irq_init(np);
@ -3206,7 +3210,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add subdevices\n");
goto no_irq_return;
return err;
}
}
@ -3214,12 +3218,10 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add ab8500 subdevice\n");
goto no_irq_return;
return err;
}
pr_info("DB8500 PRCMU initialized\n");
no_irq_return:
return err;
}
static const struct of_device_id db8500_prcmu_match[] = {

781
drivers/mfd/dln2.c Normal file
View file

@ -0,0 +1,781 @@
/*
* Driver for the Diolan DLN-2 USB adapter
*
* Copyright (c) 2014 Intel Corporation
*
* Derived from:
* i2c-diolan-u2c.c
* Copyright (c) 2010-2011 Ericsson AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/dln2.h>
#include <linux/rculist.h>
struct dln2_header {
__le16 size;
__le16 id;
__le16 echo;
__le16 handle;
};
struct dln2_response {
struct dln2_header hdr;
__le16 result;
};
#define DLN2_GENERIC_MODULE_ID 0x00
#define DLN2_GENERIC_CMD(cmd) DLN2_CMD(cmd, DLN2_GENERIC_MODULE_ID)
#define CMD_GET_DEVICE_VER DLN2_GENERIC_CMD(0x30)
#define CMD_GET_DEVICE_SN DLN2_GENERIC_CMD(0x31)
#define DLN2_HW_ID 0x200
#define DLN2_USB_TIMEOUT 200 /* in ms */
#define DLN2_MAX_RX_SLOTS 16
#define DLN2_MAX_URBS 16
#define DLN2_RX_BUF_SIZE 512
enum dln2_handle {
DLN2_HANDLE_EVENT = 0, /* don't change, hardware defined */
DLN2_HANDLE_CTRL,
DLN2_HANDLE_GPIO,
DLN2_HANDLE_I2C,
DLN2_HANDLE_SPI,
DLN2_HANDLES
};
/*
* Receive context used between the receive demultiplexer and the transfer
* routine. While sending a request the transfer routine will look for a free
* receive context and use it to wait for a response and to receive the URB and
* thus the response data.
*/
struct dln2_rx_context {
/* completion used to wait for a response */
struct completion done;
/* if non-NULL the URB contains the response */
struct urb *urb;
/* if true then this context is used to wait for a response */
bool in_use;
};
/*
* Receive contexts for a particular DLN2 module (i2c, gpio, etc.). We use the
* handle header field to identify the module in dln2_dev.mod_rx_slots and then
* the echo header field to index the slots field and find the receive context
* for a particular request.
*/
struct dln2_mod_rx_slots {
/* RX slots bitmap */
DECLARE_BITMAP(bmap, DLN2_MAX_RX_SLOTS);
/* used to wait for a free RX slot */
wait_queue_head_t wq;
/* used to wait for an RX operation to complete */
struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
/* avoid races between alloc/free_rx_slot and dln2_rx_transfer */
spinlock_t lock;
};
struct dln2_dev {
struct usb_device *usb_dev;
struct usb_interface *interface;
u8 ep_in;
u8 ep_out;
struct urb *rx_urb[DLN2_MAX_URBS];
void *rx_buf[DLN2_MAX_URBS];
struct dln2_mod_rx_slots mod_rx_slots[DLN2_HANDLES];
struct list_head event_cb_list;
spinlock_t event_cb_lock;
bool disconnect;
int active_transfers;
wait_queue_head_t disconnect_wq;
spinlock_t disconnect_lock;
};
struct dln2_event_cb_entry {
struct list_head list;
u16 id;
struct platform_device *pdev;
dln2_event_cb_t callback;
};
int dln2_register_event_cb(struct platform_device *pdev, u16 id,
dln2_event_cb_t event_cb)
{
struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
struct dln2_event_cb_entry *i, *entry;
unsigned long flags;
int ret = 0;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->id = id;
entry->callback = event_cb;
entry->pdev = pdev;
spin_lock_irqsave(&dln2->event_cb_lock, flags);
list_for_each_entry(i, &dln2->event_cb_list, list) {
if (i->id == id) {
ret = -EBUSY;
break;
}
}
if (!ret)
list_add_rcu(&entry->list, &dln2->event_cb_list);
spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
if (ret)
kfree(entry);
return ret;
}
EXPORT_SYMBOL(dln2_register_event_cb);
void dln2_unregister_event_cb(struct platform_device *pdev, u16 id)
{
struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
struct dln2_event_cb_entry *i;
unsigned long flags;
bool found = false;
spin_lock_irqsave(&dln2->event_cb_lock, flags);
list_for_each_entry(i, &dln2->event_cb_list, list) {
if (i->id == id) {
list_del_rcu(&i->list);
found = true;
break;
}
}
spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
if (found) {
synchronize_rcu();
kfree(i);
}
}
EXPORT_SYMBOL(dln2_unregister_event_cb);
/*
* Returns true if a valid transfer slot is found. In this case the URB must not
* be resubmitted immediately in dln2_rx as we need the data when dln2_transfer
* is woke up. It will be resubmitted there.
*/
static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb,
u16 handle, u16 rx_slot)
{
struct device *dev = &dln2->interface->dev;
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
struct dln2_rx_context *rxc;
bool valid_slot = false;
if (rx_slot >= DLN2_MAX_RX_SLOTS)
goto out;
rxc = &rxs->slots[rx_slot];
/*
* No need to disable interrupts as this lock is not taken in interrupt
* context elsewhere in this driver. This function (or its callers) are
* also not exported to other modules.
*/
spin_lock(&rxs->lock);
if (rxc->in_use && !rxc->urb) {
rxc->urb = urb;
complete(&rxc->done);
valid_slot = true;
}
spin_unlock(&rxs->lock);
out:
if (!valid_slot)
dev_warn(dev, "bad/late response %d/%d\n", handle, rx_slot);
return valid_slot;
}
static void dln2_run_event_callbacks(struct dln2_dev *dln2, u16 id, u16 echo,
void *data, int len)
{
struct dln2_event_cb_entry *i;
rcu_read_lock();
list_for_each_entry_rcu(i, &dln2->event_cb_list, list) {
if (i->id == id) {
i->callback(i->pdev, echo, data, len);
break;
}
}
rcu_read_unlock();
}
static void dln2_rx(struct urb *urb)
{
struct dln2_dev *dln2 = urb->context;
struct dln2_header *hdr = urb->transfer_buffer;
struct device *dev = &dln2->interface->dev;
u16 id, echo, handle, size;
u8 *data;
int len;
int err;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EPIPE:
/* this urb is terminated, clean up */
dev_dbg(dev, "urb shutting down with status %d\n", urb->status);
return;
default:
dev_dbg(dev, "nonzero urb status received %d\n", urb->status);
goto out;
}
if (urb->actual_length < sizeof(struct dln2_header)) {
dev_err(dev, "short response: %d\n", urb->actual_length);
goto out;
}
handle = le16_to_cpu(hdr->handle);
id = le16_to_cpu(hdr->id);
echo = le16_to_cpu(hdr->echo);
size = le16_to_cpu(hdr->size);
if (size != urb->actual_length) {
dev_err(dev, "size mismatch: handle %x cmd %x echo %x size %d actual %d\n",
handle, id, echo, size, urb->actual_length);
goto out;
}
if (handle >= DLN2_HANDLES) {
dev_warn(dev, "invalid handle %d\n", handle);
goto out;
}
data = urb->transfer_buffer + sizeof(struct dln2_header);
len = urb->actual_length - sizeof(struct dln2_header);
if (handle == DLN2_HANDLE_EVENT) {
dln2_run_event_callbacks(dln2, id, echo, data, len);
} else {
/* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
if (dln2_transfer_complete(dln2, urb, handle, echo))
return;
}
out:
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0)
dev_err(dev, "failed to resubmit RX URB: %d\n", err);
}
static void *dln2_prep_buf(u16 handle, u16 cmd, u16 echo, const void *obuf,
int *obuf_len, gfp_t gfp)
{
int len;
void *buf;
struct dln2_header *hdr;
len = *obuf_len + sizeof(*hdr);
buf = kmalloc(len, gfp);
if (!buf)
return NULL;
hdr = (struct dln2_header *)buf;
hdr->id = cpu_to_le16(cmd);
hdr->size = cpu_to_le16(len);
hdr->echo = cpu_to_le16(echo);
hdr->handle = cpu_to_le16(handle);
memcpy(buf + sizeof(*hdr), obuf, *obuf_len);
*obuf_len = len;
return buf;
}
static int dln2_send_wait(struct dln2_dev *dln2, u16 handle, u16 cmd, u16 echo,
const void *obuf, int obuf_len)
{
int ret = 0;
int len = obuf_len;
void *buf;
int actual;
buf = dln2_prep_buf(handle, cmd, echo, obuf, &len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = usb_bulk_msg(dln2->usb_dev,
usb_sndbulkpipe(dln2->usb_dev, dln2->ep_out),
buf, len, &actual, DLN2_USB_TIMEOUT);
kfree(buf);
return ret;
}
static bool find_free_slot(struct dln2_dev *dln2, u16 handle, int *slot)
{
struct dln2_mod_rx_slots *rxs;
unsigned long flags;
if (dln2->disconnect) {
*slot = -ENODEV;
return true;
}
rxs = &dln2->mod_rx_slots[handle];
spin_lock_irqsave(&rxs->lock, flags);
*slot = find_first_zero_bit(rxs->bmap, DLN2_MAX_RX_SLOTS);
if (*slot < DLN2_MAX_RX_SLOTS) {
struct dln2_rx_context *rxc = &rxs->slots[*slot];
set_bit(*slot, rxs->bmap);
rxc->in_use = true;
}
spin_unlock_irqrestore(&rxs->lock, flags);
return *slot < DLN2_MAX_RX_SLOTS;
}
static int alloc_rx_slot(struct dln2_dev *dln2, u16 handle)
{
int ret;
int slot;
/*
* No need to timeout here, the wait is bounded by the timeout in
* _dln2_transfer.
*/
ret = wait_event_interruptible(dln2->mod_rx_slots[handle].wq,
find_free_slot(dln2, handle, &slot));
if (ret < 0)
return ret;
return slot;
}
static void free_rx_slot(struct dln2_dev *dln2, u16 handle, int slot)
{
struct dln2_mod_rx_slots *rxs;
struct urb *urb = NULL;
unsigned long flags;
struct dln2_rx_context *rxc;
rxs = &dln2->mod_rx_slots[handle];
spin_lock_irqsave(&rxs->lock, flags);
clear_bit(slot, rxs->bmap);
rxc = &rxs->slots[slot];
rxc->in_use = false;
urb = rxc->urb;
rxc->urb = NULL;
reinit_completion(&rxc->done);
spin_unlock_irqrestore(&rxs->lock, flags);
if (urb) {
int err;
struct device *dev = &dln2->interface->dev;
err = usb_submit_urb(urb, GFP_KERNEL);
if (err < 0)
dev_err(dev, "failed to resubmit RX URB: %d\n", err);
}
wake_up_interruptible(&rxs->wq);
}
static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
const void *obuf, unsigned obuf_len,
void *ibuf, unsigned *ibuf_len)
{
int ret = 0;
int rx_slot;
struct dln2_response *rsp;
struct dln2_rx_context *rxc;
struct device *dev = &dln2->interface->dev;
const unsigned long timeout = DLN2_USB_TIMEOUT * HZ / 1000;
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
int size;
spin_lock(&dln2->disconnect_lock);
if (!dln2->disconnect)
dln2->active_transfers++;
else
ret = -ENODEV;
spin_unlock(&dln2->disconnect_lock);
if (ret)
return ret;
rx_slot = alloc_rx_slot(dln2, handle);
if (rx_slot < 0) {
ret = rx_slot;
goto out_decr;
}
ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
if (ret < 0) {
dev_err(dev, "USB write failed: %d\n", ret);
goto out_free_rx_slot;
}
rxc = &rxs->slots[rx_slot];
ret = wait_for_completion_interruptible_timeout(&rxc->done, timeout);
if (ret <= 0) {
if (!ret)
ret = -ETIMEDOUT;
goto out_free_rx_slot;
} else {
ret = 0;
}
if (dln2->disconnect) {
ret = -ENODEV;
goto out_free_rx_slot;
}
/* if we got here we know that the response header has been checked */
rsp = rxc->urb->transfer_buffer;
size = le16_to_cpu(rsp->hdr.size);
if (size < sizeof(*rsp)) {
ret = -EPROTO;
goto out_free_rx_slot;
}
if (le16_to_cpu(rsp->result) > 0x80) {
dev_dbg(dev, "%d received response with error %d\n",
handle, le16_to_cpu(rsp->result));
ret = -EREMOTEIO;
goto out_free_rx_slot;
}
if (!ibuf)
goto out_free_rx_slot;
if (*ibuf_len > size - sizeof(*rsp))
*ibuf_len = size - sizeof(*rsp);
memcpy(ibuf, rsp + 1, *ibuf_len);
out_free_rx_slot:
free_rx_slot(dln2, handle, rx_slot);
out_decr:
spin_lock(&dln2->disconnect_lock);
dln2->active_transfers--;
spin_unlock(&dln2->disconnect_lock);
if (dln2->disconnect)
wake_up(&dln2->disconnect_wq);
return ret;
}
int dln2_transfer(struct platform_device *pdev, u16 cmd,
const void *obuf, unsigned obuf_len,
void *ibuf, unsigned *ibuf_len)
{
struct dln2_platform_data *dln2_pdata;
struct dln2_dev *dln2;
u16 handle;
dln2 = dev_get_drvdata(pdev->dev.parent);
dln2_pdata = dev_get_platdata(&pdev->dev);
handle = dln2_pdata->handle;
return _dln2_transfer(dln2, handle, cmd, obuf, obuf_len, ibuf,
ibuf_len);
}
EXPORT_SYMBOL(dln2_transfer);
static int dln2_check_hw(struct dln2_dev *dln2)
{
int ret;
__le32 hw_type;
int len = sizeof(hw_type);
ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_VER,
NULL, 0, &hw_type, &len);
if (ret < 0)
return ret;
if (len < sizeof(hw_type))
return -EREMOTEIO;
if (le32_to_cpu(hw_type) != DLN2_HW_ID) {
dev_err(&dln2->interface->dev, "Device ID 0x%x not supported\n",
le32_to_cpu(hw_type));
return -ENODEV;
}
return 0;
}
static int dln2_print_serialno(struct dln2_dev *dln2)
{
int ret;
__le32 serial_no;
int len = sizeof(serial_no);
struct device *dev = &dln2->interface->dev;
ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_SN, NULL, 0,
&serial_no, &len);
if (ret < 0)
return ret;
if (len < sizeof(serial_no))
return -EREMOTEIO;
dev_info(dev, "Diolan DLN2 serial %u\n", le32_to_cpu(serial_no));
return 0;
}
static int dln2_hw_init(struct dln2_dev *dln2)
{
int ret;
ret = dln2_check_hw(dln2);
if (ret < 0)
return ret;
return dln2_print_serialno(dln2);
}
static void dln2_free_rx_urbs(struct dln2_dev *dln2)
{
int i;
for (i = 0; i < DLN2_MAX_URBS; i++) {
usb_kill_urb(dln2->rx_urb[i]);
usb_free_urb(dln2->rx_urb[i]);
kfree(dln2->rx_buf[i]);
}
}
static void dln2_free(struct dln2_dev *dln2)
{
dln2_free_rx_urbs(dln2);
usb_put_dev(dln2->usb_dev);
kfree(dln2);
}
static int dln2_setup_rx_urbs(struct dln2_dev *dln2,
struct usb_host_interface *hostif)
{
int i;
int ret;
const int rx_max_size = DLN2_RX_BUF_SIZE;
struct device *dev = &dln2->interface->dev;
for (i = 0; i < DLN2_MAX_URBS; i++) {
dln2->rx_buf[i] = kmalloc(rx_max_size, GFP_KERNEL);
if (!dln2->rx_buf[i])
return -ENOMEM;
dln2->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
if (!dln2->rx_urb[i])
return -ENOMEM;
usb_fill_bulk_urb(dln2->rx_urb[i], dln2->usb_dev,
usb_rcvbulkpipe(dln2->usb_dev, dln2->ep_in),
dln2->rx_buf[i], rx_max_size, dln2_rx, dln2);
ret = usb_submit_urb(dln2->rx_urb[i], GFP_KERNEL);
if (ret < 0) {
dev_err(dev, "failed to submit RX URB: %d\n", ret);
return ret;
}
}
return 0;
}
static struct dln2_platform_data dln2_pdata_gpio = {
.handle = DLN2_HANDLE_GPIO,
};
/* Only one I2C port seems to be supported on current hardware */
static struct dln2_platform_data dln2_pdata_i2c = {
.handle = DLN2_HANDLE_I2C,
.port = 0,
};
/* Only one SPI port supported */
static struct dln2_platform_data dln2_pdata_spi = {
.handle = DLN2_HANDLE_SPI,
.port = 0,
};
static const struct mfd_cell dln2_devs[] = {
{
.name = "dln2-gpio",
.platform_data = &dln2_pdata_gpio,
.pdata_size = sizeof(struct dln2_platform_data),
},
{
.name = "dln2-i2c",
.platform_data = &dln2_pdata_i2c,
.pdata_size = sizeof(struct dln2_platform_data),
},
{
.name = "dln2-spi",
.platform_data = &dln2_pdata_spi,
.pdata_size = sizeof(struct dln2_platform_data),
},
};
static void dln2_disconnect(struct usb_interface *interface)
{
struct dln2_dev *dln2 = usb_get_intfdata(interface);
int i, j;
/* don't allow starting new transfers */
spin_lock(&dln2->disconnect_lock);
dln2->disconnect = true;
spin_unlock(&dln2->disconnect_lock);
/* cancel in progress transfers */
for (i = 0; i < DLN2_HANDLES; i++) {
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[i];
unsigned long flags;
spin_lock_irqsave(&rxs->lock, flags);
/* cancel all response waiters */
for (j = 0; j < DLN2_MAX_RX_SLOTS; j++) {
struct dln2_rx_context *rxc = &rxs->slots[j];
if (rxc->in_use)
complete(&rxc->done);
}
spin_unlock_irqrestore(&rxs->lock, flags);
}
/* wait for transfers to end */
wait_event(dln2->disconnect_wq, !dln2->active_transfers);
mfd_remove_devices(&interface->dev);
dln2_free(dln2);
}
static int dln2_probe(struct usb_interface *interface,
const struct usb_device_id *usb_id)
{
struct usb_host_interface *hostif = interface->cur_altsetting;
struct device *dev = &interface->dev;
struct dln2_dev *dln2;
int ret;
int i, j;
if (hostif->desc.bInterfaceNumber != 0 ||
hostif->desc.bNumEndpoints < 2)
return -ENODEV;
dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
if (!dln2)
return -ENOMEM;
dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
dln2->interface = interface;
usb_set_intfdata(interface, dln2);
init_waitqueue_head(&dln2->disconnect_wq);
for (i = 0; i < DLN2_HANDLES; i++) {
init_waitqueue_head(&dln2->mod_rx_slots[i].wq);
spin_lock_init(&dln2->mod_rx_slots[i].lock);
for (j = 0; j < DLN2_MAX_RX_SLOTS; j++)
init_completion(&dln2->mod_rx_slots[i].slots[j].done);
}
spin_lock_init(&dln2->event_cb_lock);
spin_lock_init(&dln2->disconnect_lock);
INIT_LIST_HEAD(&dln2->event_cb_list);
ret = dln2_setup_rx_urbs(dln2, hostif);
if (ret)
goto out_cleanup;
ret = dln2_hw_init(dln2);
if (ret < 0) {
dev_err(dev, "failed to initialize hardware\n");
goto out_cleanup;
}
ret = mfd_add_hotplug_devices(dev, dln2_devs, ARRAY_SIZE(dln2_devs));
if (ret != 0) {
dev_err(dev, "failed to add mfd devices to core\n");
goto out_cleanup;
}
return 0;
out_cleanup:
dln2_free(dln2);
return ret;
}
static const struct usb_device_id dln2_table[] = {
{ USB_DEVICE(0xa257, 0x2013) },
{ }
};
MODULE_DEVICE_TABLE(usb, dln2_table);
static struct usb_driver dln2_driver = {
.name = "dln2",
.probe = dln2_probe,
.disconnect = dln2_disconnect,
.id_table = dln2_table,
};
module_usb_driver(dln2_driver);
MODULE_AUTHOR("Octavian Purdila <[email protected]>");
MODULE_DESCRIPTION("Core driver for the Diolan DLN2 interface adapter");
MODULE_LICENSE("GPL v2");

View file

@ -193,11 +193,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
if (ret)
mfd_remove_devices(&dev->dev);
return ret;
return mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
}
static void lpc_sch_remove(struct pci_dev *dev)

View file

@ -1,7 +1,7 @@
/*
* max14577.c - mfd core driver for the Maxim 14577/77836
*
* Copyright (C) 2014 Samsung Electrnoics
* Copyright (C) 2014 Samsung Electronics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*

View file

@ -43,9 +43,15 @@
static const struct mfd_cell max77693_devs[] = {
{ .name = "max77693-pmic", },
{ .name = "max77693-charger", },
{
.name = "max77693-charger",
.of_compatible = "maxim,max77693-charger",
},
{ .name = "max77693-muic", },
{ .name = "max77693-haptic", },
{
.name = "max77693-haptic",
.of_compatible = "maxim,max77693-haptic",
},
{
.name = "max77693-flash",
.of_compatible = "maxim,max77693-flash",
@ -147,6 +153,12 @@ static const struct regmap_irq_chip max77693_muic_irq_chip = {
.num_irqs = ARRAY_SIZE(max77693_muic_irqs),
};
static const struct regmap_config max77693_regmap_haptic_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX77693_HAPTIC_REG_END,
};
static int max77693_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -196,6 +208,15 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
}
i2c_set_clientdata(max77693->haptic, max77693);
max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic,
&max77693_regmap_haptic_config);
if (IS_ERR(max77693->regmap_haptic)) {
ret = PTR_ERR(max77693->regmap_haptic);
dev_err(max77693->dev,
"failed to initialize haptic register map: %d\n", ret);
goto err_regmap;
}
/*
* Initialize register map for MUIC device because use regmap-muic
* instance of MUIC device when irq of max77693 is initialized
@ -207,7 +228,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(max77693->regmap_muic);
dev_err(max77693->dev,
"failed to allocate register map: %d\n", ret);
goto err_regmap_muic;
goto err_regmap;
}
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@ -217,7 +238,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
&max77693->irq_data_led);
if (ret) {
dev_err(max77693->dev, "failed to add irq chip: %d\n", ret);
goto err_regmap_muic;
goto err_regmap;
}
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@ -280,7 +301,7 @@ err_irq_charger:
regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys);
err_irq_topsys:
regmap_del_irq_chip(max77693->irq, max77693->irq_data_led);
err_regmap_muic:
err_regmap:
i2c_unregister_device(max77693->haptic);
err_i2c_haptic:
i2c_unregister_device(max77693->muic);

View file

@ -125,9 +125,15 @@ static int mfd_add_device(struct device *parent, int id,
struct platform_device *pdev;
struct device_node *np = NULL;
int ret = -ENOMEM;
int platform_id;
int r;
pdev = platform_device_alloc(cell->name, id + cell->id);
if (id < 0)
platform_id = id;
else
platform_id = id + cell->id;
pdev = platform_device_alloc(cell->name, platform_id);
if (!pdev)
goto fail_alloc;

View file

@ -130,6 +130,12 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
{
int err;
err = rtsx_gops_pm_reset(pcr);
if (err < 0)
return err;
/* Optimize RX sensitivity */
return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
}

View file

@ -130,6 +130,10 @@ static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
{
int err;
err = rtsx_gops_pm_reset(pcr);
if (err < 0)
return err;
err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV,
PHY_REG_REV_RESV | PHY_REG_REV_RXIDLE_LATCHED |
PHY_REG_REV_P1_EN | PHY_REG_REV_RXIDLE_EN |

37
drivers/mfd/rtsx_gops.c Normal file
View file

@ -0,0 +1,37 @@
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Micky Ching <micky_ching@realsil.com.cn>
*/
#include <linux/mfd/rtsx_pci.h>
#include "rtsx_pcr.h"
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr)
{
int err;
/* init aspm */
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0x00);
err = rtsx_pci_update_cfg_byte(pcr, LCTLR, ~LCTLR_ASPM_CTL_MASK, 0x00);
if (err < 0)
return err;
/* reset PM_CTRL3 before send buffer cmd */
return rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
}

View file

@ -72,4 +72,7 @@ do { \
pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \
} while (0)
/* generic operations */
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
#endif

View file

@ -647,8 +647,8 @@ static int rtsx_usb_probe(struct usb_interface *intf,
/* initialize USB SG transfer timer */
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells,
ARRAY_SIZE(rtsx_usb_cells));
if (ret)
goto out_init_fail;

View file

@ -27,11 +27,11 @@
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mpu02.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
static const struct mfd_cell s5m8751_devs[] = {
@ -74,6 +74,15 @@ static const struct mfd_cell s2mps11_devs[] = {
}
};
static const struct mfd_cell s2mps13_devs[] = {
{ .name = "s2mps13-pmic", },
{ .name = "s2mps13-rtc", },
{
.name = "s2mps13-clk",
.of_compatible = "samsung,s2mps13-clk",
},
};
static const struct mfd_cell s2mps14_devs[] = {
{
.name = "s2mps14-pmic",
@ -107,6 +116,9 @@ static const struct of_device_id sec_dt_match[] = {
}, {
.compatible = "samsung,s2mps11-pmic",
.data = (void *)S2MPS11X,
}, {
.compatible = "samsung,s2mps13-pmic",
.data = (void *)S2MPS13X,
}, {
.compatible = "samsung,s2mps14-pmic",
.data = (void *)S2MPS14X,
@ -194,6 +206,15 @@ static const struct regmap_config s2mps11_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_config s2mps13_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S2MPS13_REG_LDODSCH5,
.volatile_reg = s2mps11_volatile,
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_config s2mps14_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@ -325,6 +346,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
case S2MPS11X:
regmap = &s2mps11_regmap_config;
break;
case S2MPS13X:
regmap = &s2mps13_regmap_config;
break;
case S2MPS14X:
regmap = &s2mps14_regmap_config;
break;
@ -378,6 +402,10 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_devs = s2mps11_devs;
num_sec_devs = ARRAY_SIZE(s2mps11_devs);
break;
case S2MPS13X:
sec_devs = s2mps13_devs;
num_sec_devs = ARRAY_SIZE(s2mps13_devs);
break;
case S2MPS14X:
sec_devs = s2mps14_devs;
num_sec_devs = ARRAY_SIZE(s2mps14_devs);
@ -432,15 +460,6 @@ static int sec_pmic_suspend(struct device *dev)
*/
disable_irq(sec_pmic->irq);
switch (sec_pmic->device_type) {
case S2MPS14X:
case S2MPU02:
regulator_suspend_prepare(PM_SUSPEND_MEM);
break;
default:
break;
}
return 0;
}

View file

@ -389,14 +389,22 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
.ack_base = S2MPS11_REG_INT1,
};
#define S2MPS1X_IRQ_CHIP_COMMON_DATA \
.irqs = s2mps14_irqs, \
.num_irqs = ARRAY_SIZE(s2mps14_irqs), \
.num_regs = 3, \
.status_base = S2MPS14_REG_INT1, \
.mask_base = S2MPS14_REG_INT1M, \
.ack_base = S2MPS14_REG_INT1 \
static const struct regmap_irq_chip s2mps13_irq_chip = {
.name = "s2mps13",
S2MPS1X_IRQ_CHIP_COMMON_DATA,
};
static const struct regmap_irq_chip s2mps14_irq_chip = {
.name = "s2mps14",
.irqs = s2mps14_irqs,
.num_irqs = ARRAY_SIZE(s2mps14_irqs),
.num_regs = 3,
.status_base = S2MPS14_REG_INT1,
.mask_base = S2MPS14_REG_INT1M,
.ack_base = S2MPS14_REG_INT1,
S2MPS1X_IRQ_CHIP_COMMON_DATA,
};
static const struct regmap_irq_chip s2mpu02_irq_chip = {
@ -452,6 +460,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
case S2MPS11X:
sec_irq_chip = &s2mps11_irq_chip;
break;
case S2MPS13X:
sec_irq_chip = &s2mps13_irq_chip;
break;
case S2MPS14X:
sec_irq_chip = &s2mps14_irq_chip;
break;

View file

@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@ -22,31 +23,94 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
static struct platform_driver syscon_driver;
static DEFINE_SPINLOCK(syscon_list_slock);
static LIST_HEAD(syscon_list);
struct syscon {
struct device_node *np;
struct regmap *regmap;
struct list_head list;
};
static int syscon_match_node(struct device *dev, void *data)
{
struct device_node *dn = data;
static struct regmap_config syscon_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
return (dev->of_node == dn) ? 1 : 0;
static struct syscon *of_syscon_register(struct device_node *np)
{
struct syscon *syscon;
struct regmap *regmap;
void __iomem *base;
int ret;
struct regmap_config syscon_config = syscon_regmap_config;
if (!of_device_is_compatible(np, "syscon"))
return ERR_PTR(-EINVAL);
syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
if (!syscon)
return ERR_PTR(-ENOMEM);
base = of_iomap(np, 0);
if (!base) {
ret = -ENOMEM;
goto err_map;
}
/* Parse the device's DT node for an endianness specification */
if (of_property_read_bool(np, "big-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
else if (of_property_read_bool(np, "little-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
regmap = regmap_init_mmio(NULL, base, &syscon_config);
if (IS_ERR(regmap)) {
pr_err("regmap init failed\n");
ret = PTR_ERR(regmap);
goto err_regmap;
}
syscon->regmap = regmap;
syscon->np = np;
spin_lock(&syscon_list_slock);
list_add_tail(&syscon->list, &syscon_list);
spin_unlock(&syscon_list_slock);
return syscon;
err_regmap:
iounmap(base);
err_map:
kfree(syscon);
return ERR_PTR(ret);
}
struct regmap *syscon_node_to_regmap(struct device_node *np)
{
struct syscon *syscon;
struct device *dev;
struct syscon *entry, *syscon = NULL;
dev = driver_find_device(&syscon_driver.driver, NULL, np,
syscon_match_node);
if (!dev)
return ERR_PTR(-EPROBE_DEFER);
spin_lock(&syscon_list_slock);
syscon = dev_get_drvdata(dev);
list_for_each_entry(entry, &syscon_list, list)
if (entry->np == np) {
syscon = entry;
break;
}
spin_unlock(&syscon_list_slock);
if (!syscon)
syscon = of_syscon_register(np);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
return syscon->regmap;
}
@ -110,17 +174,6 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
}
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
static const struct of_device_id of_syscon_match[] = {
{ .compatible = "syscon", },
{ },
};
static struct regmap_config syscon_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int syscon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -167,7 +220,6 @@ static struct platform_driver syscon_driver = {
.driver = {
.name = "syscon",
.owner = THIS_MODULE,
.of_match_table = of_syscon_match,
},
.probe = syscon_probe,
.id_table = syscon_ids,

View file

@ -87,7 +87,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
unsigned long flags;
u8 dev_ctl;
clk_enable(t7l66xb->clk32k);
clk_prepare_enable(t7l66xb->clk32k);
spin_lock_irqsave(&t7l66xb->lock, flags);
@ -118,7 +118,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
clk_disable(t7l66xb->clk32k);
clk_disable_unprepare(t7l66xb->clk32k);
return 0;
}
@ -285,7 +285,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
if (pdata && pdata->suspend)
pdata->suspend(dev);
clk_disable(t7l66xb->clk48m);
clk_disable_unprepare(t7l66xb->clk48m);
return 0;
}
@ -295,7 +295,7 @@ static int t7l66xb_resume(struct platform_device *dev)
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
clk_enable(t7l66xb->clk48m);
clk_prepare_enable(t7l66xb->clk48m);
if (pdata && pdata->resume)
pdata->resume(dev);
@ -369,7 +369,7 @@ static int t7l66xb_probe(struct platform_device *dev)
goto err_ioremap;
}
clk_enable(t7l66xb->clk48m);
clk_prepare_enable(t7l66xb->clk48m);
if (pdata && pdata->enable)
pdata->enable(dev);
@ -414,9 +414,9 @@ static int t7l66xb_remove(struct platform_device *dev)
int ret;
ret = pdata->disable(dev);
clk_disable(t7l66xb->clk48m);
clk_disable_unprepare(t7l66xb->clk48m);
clk_put(t7l66xb->clk48m);
clk_disable(t7l66xb->clk32k);
clk_disable_unprepare(t7l66xb->clk32k);
clk_put(t7l66xb->clk32k);
t7l66xb_detach_irq(dev);
iounmap(t7l66xb->scr);

View file

@ -241,10 +241,8 @@ static struct irq_domain_ops tc3589x_irq_ops = {
static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
{
int base = tc3589x->irq_base;
tc3589x->domain = irq_domain_add_simple(
np, TC3589x_NR_INTERNAL_IRQS, base,
np, TC3589x_NR_INTERNAL_IRQS, 0,
&tc3589x_irq_ops, tc3589x);
if (!tc3589x->domain) {
@ -298,7 +296,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_GPIO) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
ARRAY_SIZE(tc3589x_dev_gpio), NULL,
tc3589x->irq_base, tc3589x->domain);
0, tc3589x->domain);
if (ret) {
dev_err(tc3589x->dev, "failed to add gpio child\n");
return ret;
@ -309,7 +307,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_KEYPAD) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
ARRAY_SIZE(tc3589x_dev_keypad), NULL,
tc3589x->irq_base, tc3589x->domain);
0, tc3589x->domain);
if (ret) {
dev_err(tc3589x->dev, "failed to keypad child\n");
return ret;
@ -404,7 +402,6 @@ static int tc3589x_probe(struct i2c_client *i2c,
tc3589x->dev = &i2c->dev;
tc3589x->i2c = i2c;
tc3589x->pdata = pdata;
tc3589x->irq_base = pdata->irq_base;
switch (version) {
case TC3589X_TC35893:

View file

@ -52,7 +52,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
if (pdata && pdata->suspend)
pdata->suspend(dev);
clk_disable(tc6387xb->clk32k);
clk_disable_unprepare(tc6387xb->clk32k);
return 0;
}
@ -62,7 +62,7 @@ static int tc6387xb_resume(struct platform_device *dev)
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
clk_enable(tc6387xb->clk32k);
clk_prepare_enable(tc6387xb->clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
@ -100,7 +100,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
struct platform_device *dev = to_platform_device(mmc->dev.parent);
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
clk_enable(tc6387xb->clk32k);
clk_prepare_enable(tc6387xb->clk32k);
tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
tc6387xb_mmc_resources[0].start & 0xfffe);
@ -113,7 +113,7 @@ static int tc6387xb_mmc_disable(struct platform_device *mmc)
struct platform_device *dev = to_platform_device(mmc->dev.parent);
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
clk_disable(tc6387xb->clk32k);
clk_disable_unprepare(tc6387xb->clk32k);
return 0;
}
@ -214,7 +214,7 @@ static int tc6387xb_remove(struct platform_device *dev)
mfd_remove_devices(&dev->dev);
iounmap(tc6387xb->scr);
release_resource(&tc6387xb->rscr);
clk_disable(tc6387xb->clk32k);
clk_disable_unprepare(tc6387xb->clk32k);
clk_put(tc6387xb->clk32k);
kfree(tc6387xb);

View file

@ -263,6 +263,17 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
return 0;
}
static int tc6393xb_ohci_suspend(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent);
/* We can't properly store/restore OHCI state, so fail here */
if (tcpd->resume_restore)
return -EBUSY;
return tc6393xb_ohci_disable(dev);
}
static int tc6393xb_fb_enable(struct platform_device *dev)
{
struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
@ -403,7 +414,7 @@ static struct mfd_cell tc6393xb_cells[] = {
.num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
.resources = tc6393xb_ohci_resources,
.enable = tc6393xb_ohci_enable,
.suspend = tc6393xb_ohci_disable,
.suspend = tc6393xb_ohci_suspend,
.resume = tc6393xb_ohci_enable,
.disable = tc6393xb_ohci_disable,
},
@ -654,7 +665,7 @@ static int tc6393xb_probe(struct platform_device *dev)
goto err_ioremap;
}
ret = clk_enable(tc6393xb->clk);
ret = clk_prepare_enable(tc6393xb->clk);
if (ret)
goto err_clk_enable;
@ -717,7 +728,7 @@ err_gpio_add:
gpiochip_remove(&tc6393xb->gpio);
tcpd->disable(dev);
err_enable:
clk_disable(tc6393xb->clk);
clk_disable_unprepare(tc6393xb->clk);
err_clk_enable:
iounmap(tc6393xb->scr);
err_ioremap:
@ -748,7 +759,7 @@ static int tc6393xb_remove(struct platform_device *dev)
gpiochip_remove(&tc6393xb->gpio);
ret = tcpd->disable(dev);
clk_disable(tc6393xb->clk);
clk_disable_unprepare(tc6393xb->clk);
iounmap(tc6393xb->scr);
release_resource(&tc6393xb->rscr);
clk_put(tc6393xb->clk);
@ -776,7 +787,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
ioread8(tc6393xb->scr + SCR_GPI_BCR(i));
}
ret = tcpd->suspend(dev);
clk_disable(tc6393xb->clk);
clk_disable_unprepare(tc6393xb->clk);
return ret;
}
@ -788,7 +799,7 @@ static int tc6393xb_resume(struct platform_device *dev)
int ret;
int i;
clk_enable(tc6393xb->clk);
clk_prepare_enable(tc6393xb->clk);
ret = tcpd->resume(dev);
if (ret)

View file

@ -76,58 +76,58 @@ static struct mfd_cell tps65090s[] = {
static const struct regmap_irq tps65090_irqs[] = {
/* INT1 IRQs*/
[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
},
[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
},
[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
},
[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
},
[TPS65090_IRQ_CHARGING_COMPLETE] = {
.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
},
[TPS65090_IRQ_OVERLOAD_DCDC1] = {
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
},
[TPS65090_IRQ_OVERLOAD_DCDC2] = {
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
},
/* INT2 IRQs*/
[TPS65090_IRQ_OVERLOAD_DCDC3] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
},
[TPS65090_IRQ_OVERLOAD_FET1] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
},
[TPS65090_IRQ_OVERLOAD_FET2] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
},
[TPS65090_IRQ_OVERLOAD_FET3] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
},
[TPS65090_IRQ_OVERLOAD_FET4] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
},
[TPS65090_IRQ_OVERLOAD_FET5] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
},
[TPS65090_IRQ_OVERLOAD_FET6] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
},
[TPS65090_IRQ_OVERLOAD_FET7] = {
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
.reg_offset = 1,
.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
},
};
@ -176,7 +176,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match);
#endif
static int tps65090_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
int irq_base = 0;
@ -210,11 +210,11 @@ static int tps65090_i2c_probe(struct i2c_client *client,
if (client->irq) {
ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
&tps65090_irq_chip, &tps65090->irq_data);
if (ret) {
dev_err(&client->dev,
"IRQ init failed with err: %d\n", ret);
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
&tps65090_irq_chip, &tps65090->irq_data);
if (ret) {
dev_err(&client->dev,
"IRQ init failed with err: %d\n", ret);
return ret;
}
} else {
@ -223,8 +223,8 @@ static int tps65090_i2c_probe(struct i2c_client *client,
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
ARRAY_SIZE(tps65090s), NULL,
0, regmap_irq_get_domain(tps65090->irq_data));
ARRAY_SIZE(tps65090s), NULL,
0, regmap_irq_get_domain(tps65090->irq_data));
if (ret) {
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
ret);

View file

@ -33,9 +33,11 @@
static const struct mfd_cell tps65217s[] = {
{
.name = "tps65217-pmic",
.of_compatible = "ti,tps65217-pmic",
},
{
.name = "tps65217-bl",
.of_compatible = "ti,tps65217-bl",
},
};

View file

@ -830,6 +830,9 @@ static struct twl4030_power_data osc_off_idle = {
};
static struct of_device_id twl4030_power_of_match[] = {
{
.compatible = "ti,twl4030-power",
},
{
.compatible = "ti,twl4030-power-reset",
.data = &omap3_reset,

View file

@ -93,9 +93,8 @@ static int vprbrd_probe(struct usb_interface *interface,
version >> 8, version & 0xff,
vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
ret = mfd_add_devices(&interface->dev, PLATFORM_DEVID_AUTO,
vprbrd_devs, ARRAY_SIZE(vprbrd_devs), NULL, 0,
NULL);
ret = mfd_add_hotplug_devices(&interface->dev, vprbrd_devs,
ARRAY_SIZE(vprbrd_devs));
if (ret != 0) {
dev_err(&interface->dev, "Failed to add mfd devices to core.");
goto error;

View file

@ -336,8 +336,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
{ 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
{ 0x00000225, 0x0400 }, /* R549 - HP Ctrl 1L */
{ 0x00000226, 0x0400 }, /* R550 - HP Ctrl 1R */
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
{ 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
{ 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */
@ -1112,6 +1110,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@ -1949,6 +1949,8 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_SCRATCH_1:
case ARIZONA_DSP1_SCRATCH_2:
case ARIZONA_DSP1_SCRATCH_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_HP_DACVAL:
case ARIZONA_MIC_DETECT_3:

View file

@ -895,8 +895,16 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
{ 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
{ 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
{ 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */
{ 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */
{ 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */
{ 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */
{ 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
{ 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
{ 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */
{ 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */
{ 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */
{ 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */
{ 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
{ 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
{ 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
@ -1790,6 +1798,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@ -1934,8 +1944,16 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF2_FRAME_CTRL_2:
case ARIZONA_AIF2_FRAME_CTRL_3:
case ARIZONA_AIF2_FRAME_CTRL_4:
case ARIZONA_AIF2_FRAME_CTRL_5:
case ARIZONA_AIF2_FRAME_CTRL_6:
case ARIZONA_AIF2_FRAME_CTRL_7:
case ARIZONA_AIF2_FRAME_CTRL_8:
case ARIZONA_AIF2_FRAME_CTRL_11:
case ARIZONA_AIF2_FRAME_CTRL_12:
case ARIZONA_AIF2_FRAME_CTRL_13:
case ARIZONA_AIF2_FRAME_CTRL_14:
case ARIZONA_AIF2_FRAME_CTRL_15:
case ARIZONA_AIF2_FRAME_CTRL_16:
case ARIZONA_AIF2_TX_ENABLES:
case ARIZONA_AIF2_RX_ENABLES:
case ARIZONA_AIF3_BCLK_CTRL:
@ -2825,6 +2843,8 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS:
case ARIZONA_MIC_DETECT_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_INPUT_ENABLES_STATUS:
case ARIZONA_OUTPUT_STATUS_1:

View file

@ -308,7 +308,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
goto err;
}
mode = id2 & WM8350_CONF_STS_MASK >> 10;
mode = (id2 & WM8350_CONF_STS_MASK) >> 10;
cust_id = id2 & WM8350_CUST_ID_MASK;
chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
dev_info(wm8350->dev,

View file

@ -670,6 +670,7 @@ static const struct reg_default wm8997_reg_default[] = {
{ 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
{ 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
{ 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
{ 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */
{ 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
{ 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
{ 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
@ -886,6 +887,8 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@ -1328,6 +1331,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_INTERRUPT_STATUS_4:
case ARIZONA_INTERRUPT_STATUS_5:
case ARIZONA_INTERRUPT_STATUS_1_MASK:
case ARIZONA_INTERRUPT_STATUS_2_MASK:
case ARIZONA_INTERRUPT_STATUS_3_MASK:
case ARIZONA_INTERRUPT_STATUS_4_MASK:
case ARIZONA_INTERRUPT_STATUS_5_MASK:
@ -1477,6 +1481,8 @@ static bool wm8997_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_SAMPLE_RATE_3_STATUS:
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
case ARIZONA_MIC_DETECT_3:
case ARIZONA_HP_CTRL_1L:
case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_INPUT_ENABLES_STATUS:
case ARIZONA_OUTPUT_STATUS_1: