Merge tag 'mfd-for-linus-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into next
Pull MFD updates from Lee Jones: "Changes to existing drivers: - increase DT coverage: arizona, mc13xxx, stmpe-i2c, syscon, sun6i-prcm - regmap use of and/or clean-up: tps65090, twl6040 - basic renaming: max14577 - use new cpufreq helpers: db8500-prcmu - increase regulator support: stmpe, arizona, wm5102 - reduce legacy GPIO overhead: stmpe - provide necessary remove path: bcm590xx - expand sysfs presence: kempld - move driver specific code out to drivers: rtc-s5m, arizona - clk handling: twl6040 - use managed (devm_*) resources: ipaq-micro - clean-up/remove unused/duplicated code: tps65218, sec, pm8921, abx500-core, db8500-prcmu, menelaus - build/boot/sematic bug fixes: rtsx_usb, stmpe, bcm590xx, abx500, mc13xxx, rdc321x-southbridge, mfd-core, sec, max14577, syscon, cros_ec_spi - constify stuff: sm501, tps65910, tps6507x, tps6586x, max77686, max8997, kempld, max77693, max8907, rtsx_usb, db8500-prcmu, max8998, wm8400, sec, lp3943, max14577, as3711, omap-usb-host, ipaq-micro Support for new devices: - add support for max77836 into max14577 - add support for tps658640 into tps6586x - add support for cros-ec-i2c-tunnel into cros_ec - add new driver for rtsx_usb_sdmmc and rtsx_usb_ms - add new driver for axp20x - add new driver for sun6i-prcm - add new driver for ipaq-micro" * tag 'mfd-for-linus-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (77 commits) mfd: wm5102: Correct default for LDO Control 2 register mfd: menelaus: Use module_i2c_driver mfd: tps65218: Terminate of match table mfd: db8500-prcmu: Remove check for CONFIG_DBX500_PRCMU_DEBUG mfd: ti-keystone-devctrl: Add bindings for device state control mfd: palmas: Format the header file mfd: abx500-core: Remove unused function abx500_dump_all_banks() mfd: arizona: Correct addresses of always-on trigger registers mfd: max14577: Cast to architecture agnostic data type i2c: ChromeOS EC tunnel driver mfd: cros_ec: Sync to the latest cros_ec_commands.h from EC sources mfd: cros_ec: spi: Increase cros_ec_spi deadline from 5ms to 100ms mfd: cros_ec: spi: Make the cros_ec_spi timeout more reliable mfd: cros_ec: spi: Add mutex to cros_ec_spi mfd: cros_ec: spi: Calculate delay between transfers correctly mfd: arizona: Correct error message for addition of main IRQ chip mfd: wm8997: Add registers for high power mode mfd: arizona: Add MICVDD to mapped regulators mfd: ipaq-micro: Make mfd_cell array const mfd: ipaq-micro: Use devm_ioremap_resource() ...
This commit is contained in:
@@ -67,6 +67,18 @@ config MFD_BCM590XX
|
||||
help
|
||||
Support for the BCM590xx PMUs from Broadcom
|
||||
|
||||
config MFD_AXP20X
|
||||
bool "X-Powers AXP20X"
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y
|
||||
help
|
||||
If you say Y here you get support for the X-Powers AXP202 and AXP209.
|
||||
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.
|
||||
|
||||
config MFD_CROS_EC
|
||||
tristate "ChromeOS Embedded Controller"
|
||||
select MFD_CORE
|
||||
@@ -250,6 +262,16 @@ config MFD_INTEL_MSIC
|
||||
Passage) chip. This chip embeds audio, battery, GPIO, etc.
|
||||
devices used in Intel Medfield platforms.
|
||||
|
||||
config MFD_IPAQ_MICRO
|
||||
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
|
||||
depends on SA1100_H3100 || SA1100_H3600
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this to get support for the Microcontroller found in
|
||||
the Compaq iPAQ handheld computers. This is an Atmel
|
||||
AT90LS8535 microcontroller flashed with a special iPAQ
|
||||
firmware using the custom protocol implemented in this driver.
|
||||
|
||||
config MFD_JANZ_CMODIO
|
||||
tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
|
||||
select MFD_CORE
|
||||
@@ -675,6 +697,7 @@ config MFD_DB8500_PRCMU
|
||||
config MFD_STMPE
|
||||
bool "STMicroelectronics STMPE"
|
||||
depends on (I2C=y || SPI_MASTER=y)
|
||||
depends on OF
|
||||
select MFD_CORE
|
||||
help
|
||||
Support for the STMPE family of I/O Expanders from
|
||||
@@ -719,6 +742,14 @@ config MFD_STA2X11
|
||||
select MFD_CORE
|
||||
select REGMAP_MMIO
|
||||
|
||||
config MFD_SUN6I_PRCM
|
||||
bool "Allwinner A31 PRCM controller"
|
||||
depends on ARCH_SUNXI
|
||||
select MFD_CORE
|
||||
help
|
||||
Support for the PRCM (Power/Reset/Clock Management) unit available
|
||||
in A31 SoC.
|
||||
|
||||
config MFD_SYSCON
|
||||
bool "System Controller Register R/W Based on Regmap"
|
||||
select REGMAP_MMIO
|
||||
|
@@ -29,6 +29,7 @@ obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
|
||||
obj-$(CONFIG_MFD_STMPE) += stmpe.o
|
||||
obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
|
||||
obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
|
||||
obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o
|
||||
obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
|
||||
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
|
||||
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
|
||||
@@ -102,6 +103,7 @@ 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_AXP20X) += axp20x.o
|
||||
|
||||
obj-$(CONFIG_MFD_LP3943) += lp3943.o
|
||||
obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
|
||||
@@ -166,3 +168,4 @@ obj-$(CONFIG_MFD_RETU) += retu-mfd.o
|
||||
obj-$(CONFIG_MFD_AS3711) += as3711.o
|
||||
obj-$(CONFIG_MFD_AS3722) += as3722.o
|
||||
obj-$(CONFIG_MFD_STW481X) += stw481x.o
|
||||
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
|
||||
|
@@ -151,22 +151,6 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
|
||||
}
|
||||
EXPORT_SYMBOL(abx500_startup_irq_enabled);
|
||||
|
||||
void abx500_dump_all_banks(void)
|
||||
{
|
||||
struct abx500_ops *ops;
|
||||
struct device dummy_child = {NULL};
|
||||
struct abx500_device_entry *dev_entry;
|
||||
|
||||
list_for_each_entry(dev_entry, &abx500_list, list) {
|
||||
dummy_child.parent = dev_entry->dev;
|
||||
ops = &dev_entry->ops;
|
||||
|
||||
if ((ops != NULL) && (ops->dump_all_banks != NULL))
|
||||
ops->dump_all_banks(&dummy_child);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(abx500_dump_all_banks);
|
||||
|
||||
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
|
||||
MODULE_DESCRIPTION("ABX500 core driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -583,6 +583,7 @@ static const char *wm5102_supplies[] = {
|
||||
"CPVDD",
|
||||
"SPKVDDL",
|
||||
"SPKVDDR",
|
||||
"MICVDD",
|
||||
};
|
||||
|
||||
static const struct mfd_cell wm5102_devs[] = {
|
||||
|
@@ -285,7 +285,7 @@ int arizona_irq_init(struct arizona *arizona)
|
||||
IRQF_ONESHOT, -1, irq,
|
||||
&arizona->irq_chip);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
|
||||
dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
|
||||
goto err_aod;
|
||||
}
|
||||
|
||||
|
@@ -114,7 +114,7 @@ static const struct regmap_config as3711_regmap_config = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id as3711_of_match[] = {
|
||||
static const struct of_device_id as3711_of_match[] = {
|
||||
{.compatible = "ams,as3711",},
|
||||
{}
|
||||
};
|
||||
|
258
drivers/mfd/axp20x.c
Normal file
258
drivers/mfd/axp20x.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Carlo Caione <carlo@caione.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/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define AXP20X_OFF 0x80
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp20x_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp20x_writeable_table = {
|
||||
.yes_ranges = axp20x_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp20x_volatile_table = {
|
||||
.yes_ranges = axp20x_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
|
||||
};
|
||||
|
||||
static struct resource axp20x_pek_resources[] = {
|
||||
{
|
||||
.name = "PEK_DBR",
|
||||
.start = AXP20X_IRQ_PEK_RIS_EDGE,
|
||||
.end = AXP20X_IRQ_PEK_RIS_EDGE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
.name = "PEK_DBF",
|
||||
.start = AXP20X_IRQ_PEK_FAL_EDGE,
|
||||
.end = AXP20X_IRQ_PEK_FAL_EDGE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config axp20x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.wr_table = &axp20x_writeable_table,
|
||||
.volatile_table = &axp20x_volatile_table,
|
||||
.max_register = AXP20X_FG_RES,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define AXP20X_IRQ(_irq, _off, _mask) \
|
||||
[AXP20X_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),
|
||||
};
|
||||
|
||||
static const struct of_device_id axp20x_of_match[] = {
|
||||
{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
|
||||
{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axp20x_of_match);
|
||||
|
||||
/*
|
||||
* This is useless for OF-enabled devices, but it is needed by I2C subsystem
|
||||
*/
|
||||
static const struct i2c_device_id axp20x_i2c_id[] = {
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static const char * const axp20x_supplies[] = {
|
||||
"acin",
|
||||
"vin2",
|
||||
"vin3",
|
||||
"ldo24in",
|
||||
"ldo3in",
|
||||
"ldo5in",
|
||||
};
|
||||
|
||||
static struct mfd_cell axp20x_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp20x_pek_resources),
|
||||
.resources = axp20x_pek_resources,
|
||||
}, {
|
||||
.name = "axp20x-regulator",
|
||||
.parent_supplies = axp20x_supplies,
|
||||
.num_parent_supplies = ARRAY_SIZE(axp20x_supplies),
|
||||
},
|
||||
};
|
||||
|
||||
static struct axp20x_dev *axp20x_pm_power_off;
|
||||
static void axp20x_power_off(void)
|
||||
{
|
||||
regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
|
||||
AXP20X_OFF);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
axp20x->i2c_client = i2c;
|
||||
axp20x->dev = &i2c->dev;
|
||||
dev_set_drvdata(axp20x->dev, axp20x);
|
||||
|
||||
axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
|
||||
if (IS_ERR(axp20x->regmap)) {
|
||||
ret = PTR_ERR(axp20x->regmap);
|
||||
dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
&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);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
|
||||
regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!pm_power_off) {
|
||||
axp20x_pm_power_off = axp20x;
|
||||
pm_power_off = axp20x_power_off;
|
||||
}
|
||||
|
||||
dev_info(&i2c->dev, "AXP20X driver loaded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axp20x_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
|
||||
|
||||
if (axp20x == axp20x_pm_power_off) {
|
||||
axp20x_pm_power_off = NULL;
|
||||
pm_power_off = NULL;
|
||||
}
|
||||
|
||||
mfd_remove_devices(axp20x->dev);
|
||||
regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver axp20x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "axp20x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(axp20x_of_match),
|
||||
},
|
||||
.probe = axp20x_i2c_probe,
|
||||
.remove = axp20x_i2c_remove,
|
||||
.id_table = axp20x_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(axp20x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
|
||||
MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
|
||||
MODULE_LICENSE("GPL");
|
@@ -96,6 +96,12 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bcm590xx_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
mfd_remove_devices(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm590xx_of_match[] = {
|
||||
{ .compatible = "brcm,bcm59056" },
|
||||
{ }
|
||||
@@ -115,6 +121,7 @@ static struct i2c_driver bcm590xx_i2c_driver = {
|
||||
.of_match_table = of_match_ptr(bcm590xx_of_match),
|
||||
},
|
||||
.probe = bcm590xx_i2c_probe,
|
||||
.remove = bcm590xx_i2c_remove,
|
||||
.id_table = bcm590xx_i2c_id,
|
||||
};
|
||||
module_i2c_driver(bcm590xx_i2c_driver);
|
||||
@@ -122,4 +129,4 @@ module_i2c_driver(bcm590xx_i2c_driver);
|
||||
MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
|
||||
MODULE_DESCRIPTION("BCM590xx multi-function driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bcm590xx");
|
||||
MODULE_ALIAS("i2c:bcm590xx");
|
||||
|
@@ -30,7 +30,7 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
uint8_t *out;
|
||||
int csum, i;
|
||||
|
||||
BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE);
|
||||
BUG_ON(msg->out_len > EC_PROTO2_MAX_PARAM_SIZE);
|
||||
out = ec_dev->dout;
|
||||
out[0] = EC_CMD_VERSION0 + msg->version;
|
||||
out[1] = msg->cmd;
|
||||
@@ -90,6 +90,11 @@ static const struct mfd_cell cros_devs[] = {
|
||||
.id = 1,
|
||||
.of_compatible = "google,cros-ec-keyb",
|
||||
},
|
||||
{
|
||||
.name = "cros-ec-i2c-tunnel",
|
||||
.id = 2,
|
||||
.of_compatible = "google,cros-ec-i2c-tunnel",
|
||||
},
|
||||
};
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
@@ -184,3 +189,6 @@ int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
EXPORT_SYMBOL(cros_ec_resume);
|
||||
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ChromeOS EC core driver");
|
||||
|
@@ -39,14 +39,22 @@
|
||||
#define EC_MSG_PREAMBLE_COUNT 32
|
||||
|
||||
/*
|
||||
* We must get a response from the EC in 5ms. This is a very long
|
||||
* time, but the flash write command can take 2-3ms. The EC command
|
||||
* processing is currently not very fast (about 500us). We could
|
||||
* look at speeding this up and making the flash write command a
|
||||
* 'slow' command, requiring a GET_STATUS wait loop, like flash
|
||||
* erase.
|
||||
*/
|
||||
#define EC_MSG_DEADLINE_MS 5
|
||||
* Allow for a long time for the EC to respond. We support i2c
|
||||
* tunneling and support fairly long messages for the tunnel (249
|
||||
* bytes long at the moment). If we're talking to a 100 kHz device
|
||||
* on the other end and need to transfer ~256 bytes, then we need:
|
||||
* 10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms
|
||||
*
|
||||
* We'll wait 4 times that to handle clock stretching and other
|
||||
* paranoia.
|
||||
*
|
||||
* It's pretty unlikely that we'll really see a 249 byte tunnel in
|
||||
* anything other than testing. If this was more common we might
|
||||
* consider having slow commands like this require a GET_STATUS
|
||||
* wait loop. The 'flash write' command would be another candidate
|
||||
* for this, clocking in at 2-3ms.
|
||||
*/
|
||||
#define EC_MSG_DEADLINE_MS 100
|
||||
|
||||
/*
|
||||
* Time between raising the SPI chip select (for the end of a
|
||||
@@ -65,11 +73,13 @@
|
||||
* if no record
|
||||
* @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that
|
||||
* is sent when we want to turn off CS at the end of a transaction.
|
||||
* @lock: mutex to ensure only one user of cros_ec_command_spi_xfer at a time
|
||||
*/
|
||||
struct cros_ec_spi {
|
||||
struct spi_device *spi;
|
||||
s64 last_transfer_ns;
|
||||
unsigned int end_of_msg_delay;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static void debug_packet(struct device *dev, const char *name, u8 *ptr,
|
||||
@@ -111,7 +121,9 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
||||
|
||||
/* Receive data until we see the header byte */
|
||||
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
|
||||
do {
|
||||
while (true) {
|
||||
unsigned long start_jiffies = jiffies;
|
||||
|
||||
memset(&trans, 0, sizeof(trans));
|
||||
trans.cs_change = 1;
|
||||
trans.rx_buf = ptr = ec_dev->din;
|
||||
@@ -132,12 +144,19 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ptr != end)
|
||||
break;
|
||||
|
||||
if (time_after(jiffies, deadline)) {
|
||||
/*
|
||||
* Use the time at the start of the loop as a timeout. This
|
||||
* gives us one last shot at getting the transfer and is useful
|
||||
* in case we got context switched out for a while.
|
||||
*/
|
||||
if (time_after(start_jiffies, deadline)) {
|
||||
dev_warn(ec_dev->dev, "EC failed to respond in time\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} while (ptr == end);
|
||||
}
|
||||
|
||||
/*
|
||||
* ptr now points to the header byte. Copy any valid data to the
|
||||
@@ -208,6 +227,13 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
|
||||
int ret = 0, final_ret;
|
||||
struct timespec ts;
|
||||
|
||||
/*
|
||||
* We have the shared ec_dev buffer plus we do lots of separate spi_sync
|
||||
* calls, so we need to make sure only one person is using this at a
|
||||
* time.
|
||||
*/
|
||||
mutex_lock(&ec_spi->lock);
|
||||
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
@@ -219,7 +245,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
|
||||
ktime_get_ts(&ts);
|
||||
delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns;
|
||||
if (delay < EC_SPI_RECOVERY_TIME_NS)
|
||||
ndelay(delay);
|
||||
ndelay(EC_SPI_RECOVERY_TIME_NS - delay);
|
||||
}
|
||||
|
||||
/* Transmit phase - send our message */
|
||||
@@ -260,7 +286,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
|
||||
ret = final_ret;
|
||||
if (ret < 0) {
|
||||
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
|
||||
return ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* check response error code */
|
||||
@@ -269,14 +295,16 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
|
||||
dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
|
||||
ec_msg->cmd, ptr[0]);
|
||||
debug_packet(ec_dev->dev, "in_err", ptr, len);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
len = ptr[1];
|
||||
sum = ptr[0] + ptr[1];
|
||||
if (len > ec_msg->in_len) {
|
||||
dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
|
||||
len, ec_msg->in_len);
|
||||
return -ENOSPC;
|
||||
ret = -ENOSPC;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* copy response packet payload and compute checksum */
|
||||
@@ -293,10 +321,14 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
|
||||
dev_err(ec_dev->dev,
|
||||
"bad packet checksum, expected %02x, got %02x\n",
|
||||
sum, ptr[len + 2]);
|
||||
return -EBADMSG;
|
||||
ret = -EBADMSG;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
exit:
|
||||
mutex_unlock(&ec_spi->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
|
||||
@@ -327,6 +359,7 @@ static int cros_ec_spi_probe(struct spi_device *spi)
|
||||
if (ec_spi == NULL)
|
||||
return -ENOMEM;
|
||||
ec_spi->spi = spi;
|
||||
mutex_init(&ec_spi->lock);
|
||||
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
|
||||
if (!ec_dev)
|
||||
return -ENOMEM;
|
||||
|
@@ -2300,9 +2300,6 @@ int prcmu_ac_wake_req(void)
|
||||
|
||||
if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
|
||||
msecs_to_jiffies(5000))) {
|
||||
#if defined(CONFIG_DBX500_PRCMU_DEBUG)
|
||||
db8500_prcmu_debug_dump(__func__, true, true);
|
||||
#endif
|
||||
pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n",
|
||||
__func__);
|
||||
ret = -EFAULT;
|
||||
@@ -3112,7 +3109,7 @@ static int db8500_prcmu_register_ab8500(struct device *parent,
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource ab8500_resource;
|
||||
struct mfd_cell ab8500_cell = {
|
||||
const struct mfd_cell ab8500_cell = {
|
||||
.name = "ab8500-core",
|
||||
.of_compatible = "stericsson,ab8500",
|
||||
.id = AB8500_VERSION_AB8500,
|
||||
|
482
drivers/mfd/ipaq-micro.c
Normal file
482
drivers/mfd/ipaq-micro.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Compaq iPAQ h3xxx Atmel microcontroller companion support
|
||||
*
|
||||
* This is an Atmel AT90LS8535 with a special flashed-in firmware that
|
||||
* implements the special protocol used by this driver.
|
||||
*
|
||||
* based on previous kernel 2.4 version by Andrew Christian
|
||||
* Author : Alessandro Gardich <gremlin@gremlin.it>
|
||||
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
|
||||
* Author : Linus Walleij <linus.walleij@linaro.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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ipaq-micro.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static void ipaq_micro_trigger_tx(struct ipaq_micro *micro)
|
||||
{
|
||||
struct ipaq_micro_txdev *tx = µ->tx;
|
||||
struct ipaq_micro_msg *msg = micro->msg;
|
||||
int i, bp;
|
||||
u8 checksum;
|
||||
u32 val;
|
||||
|
||||
bp = 0;
|
||||
tx->buf[bp++] = CHAR_SOF;
|
||||
|
||||
checksum = ((msg->id & 0x0f) << 4) | (msg->tx_len & 0x0f);
|
||||
tx->buf[bp++] = checksum;
|
||||
|
||||
for (i = 0; i < msg->tx_len; i++) {
|
||||
tx->buf[bp++] = msg->tx_data[i];
|
||||
checksum += msg->tx_data[i];
|
||||
}
|
||||
|
||||
tx->buf[bp++] = checksum;
|
||||
tx->len = bp;
|
||||
tx->index = 0;
|
||||
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
tx->buf, tx->len, true);
|
||||
|
||||
/* Enable interrupt */
|
||||
val = readl(micro->base + UTCR3);
|
||||
val |= UTCR3_TIE;
|
||||
writel(val, micro->base + UTCR3);
|
||||
}
|
||||
|
||||
int ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(micro->dev, "TX msg: %02x, %d bytes\n", msg->id, msg->tx_len);
|
||||
|
||||
spin_lock_irqsave(µ->lock, flags);
|
||||
if (micro->msg) {
|
||||
list_add_tail(&msg->node, µ->queue);
|
||||
spin_unlock_irqrestore(µ->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
micro->msg = msg;
|
||||
ipaq_micro_trigger_tx(micro);
|
||||
spin_unlock_irqrestore(µ->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipaq_micro_tx_msg);
|
||||
|
||||
static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev_dbg(micro->dev, "RX msg: %02x, %d bytes\n", id, len);
|
||||
|
||||
spin_lock(µ->lock);
|
||||
switch (id) {
|
||||
case MSG_VERSION:
|
||||
case MSG_EEPROM_READ:
|
||||
case MSG_EEPROM_WRITE:
|
||||
case MSG_BACKLIGHT:
|
||||
case MSG_NOTIFY_LED:
|
||||
case MSG_THERMAL_SENSOR:
|
||||
case MSG_BATTERY:
|
||||
/* Handle synchronous messages */
|
||||
if (micro->msg && micro->msg->id == id) {
|
||||
struct ipaq_micro_msg *msg = micro->msg;
|
||||
|
||||
memcpy(msg->rx_data, data, len);
|
||||
msg->rx_len = len;
|
||||
complete(µ->msg->ack);
|
||||
if (!list_empty(µ->queue)) {
|
||||
micro->msg = list_entry(micro->queue.next,
|
||||
struct ipaq_micro_msg,
|
||||
node);
|
||||
list_del_init(µ->msg->node);
|
||||
ipaq_micro_trigger_tx(micro);
|
||||
} else
|
||||
micro->msg = NULL;
|
||||
dev_dbg(micro->dev, "OK RX message 0x%02x\n", id);
|
||||
} else {
|
||||
dev_err(micro->dev,
|
||||
"out of band RX message 0x%02x\n", id);
|
||||
if(!micro->msg)
|
||||
dev_info(micro->dev, "no message queued\n");
|
||||
else
|
||||
dev_info(micro->dev, "expected message %02x\n",
|
||||
micro->msg->id);
|
||||
}
|
||||
break;
|
||||
case MSG_KEYBOARD:
|
||||
if (micro->key)
|
||||
micro->key(micro->key_data, len, data);
|
||||
else
|
||||
dev_dbg(micro->dev, "key message ignored, no handle \n");
|
||||
break;
|
||||
case MSG_TOUCHSCREEN:
|
||||
if (micro->ts)
|
||||
micro->ts(micro->ts_data, len, data);
|
||||
else
|
||||
dev_dbg(micro->dev, "touchscreen message ignored, no handle \n");
|
||||
break;
|
||||
default:
|
||||
dev_err(micro->dev,
|
||||
"unknown msg %d [%d] ", id, len);
|
||||
for (i = 0; i < len; ++i)
|
||||
pr_cont("0x%02x ", data[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
spin_unlock(µ->lock);
|
||||
}
|
||||
|
||||
static void micro_process_char(struct ipaq_micro *micro, u8 ch)
|
||||
{
|
||||
struct ipaq_micro_rxdev *rx = µ->rx;
|
||||
|
||||
switch (rx->state) {
|
||||
case STATE_SOF: /* Looking for SOF */
|
||||
if (ch == CHAR_SOF)
|
||||
rx->state = STATE_ID; /* Next byte is the id and len */
|
||||
break;
|
||||
case STATE_ID: /* Looking for id and len byte */
|
||||
rx->id = (ch & 0xf0) >> 4 ;
|
||||
rx->len = (ch & 0x0f);
|
||||
rx->index = 0;
|
||||
rx->chksum = ch;
|
||||
rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM;
|
||||
break;
|
||||
case STATE_DATA: /* Looking for 'len' data bytes */
|
||||
rx->chksum += ch;
|
||||
rx->buf[rx->index] = ch;
|
||||
if (++rx->index == rx->len)
|
||||
rx->state = STATE_CHKSUM;
|
||||
break;
|
||||
case STATE_CHKSUM: /* Looking for the checksum */
|
||||
if (ch == rx->chksum)
|
||||
micro_rx_msg(micro, rx->id, rx->len, rx->buf);
|
||||
rx->state = STATE_SOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void micro_rx_chars(struct ipaq_micro *micro)
|
||||
{
|
||||
u32 status, ch;
|
||||
|
||||
while ((status = readl(micro->base + UTSR1)) & UTSR1_RNE) {
|
||||
ch = readl(micro->base + UTDR);
|
||||
if (status & UTSR1_PRE)
|
||||
dev_err(micro->dev, "rx: parity error\n");
|
||||
else if (status & UTSR1_FRE)
|
||||
dev_err(micro->dev, "rx: framing error\n");
|
||||
else if (status & UTSR1_ROR)
|
||||
dev_err(micro->dev, "rx: overrun error\n");
|
||||
micro_process_char(micro, ch);
|
||||
}
|
||||
}
|
||||
|
||||
static void ipaq_micro_get_version(struct ipaq_micro *micro)
|
||||
{
|
||||
struct ipaq_micro_msg msg = {
|
||||
.id = MSG_VERSION,
|
||||
};
|
||||
|
||||
ipaq_micro_tx_msg_sync(micro, &msg);
|
||||
if (msg.rx_len == 4) {
|
||||
memcpy(micro->version, msg.rx_data, 4);
|
||||
micro->version[4] = '\0';
|
||||
} else if (msg.rx_len == 9) {
|
||||
memcpy(micro->version, msg.rx_data, 4);
|
||||
micro->version[4] = '\0';
|
||||
/* Bytes 4-7 are "pack", byte 8 is "boot type" */
|
||||
} else {
|
||||
dev_err(micro->dev,
|
||||
"illegal version message %d bytes\n", msg.rx_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ipaq_micro_eeprom_read(struct ipaq_micro *micro,
|
||||
u8 address, u8 len, u8 *data)
|
||||
{
|
||||
struct ipaq_micro_msg msg = {
|
||||
.id = MSG_EEPROM_READ,
|
||||
};
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
msg.tx_data[0] = address + i;
|
||||
msg.tx_data[1] = 1;
|
||||
msg.tx_len = 2;
|
||||
ipaq_micro_tx_msg_sync(micro, &msg);
|
||||
memcpy(data + (i * 2), msg.rx_data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
static char *ipaq_micro_str(u8 *wchar, u8 len)
|
||||
{
|
||||
char retstr[256];
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < len / 2; i++)
|
||||
retstr[i] = wchar[i * 2];
|
||||
return kstrdup(retstr, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static u16 ipaq_micro_to_u16(u8 *data)
|
||||
{
|
||||
return data[1] << 8 | data[0];
|
||||
}
|
||||
|
||||
static void ipaq_micro_eeprom_dump(struct ipaq_micro *micro)
|
||||
{
|
||||
u8 dump[256];
|
||||
char *str;
|
||||
|
||||
ipaq_micro_eeprom_read(micro, 0, 128, dump);
|
||||
str = ipaq_micro_str(dump, 10);
|
||||
if (str) {
|
||||
dev_info(micro->dev, "HM version %s\n", str);
|
||||
kfree(str);
|
||||
}
|
||||
str = ipaq_micro_str(dump+10, 40);
|
||||
if (str) {
|
||||
dev_info(micro->dev, "serial number: %s\n", str);
|
||||
/* Feed the random pool with this */
|
||||
add_device_randomness(str, strlen(str));
|
||||
kfree(str);
|
||||
}
|
||||
str = ipaq_micro_str(dump+50, 20);
|
||||
if (str) {
|
||||
dev_info(micro->dev, "module ID: %s\n", str);
|
||||
kfree(str);
|
||||
}
|
||||
str = ipaq_micro_str(dump+70, 10);
|
||||
if (str) {
|
||||
dev_info(micro->dev, "product revision: %s\n", str);
|
||||
kfree(str);
|
||||
}
|
||||
dev_info(micro->dev, "product ID: %u\n", ipaq_micro_to_u16(dump+80));
|
||||
dev_info(micro->dev, "frame rate: %u fps\n",
|
||||
ipaq_micro_to_u16(dump+82));
|
||||
dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84));
|
||||
dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86));
|
||||
dev_info(micro->dev, "color display: %s\n",
|
||||
ipaq_micro_to_u16(dump+88) ? "yes" : "no");
|
||||
dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90));
|
||||
dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92));
|
||||
dev_info(micro->dev, "screen: %u x %u\n",
|
||||
ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96));
|
||||
print_hex_dump(KERN_DEBUG, "eeprom: ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
dump, 256, true);
|
||||
|
||||
}
|
||||
|
||||
static void micro_tx_chars(struct ipaq_micro *micro)
|
||||
{
|
||||
struct ipaq_micro_txdev *tx = µ->tx;
|
||||
u32 val;
|
||||
|
||||
while ((tx->index < tx->len) &&
|
||||
(readl(micro->base + UTSR1) & UTSR1_TNF)) {
|
||||
writel(tx->buf[tx->index], micro->base + UTDR);
|
||||
tx->index++;
|
||||
}
|
||||
|
||||
/* Stop interrupts */
|
||||
val = readl(micro->base + UTCR3);
|
||||
val &= ~UTCR3_TIE;
|
||||
writel(val, micro->base + UTCR3);
|
||||
}
|
||||
|
||||
static void micro_reset_comm(struct ipaq_micro *micro)
|
||||
{
|
||||
struct ipaq_micro_rxdev *rx = µ->rx;
|
||||
u32 val;
|
||||
|
||||
if (micro->msg)
|
||||
complete(µ->msg->ack);
|
||||
|
||||
/* Initialize Serial channel protocol frame */
|
||||
rx->state = STATE_SOF; /* Reset the state machine */
|
||||
|
||||
/* Set up interrupts */
|
||||
writel(0x01, micro->sdlc + 0x0); /* Select UART mode */
|
||||
|
||||
/* Clean up CR3 */
|
||||
writel(0x0, micro->base + UTCR3);
|
||||
|
||||
/* Format: 8N1 */
|
||||
writel(UTCR0_8BitData | UTCR0_1StpBit, micro->base + UTCR0);
|
||||
|
||||
/* Baud rate: 115200 */
|
||||
writel(0x0, micro->base + UTCR1);
|
||||
writel(0x1, micro->base + UTCR2);
|
||||
|
||||
/* Clear SR0 */
|
||||
writel(0xff, micro->base + UTSR0);
|
||||
|
||||
/* Enable RX int, disable TX int */
|
||||
writel(UTCR3_TXE | UTCR3_RXE | UTCR3_RIE, micro->base + UTCR3);
|
||||
val = readl(micro->base + UTCR3);
|
||||
val &= ~UTCR3_TIE;
|
||||
writel(val, micro->base + UTCR3);
|
||||
}
|
||||
|
||||
static irqreturn_t micro_serial_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct ipaq_micro *micro = dev_id;
|
||||
struct ipaq_micro_txdev *tx = µ->tx;
|
||||
u32 status;
|
||||
|
||||
status = readl(micro->base + UTSR0);
|
||||
do {
|
||||
if (status & (UTSR0_RID | UTSR0_RFS)) {
|
||||
if (status & UTSR0_RID)
|
||||
/* Clear the Receiver IDLE bit */
|
||||
writel(UTSR0_RID, micro->base + UTSR0);
|
||||
micro_rx_chars(micro);
|
||||
}
|
||||
|
||||
/* Clear break bits */
|
||||
if (status & (UTSR0_RBB | UTSR0_REB))
|
||||
writel(status & (UTSR0_RBB | UTSR0_REB),
|
||||
micro->base + UTSR0);
|
||||
|
||||
if (status & UTSR0_TFS)
|
||||
micro_tx_chars(micro);
|
||||
|
||||
status = readl(micro->base + UTSR0);
|
||||
|
||||
} while (((tx->index < tx->len) && (status & UTSR0_TFS)) ||
|
||||
(status & (UTSR0_RFS | UTSR0_RID)));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct mfd_cell micro_cells[] = {
|
||||
{ .name = "ipaq-micro-backlight", },
|
||||
{ .name = "ipaq-micro-battery", },
|
||||
{ .name = "ipaq-micro-keys", },
|
||||
{ .name = "ipaq-micro-ts", },
|
||||
{ .name = "ipaq-micro-leds", },
|
||||
};
|
||||
|
||||
static int micro_resume(struct device *dev)
|
||||
{
|
||||
struct ipaq_micro *micro = dev_get_drvdata(dev);
|
||||
|
||||
micro_reset_comm(micro);
|
||||
mdelay(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ipaq_micro *micro;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL);
|
||||
if (!micro)
|
||||
return -ENOMEM;
|
||||
|
||||
micro->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
micro->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(micro->base))
|
||||
return PTR_ERR(micro->base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
micro->sdlc = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(micro->sdlc))
|
||||
return PTR_ERR(micro->sdlc);
|
||||
|
||||
micro_reset_comm(micro);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!irq)
|
||||
return -EINVAL;
|
||||
ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr,
|
||||
IRQF_SHARED, "ipaq-micro",
|
||||
micro);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to grab serial port IRQ\n");
|
||||
return ret;
|
||||
} else
|
||||
dev_info(&pdev->dev, "grabbed serial port IRQ\n");
|
||||
|
||||
spin_lock_init(µ->lock);
|
||||
INIT_LIST_HEAD(µ->queue);
|
||||
platform_set_drvdata(pdev, micro);
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, micro_cells,
|
||||
ARRAY_SIZE(micro_cells), NULL, 0, NULL);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error adding MFD cells");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check version */
|
||||
ipaq_micro_get_version(micro);
|
||||
dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version);
|
||||
ipaq_micro_eeprom_dump(micro);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micro_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ipaq_micro *micro = platform_get_drvdata(pdev);
|
||||
u32 val;
|
||||
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
|
||||
val = readl(micro->base + UTCR3);
|
||||
val &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */
|
||||
val &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */
|
||||
writel(val, micro->base + UTCR3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops micro_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(NULL, micro_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver micro_device_driver = {
|
||||
.driver = {
|
||||
.name = "ipaq-h3xxx-micro",
|
||||
.pm = µ_dev_pm_ops,
|
||||
},
|
||||
.probe = micro_probe,
|
||||
.remove = micro_remove,
|
||||
/* .shutdown = micro_suspend, // FIXME */
|
||||
};
|
||||
module_platform_driver(micro_device_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight");
|
@@ -86,7 +86,7 @@ enum kempld_cells {
|
||||
KEMPLD_UART,
|
||||
};
|
||||
|
||||
static struct mfd_cell kempld_devs[] = {
|
||||
static const struct mfd_cell kempld_devs[] = {
|
||||
[KEMPLD_I2C] = {
|
||||
.name = "kempld-i2c",
|
||||
},
|
||||
@@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex);
|
||||
*/
|
||||
static int kempld_get_info(struct kempld_device_data *pld)
|
||||
{
|
||||
int ret;
|
||||
struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
|
||||
char major, minor;
|
||||
|
||||
return pdata->get_info(pld);
|
||||
ret = pdata->get_info(pld);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The Kontron PLD firmware version string has the following format:
|
||||
* Pwxy.zzzz
|
||||
* P: Fixed
|
||||
* w: PLD number - 1 hex digit
|
||||
* x: Major version - 1 alphanumerical digit (0-9A-V)
|
||||
* y: Minor version - 1 alphanumerical digit (0-9A-V)
|
||||
* zzzz: Build number - 4 zero padded hex digits */
|
||||
|
||||
if (pld->info.major < 10)
|
||||
major = pld->info.major + '0';
|
||||
else
|
||||
major = (pld->info.major - 10) + 'A';
|
||||
if (pld->info.minor < 10)
|
||||
minor = pld->info.minor + '0';
|
||||
else
|
||||
minor = (pld->info.minor - 10) + 'A';
|
||||
|
||||
ret = scnprintf(pld->info.version, sizeof(pld->info.version),
|
||||
"P%X%c%c.%04X", pld->info.number, major, minor,
|
||||
pld->info.buildnr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld)
|
||||
return pdata->register_cells(pld);
|
||||
}
|
||||
|
||||
static const char *kempld_get_type_string(struct kempld_device_data *pld)
|
||||
{
|
||||
const char *version_type;
|
||||
|
||||
switch (pld->info.type) {
|
||||
case 0:
|
||||
version_type = "release";
|
||||
break;
|
||||
case 1:
|
||||
version_type = "debug";
|
||||
break;
|
||||
case 2:
|
||||
version_type = "custom";
|
||||
break;
|
||||
default:
|
||||
version_type = "unspecified";
|
||||
break;
|
||||
}
|
||||
|
||||
return version_type;
|
||||
}
|
||||
|
||||
static ssize_t kempld_version_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct kempld_device_data *pld = dev_get_drvdata(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
|
||||
}
|
||||
|
||||
static ssize_t kempld_specification_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct kempld_device_data *pld = dev_get_drvdata(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
|
||||
pld->info.spec_minor);
|
||||
}
|
||||
|
||||
static ssize_t kempld_type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct kempld_device_data *pld = dev_get_drvdata(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
|
||||
static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
|
||||
NULL);
|
||||
static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
|
||||
|
||||
static struct attribute *pld_attributes[] = {
|
||||
&dev_attr_pld_version.attr,
|
||||
&dev_attr_pld_specification.attr,
|
||||
&dev_attr_pld_type.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pld_attr_group = {
|
||||
.attrs = pld_attributes,
|
||||
};
|
||||
|
||||
static int kempld_detect_device(struct kempld_device_data *pld)
|
||||
{
|
||||
char *version_type;
|
||||
u8 index_reg;
|
||||
int ret;
|
||||
|
||||
@@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (pld->info.type) {
|
||||
case 0:
|
||||
version_type = "release";
|
||||
break;
|
||||
case 1:
|
||||
version_type = "debug";
|
||||
break;
|
||||
case 2:
|
||||
version_type = "custom";
|
||||
break;
|
||||
default:
|
||||
version_type = "unspecified";
|
||||
}
|
||||
dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
|
||||
pld->info.version, kempld_get_type_string(pld),
|
||||
pld->info.spec_major, pld->info.spec_minor);
|
||||
|
||||
dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
|
||||
dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
|
||||
version_type, pld->info.major, pld->info.minor,
|
||||
pld->info.buildnr, pld->info.spec_major,
|
||||
pld->info.spec_minor);
|
||||
ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return kempld_register_cells(pld);
|
||||
ret = kempld_register_cells(pld);
|
||||
if (ret)
|
||||
sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kempld_probe(struct platform_device *pdev)
|
||||
@@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev)
|
||||
struct kempld_device_data *pld = platform_get_drvdata(pdev);
|
||||
struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
|
||||
|
||||
sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
|
||||
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pdata->release_hardware_mutex(pld);
|
||||
|
||||
|
@@ -62,7 +62,7 @@ static const struct lp3943_reg_cfg lp3943_mux_cfg[] = {
|
||||
{ LP3943_REG_MUX3, 0xC0, 6 },
|
||||
};
|
||||
|
||||
static struct mfd_cell lp3943_devs[] = {
|
||||
static const struct mfd_cell lp3943_devs[] = {
|
||||
{
|
||||
.name = "lp3943-pwm",
|
||||
.of_compatible = "ti,lp3943-pwm",
|
||||
|
@@ -488,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
|
||||
[LPC_PPT] = {
|
||||
.name = "Panther Point",
|
||||
.iTCO_version = 2,
|
||||
.gpio_version = ICH_V5_GPIO,
|
||||
},
|
||||
[LPC_LPT] = {
|
||||
.name = "Lynx Point",
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#include <linux/mfd/max14577.h>
|
||||
#include <linux/mfd/max14577-private.h>
|
||||
|
||||
static struct mfd_cell max14577_devs[] = {
|
||||
static const struct mfd_cell max14577_devs[] = {
|
||||
{
|
||||
.name = "max14577-muic",
|
||||
.of_compatible = "maxim,max14577-muic",
|
||||
@@ -38,7 +38,7 @@ static struct mfd_cell max14577_devs[] = {
|
||||
{ .name = "max14577-charger", },
|
||||
};
|
||||
|
||||
static struct mfd_cell max77836_devs[] = {
|
||||
static const struct mfd_cell max77836_devs[] = {
|
||||
{
|
||||
.name = "max77836-muic",
|
||||
.of_compatible = "maxim,max77836-muic",
|
||||
@@ -57,7 +57,7 @@ static struct mfd_cell max77836_devs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct of_device_id max14577_dt_match[] = {
|
||||
static const struct of_device_id max14577_dt_match[] = {
|
||||
{
|
||||
.compatible = "maxim,max14577",
|
||||
.data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
|
||||
@@ -292,7 +292,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
int ret = 0;
|
||||
const struct regmap_irq_chip *irq_chip;
|
||||
struct mfd_cell *mfd_devs;
|
||||
const struct mfd_cell *mfd_devs;
|
||||
unsigned int mfd_devs_size;
|
||||
int irq_flags;
|
||||
|
||||
@@ -331,7 +331,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
of_id = of_match_device(max14577_dt_match, &i2c->dev);
|
||||
if (of_id)
|
||||
max14577->dev_type = (unsigned int)of_id->data;
|
||||
max14577->dev_type =
|
||||
(enum maxim_device_type)of_id->data;
|
||||
} else {
|
||||
max14577->dev_type = id->driver_data;
|
||||
}
|
||||
@@ -414,20 +415,18 @@ static int max14577_suspend(struct device *dev)
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max14577 *max14577 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(max14577->irq);
|
||||
/*
|
||||
* MUIC IRQ must be disabled during suspend if this is
|
||||
* a wake up source because it will be handled before
|
||||
* resuming I2C.
|
||||
*
|
||||
* When device is woken up from suspend (e.g. by ADC change),
|
||||
* an interrupt occurs before resuming I2C bus controller.
|
||||
* Interrupt handler tries to read registers but this read
|
||||
* will fail because I2C is still suspended.
|
||||
*/
|
||||
disable_irq(max14577->irq);
|
||||
}
|
||||
/*
|
||||
* MUIC IRQ must be disabled during suspend because if it happens
|
||||
* while suspended it will be handled before resuming I2C.
|
||||
*
|
||||
* When device is woken up from suspend (e.g. by ADC change),
|
||||
* an interrupt occurs before resuming I2C bus controller.
|
||||
* Interrupt handler tries to read registers but this read
|
||||
* will fail because I2C is still suspended.
|
||||
*/
|
||||
disable_irq(max14577->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -437,10 +436,9 @@ static int max14577_resume(struct device *dev)
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max14577 *max14577 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(max14577->irq);
|
||||
enable_irq(max14577->irq);
|
||||
}
|
||||
enable_irq(max14577->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ static struct regmap_config max77686_regmap_config = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max77686_pmic_dt_match[] = {
|
||||
static const struct of_device_id max77686_pmic_dt_match[] = {
|
||||
{.compatible = "maxim,max77686", .data = NULL},
|
||||
{},
|
||||
};
|
||||
|
@@ -243,7 +243,7 @@ static const struct dev_pm_ops max77693_pm = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max77693_dt_match[] = {
|
||||
static const struct of_device_id max77693_dt_match[] = {
|
||||
{ .compatible = "maxim,max77693" },
|
||||
{},
|
||||
};
|
||||
|
@@ -305,7 +305,7 @@ static int max8907_i2c_remove(struct i2c_client *i2c)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max8907_of_match[] = {
|
||||
static const struct of_device_id max8907_of_match[] = {
|
||||
{ .compatible = "maxim,max8907" },
|
||||
{ },
|
||||
};
|
||||
|
@@ -51,7 +51,7 @@ static const struct mfd_cell max8997_devs[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max8997_pmic_dt_match[] = {
|
||||
static const struct of_device_id max8997_pmic_dt_match[] = {
|
||||
{ .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 },
|
||||
{},
|
||||
};
|
||||
|
@@ -132,7 +132,7 @@ int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
|
||||
EXPORT_SYMBOL(max8998_update_reg);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id max8998_dt_match[] = {
|
||||
static const struct of_device_id max8998_dt_match[] = {
|
||||
{ .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 },
|
||||
{ .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 },
|
||||
{ .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 },
|
||||
|
@@ -660,34 +660,22 @@ int mc13xxx_common_init(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&mc13xxx->lock);
|
||||
|
||||
ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&mc13xxx->lock);
|
||||
|
||||
if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
|
||||
mc13xxx->flags = pdata->flags;
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_ADC)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_CODEC) {
|
||||
if (pdata)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
||||
pdata->codec, sizeof(*pdata->codec));
|
||||
else
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
|
||||
}
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_RTC)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
|
||||
&pdata->touch, sizeof(pdata->touch));
|
||||
|
||||
if (pdata) {
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
|
||||
&pdata->regulators, sizeof(pdata->regulators));
|
||||
@@ -695,10 +683,20 @@ int mc13xxx_common_init(struct device *dev)
|
||||
pdata->leds, sizeof(*pdata->leds));
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
|
||||
pdata->buttons, sizeof(*pdata->buttons));
|
||||
if (mc13xxx->flags & MC13XXX_USE_CODEC)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
||||
pdata->codec, sizeof(*pdata->codec));
|
||||
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
|
||||
&pdata->touch, sizeof(pdata->touch));
|
||||
} else {
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-led");
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
|
||||
if (mc13xxx->flags & MC13XXX_USE_CODEC)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
|
||||
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -1287,29 +1287,8 @@ static struct i2c_driver menelaus_i2c_driver = {
|
||||
.id_table = menelaus_id,
|
||||
};
|
||||
|
||||
static int __init menelaus_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = i2c_add_driver(&menelaus_i2c_driver);
|
||||
if (res < 0) {
|
||||
pr_err(DRIVER_NAME ": driver registration failed\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit menelaus_exit(void)
|
||||
{
|
||||
i2c_del_driver(&menelaus_i2c_driver);
|
||||
|
||||
/* FIXME: Shutdown menelaus parts that can be shut down */
|
||||
}
|
||||
module_i2c_driver(menelaus_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments, Inc. (and others)");
|
||||
MODULE_DESCRIPTION("I2C interface for Menelaus.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(menelaus_init);
|
||||
module_exit(menelaus_exit);
|
||||
|
@@ -102,7 +102,7 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
pdev->dev.dma_mask = parent->dma_mask;
|
||||
pdev->dev.dma_parms = parent->dma_parms;
|
||||
|
||||
ret = devm_regulator_bulk_register_supply_alias(
|
||||
ret = regulator_bulk_register_supply_alias(
|
||||
&pdev->dev, cell->parent_supplies,
|
||||
parent, cell->parent_supplies,
|
||||
cell->num_parent_supplies);
|
||||
@@ -182,9 +182,9 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
return 0;
|
||||
|
||||
fail_alias:
|
||||
devm_regulator_bulk_unregister_supply_alias(&pdev->dev,
|
||||
cell->parent_supplies,
|
||||
cell->num_parent_supplies);
|
||||
regulator_bulk_unregister_supply_alias(&pdev->dev,
|
||||
cell->parent_supplies,
|
||||
cell->num_parent_supplies);
|
||||
fail_res:
|
||||
kfree(res);
|
||||
fail_device:
|
||||
@@ -238,6 +238,9 @@ static int mfd_remove_devices_fn(struct device *dev, void *c)
|
||||
pdev = to_platform_device(dev);
|
||||
cell = mfd_get_cell(pdev);
|
||||
|
||||
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
|
||||
cell->num_parent_supplies);
|
||||
|
||||
/* find the base address of usage_count pointers (for freeing) */
|
||||
if (!*usage_count || (cell->usage_count < *usage_count))
|
||||
*usage_count = cell->usage_count;
|
||||
|
@@ -557,7 +557,7 @@ static int usbhs_omap_get_dt_pdata(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id usbhs_child_match_table[] = {
|
||||
static const struct of_device_id usbhs_child_match_table[] = {
|
||||
{ .compatible = "ti,omap-ehci", },
|
||||
{ .compatible = "ti,omap-ohci", },
|
||||
{ }
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
|
||||
#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
|
||||
|
||||
@@ -57,7 +56,6 @@
|
||||
#define PM8921_NR_IRQS 256
|
||||
|
||||
struct pm_irq_chip {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
spinlock_t pm_irq_lock;
|
||||
struct irq_domain *irqdomain;
|
||||
@@ -67,11 +65,6 @@ struct pm_irq_chip {
|
||||
u8 config[0];
|
||||
};
|
||||
|
||||
struct pm8921 {
|
||||
struct device *dev;
|
||||
struct pm_irq_chip *irq_chip;
|
||||
};
|
||||
|
||||
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
|
||||
unsigned int *ip)
|
||||
{
|
||||
@@ -255,55 +248,6 @@ static struct irq_chip pm8xxx_irq_chip = {
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
/**
|
||||
* pm8xxx_get_irq_stat - get the status of the irq line
|
||||
* @chip: pointer to identify a pmic irq controller
|
||||
* @irq: the irq number
|
||||
*
|
||||
* The pm8xxx gpio and mpp rely on the interrupt block to read
|
||||
* the values on their pins. This function is to facilitate reading
|
||||
* the status of a gpio or an mpp line. The caller has to convert the
|
||||
* gpio number to irq number.
|
||||
*
|
||||
* RETURNS:
|
||||
* an int indicating the value read on that line
|
||||
*/
|
||||
static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
|
||||
{
|
||||
int pmirq, rc;
|
||||
unsigned int block, bits, bit;
|
||||
unsigned long flags;
|
||||
struct irq_data *irq_data = irq_get_irq_data(irq);
|
||||
|
||||
pmirq = irq_data->hwirq;
|
||||
|
||||
block = pmirq / 8;
|
||||
bit = pmirq % 8;
|
||||
|
||||
spin_lock_irqsave(&chip->pm_irq_lock, flags);
|
||||
|
||||
rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
|
||||
if (rc) {
|
||||
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
|
||||
irq, pmirq, block, rc);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
|
||||
if (rc) {
|
||||
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
|
||||
irq, pmirq, block, rc);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
rc = (bits & (1 << bit)) ? 1 : 0;
|
||||
|
||||
bail_out:
|
||||
spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
@@ -324,56 +268,6 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
|
||||
.map = pm8xxx_irq_domain_map,
|
||||
};
|
||||
|
||||
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return ssbi_read(pmic->dev->parent, addr, val, 1);
|
||||
}
|
||||
|
||||
static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return ssbi_write(pmic->dev->parent, addr, &val, 1);
|
||||
}
|
||||
|
||||
static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int cnt)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return ssbi_read(pmic->dev->parent, addr, buf, cnt);
|
||||
}
|
||||
|
||||
static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int cnt)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return ssbi_write(pmic->dev->parent, addr, buf, cnt);
|
||||
}
|
||||
|
||||
static int pm8921_read_irq_stat(const struct device *dev, int irq)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
|
||||
}
|
||||
|
||||
static struct pm8xxx_drvdata pm8921_drvdata = {
|
||||
.pmic_readb = pm8921_readb,
|
||||
.pmic_writeb = pm8921_writeb,
|
||||
.pmic_read_buf = pm8921_read_buf,
|
||||
.pmic_write_buf = pm8921_write_buf,
|
||||
.pmic_read_irq_stat = pm8921_read_irq_stat,
|
||||
};
|
||||
|
||||
static const struct regmap_config ssbi_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
@@ -392,7 +286,6 @@ MODULE_DEVICE_TABLE(of, pm8921_id_table);
|
||||
|
||||
static int pm8921_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8921 *pmic;
|
||||
struct regmap *regmap;
|
||||
int irq, rc;
|
||||
unsigned int val;
|
||||
@@ -404,12 +297,6 @@ static int pm8921_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
|
||||
if (!pmic) {
|
||||
pr_err("Cannot alloc pm8921 struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent,
|
||||
&ssbi_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
@@ -434,18 +321,13 @@ static int pm8921_probe(struct platform_device *pdev)
|
||||
pr_info("PMIC revision 2: %02X\n", val);
|
||||
rev |= val << BITS_PER_BYTE;
|
||||
|
||||
pmic->dev = &pdev->dev;
|
||||
pm8921_drvdata.pm_chip_data = pmic;
|
||||
platform_set_drvdata(pdev, &pm8921_drvdata);
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
|
||||
sizeof(chip->config[0]) * nirqs,
|
||||
GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
pmic->irq_chip = chip;
|
||||
chip->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, chip);
|
||||
chip->regmap = regmap;
|
||||
chip->num_irqs = nirqs;
|
||||
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
|
||||
@@ -481,8 +363,7 @@ static int pm8921_remove_child(struct device *dev, void *unused)
|
||||
static int pm8921_remove(struct platform_device *pdev)
|
||||
{
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct pm8921 *pmic = pm8921_drvdata.pm_chip_data;
|
||||
struct pm_irq_chip *chip = pmic->irq_chip;
|
||||
struct pm_irq_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
device_for_each_child(&pdev->dev, NULL, pm8921_remove_child);
|
||||
irq_set_chained_handler(irq, NULL);
|
||||
|
@@ -38,7 +38,7 @@ static struct resource rdc321x_wdt_resource[] = {
|
||||
};
|
||||
|
||||
static struct rdc321x_gpio_pdata rdc321x_gpio_pdata = {
|
||||
.max_gpios = RDC321X_MAX_GPIO,
|
||||
.max_gpios = RDC321X_NUM_GPIO,
|
||||
};
|
||||
|
||||
static struct resource rdc321x_gpio_resources[] = {
|
||||
|
@@ -29,7 +29,7 @@ static int polling_pipe = 1;
|
||||
module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)");
|
||||
|
||||
static struct mfd_cell rtsx_usb_cells[] = {
|
||||
static const struct mfd_cell rtsx_usb_cells[] = {
|
||||
[RTSX_USB_SD_CARD] = {
|
||||
.name = "rtsx_usb_sdmmc",
|
||||
.pdata_size = 0,
|
||||
@@ -67,7 +67,7 @@ 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(&ucr->sg_timer);
|
||||
del_timer_sync(&ucr->sg_timer);
|
||||
|
||||
if (act_len)
|
||||
*act_len = ucr->current_sg.bytes;
|
||||
@@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf,
|
||||
if (ret)
|
||||
goto out_init_fail;
|
||||
|
||||
/* 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);
|
||||
if (ret)
|
||||
goto out_init_fail;
|
||||
|
||||
/* initialize USB SG transfer timer */
|
||||
init_timer(&ucr->sg_timer);
|
||||
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
|
||||
#ifdef CONFIG_PM
|
||||
intf->needs_remote_wakeup = 1;
|
||||
usb_enable_autosuspend(usb_dev);
|
||||
@@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
|
||||
__func__, message.event);
|
||||
|
||||
/*
|
||||
* Call to make sure LED is off during suspend to save more power.
|
||||
* It is NOT a permanent state and could be turned on anytime later.
|
||||
* Thus no need to call turn_on when resunming.
|
||||
*/
|
||||
mutex_lock(&ucr->dev_mutex);
|
||||
rtsx_usb_turn_off_led(ucr);
|
||||
mutex_unlock(&ucr->dev_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/samsung/core.h>
|
||||
#include <linux/mfd/samsung/irq.h>
|
||||
#include <linux/mfd/samsung/rtc.h>
|
||||
#include <linux/mfd/samsung/s2mpa01.h>
|
||||
#include <linux/mfd/samsung/s2mps11.h>
|
||||
#include <linux/mfd/samsung/s2mps14.h>
|
||||
@@ -91,7 +90,7 @@ static const struct mfd_cell s2mpa01_devs[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id sec_dt_match[] = {
|
||||
static const struct of_device_id sec_dt_match[] = {
|
||||
{ .compatible = "samsung,s5m8767-pmic",
|
||||
.data = (void *)S5M8767X,
|
||||
}, {
|
||||
@@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = {
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static const struct regmap_config s5m_rtc_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = SEC_RTC_REG_MAX,
|
||||
};
|
||||
|
||||
static const struct regmap_config s2mps14_rtc_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = S2MPS_RTC_REG_MAX,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* Only the common platform data elements for s5m8767 are parsed here from the
|
||||
@@ -264,8 +249,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
const struct regmap_config *regmap, *regmap_rtc;
|
||||
const struct regmap_config *regmap;
|
||||
struct sec_pmic_dev *sec_pmic;
|
||||
unsigned long device_type;
|
||||
int ret;
|
||||
|
||||
sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
|
||||
@@ -277,7 +263,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
sec_pmic->dev = &i2c->dev;
|
||||
sec_pmic->i2c = i2c;
|
||||
sec_pmic->irq = i2c->irq;
|
||||
sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
|
||||
device_type = sec_i2c_get_driver_data(i2c, id);
|
||||
|
||||
if (sec_pmic->dev->of_node) {
|
||||
pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
|
||||
@@ -285,7 +271,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
ret = PTR_ERR(pdata);
|
||||
return ret;
|
||||
}
|
||||
pdata->device_type = sec_pmic->type;
|
||||
pdata->device_type = device_type;
|
||||
}
|
||||
if (pdata) {
|
||||
sec_pmic->device_type = pdata->device_type;
|
||||
@@ -298,39 +284,21 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
switch (sec_pmic->device_type) {
|
||||
case S2MPA01:
|
||||
regmap = &s2mpa01_regmap_config;
|
||||
/*
|
||||
* The rtc-s5m driver does not support S2MPA01 and there
|
||||
* is no mfd_cell for S2MPA01 RTC device.
|
||||
* However we must pass something to devm_regmap_init_i2c()
|
||||
* so use S5M-like regmap config even though it wouldn't work.
|
||||
*/
|
||||
regmap_rtc = &s5m_rtc_regmap_config;
|
||||
break;
|
||||
case S2MPS11X:
|
||||
regmap = &s2mps11_regmap_config;
|
||||
/*
|
||||
* The rtc-s5m driver does not support S2MPS11 and there
|
||||
* is no mfd_cell for S2MPS11 RTC device.
|
||||
* However we must pass something to devm_regmap_init_i2c()
|
||||
* so use S5M-like regmap config even though it wouldn't work.
|
||||
*/
|
||||
regmap_rtc = &s5m_rtc_regmap_config;
|
||||
break;
|
||||
case S2MPS14X:
|
||||
regmap = &s2mps14_regmap_config;
|
||||
regmap_rtc = &s2mps14_rtc_regmap_config;
|
||||
break;
|
||||
case S5M8763X:
|
||||
regmap = &s5m8763_regmap_config;
|
||||
regmap_rtc = &s5m_rtc_regmap_config;
|
||||
break;
|
||||
case S5M8767X:
|
||||
regmap = &s5m8767_regmap_config;
|
||||
regmap_rtc = &s5m_rtc_regmap_config;
|
||||
break;
|
||||
default:
|
||||
regmap = &sec_regmap_config;
|
||||
regmap_rtc = &s5m_rtc_regmap_config;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -342,21 +310,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
|
||||
if (!sec_pmic->rtc) {
|
||||
dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
|
||||
|
||||
sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
|
||||
if (IS_ERR(sec_pmic->regmap_rtc)) {
|
||||
ret = PTR_ERR(sec_pmic->regmap_rtc);
|
||||
dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
|
||||
ret);
|
||||
goto err_regmap_rtc;
|
||||
}
|
||||
|
||||
if (pdata && pdata->cfg_pmic_irq)
|
||||
pdata->cfg_pmic_irq();
|
||||
|
||||
@@ -403,8 +356,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
|
||||
err_mfd:
|
||||
sec_irq_exit(sec_pmic);
|
||||
err_regmap_rtc:
|
||||
i2c_unregister_device(sec_pmic->rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -414,7 +365,6 @@ static int sec_pmic_remove(struct i2c_client *i2c)
|
||||
|
||||
mfd_remove_devices(sec_pmic->dev);
|
||||
sec_irq_exit(sec_pmic);
|
||||
i2c_unregister_device(sec_pmic->rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -424,19 +374,18 @@ static int sec_pmic_suspend(struct device *dev)
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(sec_pmic->irq);
|
||||
/*
|
||||
* PMIC IRQ must be disabled during suspend for RTC alarm
|
||||
* to work properly.
|
||||
* When device is woken up from suspend by RTC Alarm, an
|
||||
* interrupt occurs before resuming I2C bus controller.
|
||||
* The interrupt is handled by regmap_irq_thread which tries
|
||||
* to read RTC registers. This read fails (I2C is still
|
||||
* suspended) and RTC Alarm interrupt is disabled.
|
||||
*/
|
||||
disable_irq(sec_pmic->irq);
|
||||
}
|
||||
/*
|
||||
* PMIC IRQ must be disabled during suspend for RTC alarm
|
||||
* to work properly.
|
||||
* When device is woken up from suspend, an
|
||||
* interrupt occurs before resuming I2C bus controller.
|
||||
* The interrupt is handled by regmap_irq_thread which tries
|
||||
* to read RTC registers. This read fails (I2C is still
|
||||
* suspended) and RTC Alarm interrupt is disabled.
|
||||
*/
|
||||
disable_irq(sec_pmic->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -446,10 +395,9 @@ static int sec_pmic_resume(struct device *dev)
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(sec_pmic->irq);
|
||||
enable_irq(sec_pmic->irq);
|
||||
}
|
||||
enable_irq(sec_pmic->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -385,7 +385,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
|
||||
&sec_pmic->irq_data);
|
||||
break;
|
||||
default:
|
||||
dev_err(sec_pmic->dev, "Unknown device type %d\n",
|
||||
dev_err(sec_pmic->dev, "Unknown device type %lu\n",
|
||||
sec_pmic->device_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -1726,7 +1726,7 @@ static struct pci_driver sm501_pci_driver = {
|
||||
|
||||
MODULE_ALIAS("platform:sm501");
|
||||
|
||||
static struct of_device_id of_sm501_match_tbl[] = {
|
||||
static const struct of_device_id of_sm501_match_tbl[] = {
|
||||
{ .compatible = "smi,sm501", },
|
||||
{ /* end */ }
|
||||
};
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "stmpe.h"
|
||||
|
||||
static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
|
||||
@@ -52,15 +53,41 @@ static struct stmpe_client_info i2c_ci = {
|
||||
.write_block = i2c_block_write,
|
||||
};
|
||||
|
||||
static const struct of_device_id stmpe_of_match[] = {
|
||||
{ .compatible = "st,stmpe610", .data = (void *)STMPE610, },
|
||||
{ .compatible = "st,stmpe801", .data = (void *)STMPE801, },
|
||||
{ .compatible = "st,stmpe811", .data = (void *)STMPE811, },
|
||||
{ .compatible = "st,stmpe1601", .data = (void *)STMPE1601, },
|
||||
{ .compatible = "st,stmpe1801", .data = (void *)STMPE1801, },
|
||||
{ .compatible = "st,stmpe2401", .data = (void *)STMPE2401, },
|
||||
{ .compatible = "st,stmpe2403", .data = (void *)STMPE2403, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmpe_of_match);
|
||||
|
||||
static int
|
||||
stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
{
|
||||
int partnum;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
i2c_ci.data = (void *)id;
|
||||
i2c_ci.irq = i2c->irq;
|
||||
i2c_ci.client = i2c;
|
||||
i2c_ci.dev = &i2c->dev;
|
||||
|
||||
return stmpe_probe(&i2c_ci, id->driver_data);
|
||||
of_id = of_match_device(stmpe_of_match, &i2c->dev);
|
||||
if (!of_id) {
|
||||
/*
|
||||
* This happens when the I2C ID matches the node name
|
||||
* but no real compatible string has been given.
|
||||
*/
|
||||
dev_info(&i2c->dev, "matching on node name, compatible is preferred\n");
|
||||
partnum = id->driver_data;
|
||||
} else
|
||||
partnum = (int)of_id->data;
|
||||
|
||||
return stmpe_probe(&i2c_ci, partnum);
|
||||
}
|
||||
|
||||
static int stmpe_i2c_remove(struct i2c_client *i2c)
|
||||
@@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = {
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &stmpe_dev_pm_ops,
|
||||
#endif
|
||||
.of_match_table = stmpe_of_match,
|
||||
},
|
||||
.probe = stmpe_i2c_probe,
|
||||
.remove = stmpe_i2c_remove,
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include "stmpe.h"
|
||||
|
||||
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
|
||||
@@ -605,9 +606,18 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
|
||||
|
||||
if (blocks & STMPE_BLOCK_GPIO)
|
||||
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
|
||||
else
|
||||
mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO;
|
||||
|
||||
if (blocks & STMPE_BLOCK_KEYPAD)
|
||||
mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
|
||||
else
|
||||
mask &= ~STMPE1601_SYS_CTRL_ENABLE_KPC;
|
||||
|
||||
if (blocks & STMPE_BLOCK_PWM)
|
||||
mask |= STMPE1601_SYS_CTRL_ENABLE_SPWM;
|
||||
else
|
||||
mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM;
|
||||
|
||||
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
|
||||
enable ? mask : 0);
|
||||
@@ -986,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np)
|
||||
int base = 0;
|
||||
int num_irqs = stmpe->variant->num_irqs;
|
||||
|
||||
if (!np)
|
||||
base = stmpe->irq_base;
|
||||
|
||||
stmpe->domain = irq_domain_add_simple(np, num_irqs, base,
|
||||
&stmpe_irq_ops, stmpe);
|
||||
if (!stmpe->domain) {
|
||||
@@ -1067,7 +1074,7 @@ static int stmpe_chip_init(struct stmpe *stmpe)
|
||||
static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell)
|
||||
{
|
||||
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
|
||||
NULL, stmpe->irq_base, stmpe->domain);
|
||||
NULL, 0, stmpe->domain);
|
||||
}
|
||||
|
||||
static int stmpe_devices_init(struct stmpe *stmpe)
|
||||
@@ -1171,12 +1178,23 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||
stmpe->dev = ci->dev;
|
||||
stmpe->client = ci->client;
|
||||
stmpe->pdata = pdata;
|
||||
stmpe->irq_base = pdata->irq_base;
|
||||
stmpe->ci = ci;
|
||||
stmpe->partnum = partnum;
|
||||
stmpe->variant = stmpe_variant_info[partnum];
|
||||
stmpe->regs = stmpe->variant->regs;
|
||||
stmpe->num_gpios = stmpe->variant->num_gpios;
|
||||
stmpe->vcc = devm_regulator_get_optional(ci->dev, "vcc");
|
||||
if (!IS_ERR(stmpe->vcc)) {
|
||||
ret = regulator_enable(stmpe->vcc);
|
||||
if (ret)
|
||||
dev_warn(ci->dev, "failed to enable VCC supply\n");
|
||||
}
|
||||
stmpe->vio = devm_regulator_get_optional(ci->dev, "vio");
|
||||
if (!IS_ERR(stmpe->vio)) {
|
||||
ret = regulator_enable(stmpe->vio);
|
||||
if (ret)
|
||||
dev_warn(ci->dev, "failed to enable VIO supply\n");
|
||||
}
|
||||
dev_set_drvdata(stmpe->dev, stmpe);
|
||||
|
||||
if (ci->init)
|
||||
@@ -1243,6 +1261,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||
|
||||
int stmpe_remove(struct stmpe *stmpe)
|
||||
{
|
||||
if (!IS_ERR(stmpe->vio))
|
||||
regulator_disable(stmpe->vio);
|
||||
if (!IS_ERR(stmpe->vcc))
|
||||
regulator_disable(stmpe->vcc);
|
||||
|
||||
mfd_remove_devices(stmpe->dev);
|
||||
|
||||
return 0;
|
||||
|
@@ -192,7 +192,7 @@ int stmpe_remove(struct stmpe *stmpe);
|
||||
|
||||
#define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3)
|
||||
#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
|
||||
#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0)
|
||||
#define STMPE1601_SYS_CTRL_ENABLE_SPWM (1 << 0)
|
||||
|
||||
/* The 1601/2403 share the same masks */
|
||||
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
|
||||
|
134
drivers/mfd/sun6i-prcm.c
Normal file
134
drivers/mfd/sun6i-prcm.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* Allwinner PRCM (Power/Reset/Clock Management) driver
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct prcm_data {
|
||||
int nsubdevs;
|
||||
const struct mfd_cell *subdevs;
|
||||
};
|
||||
|
||||
static const struct resource sun6i_a31_ar100_clk_res[] = {
|
||||
{
|
||||
.start = 0x0,
|
||||
.end = 0x3,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource sun6i_a31_apb0_clk_res[] = {
|
||||
{
|
||||
.start = 0xc,
|
||||
.end = 0xf,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
|
||||
{
|
||||
.start = 0x28,
|
||||
.end = 0x2b,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource sun6i_a31_apb0_rstc_res[] = {
|
||||
{
|
||||
.start = 0xb0,
|
||||
.end = 0xb3,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
|
||||
{
|
||||
.name = "sun6i-a31-ar100-clk",
|
||||
.of_compatible = "allwinner,sun6i-a31-ar100-clk",
|
||||
.num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res),
|
||||
.resources = sun6i_a31_ar100_clk_res,
|
||||
},
|
||||
{
|
||||
.name = "sun6i-a31-apb0-clk",
|
||||
.of_compatible = "allwinner,sun6i-a31-apb0-clk",
|
||||
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
|
||||
.resources = sun6i_a31_apb0_clk_res,
|
||||
},
|
||||
{
|
||||
.name = "sun6i-a31-apb0-gates-clk",
|
||||
.of_compatible = "allwinner,sun6i-a31-apb0-gates-clk",
|
||||
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
|
||||
.resources = sun6i_a31_apb0_gates_clk_res,
|
||||
},
|
||||
{
|
||||
.name = "sun6i-a31-apb0-clock-reset",
|
||||
.of_compatible = "allwinner,sun6i-a31-clock-reset",
|
||||
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
|
||||
.resources = sun6i_a31_apb0_rstc_res,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct prcm_data sun6i_a31_prcm_data = {
|
||||
.nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
|
||||
.subdevs = sun6i_a31_prcm_subdevs,
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_prcm_dt_ids[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun6i-a31-prcm",
|
||||
.data = &sun6i_a31_prcm_data,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static int sun6i_prcm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
const struct prcm_data *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
match = of_match_node(sun6i_prcm_dt_ids, np);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
data = match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no prcm memory region provided\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs,
|
||||
res, -1, NULL);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add subdevices\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sun6i_prcm_driver = {
|
||||
.driver = {
|
||||
.name = "sun6i-prcm",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sun6i_prcm_dt_ids,
|
||||
},
|
||||
.probe = sun6i_prcm_probe,
|
||||
};
|
||||
module_platform_driver(sun6i_prcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -95,7 +95,11 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
|
||||
struct device_node *syscon_np;
|
||||
struct regmap *regmap;
|
||||
|
||||
syscon_np = of_parse_phandle(np, property, 0);
|
||||
if (property)
|
||||
syscon_np = of_parse_phandle(np, property, 0);
|
||||
else
|
||||
syscon_np = np;
|
||||
|
||||
if (!syscon_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
|
@@ -119,7 +119,7 @@ static const struct i2c_device_id tps6507x_i2c_id[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id tps6507x_of_match[] = {
|
||||
static const struct of_device_id tps6507x_of_match[] = {
|
||||
{.compatible = "ti,tps6507x", },
|
||||
{},
|
||||
};
|
||||
|
@@ -197,6 +197,7 @@ static struct regmap_irq_chip tps65218_irq_chip = {
|
||||
|
||||
static const struct of_device_id of_tps65218_match_table[] = {
|
||||
{ .compatible = "ti,tps65218", },
|
||||
{}
|
||||
};
|
||||
|
||||
static int tps65218_probe(struct i2c_client *client,
|
||||
|
@@ -444,7 +444,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static struct of_device_id tps6586x_of_match[] = {
|
||||
static const struct of_device_id tps6586x_of_match[] = {
|
||||
{ .compatible = "ti,tps6586x", },
|
||||
{ },
|
||||
};
|
||||
|
@@ -379,7 +379,7 @@ err_sleep_init:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id tps65910_of_match[] = {
|
||||
static const struct of_device_id tps65910_of_match[] = {
|
||||
{ .compatible = "ti,tps65910", .data = (void *)TPS65910},
|
||||
{ .compatible = "ti,tps65911", .data = (void *)TPS65911},
|
||||
{ },
|
||||
|
@@ -87,8 +87,13 @@ static struct reg_default twl6040_defaults[] = {
|
||||
};
|
||||
|
||||
static struct reg_default twl6040_patch[] = {
|
||||
/* Select I2C bus access to dual access registers */
|
||||
{ TWL6040_REG_ACCCTL, 0x09 },
|
||||
/*
|
||||
* Select I2C bus access to dual access registers
|
||||
* Interrupt register is cleared on read
|
||||
* Select fast mode for i2c (400KHz)
|
||||
*/
|
||||
{ TWL6040_REG_ACCCTL,
|
||||
TWL6040_I2CSEL | TWL6040_INTCLRMODE | TWL6040_I2CMODE(1) },
|
||||
};
|
||||
|
||||
|
||||
@@ -286,6 +291,8 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
if (twl6040->power_count++)
|
||||
goto out;
|
||||
|
||||
clk_prepare_enable(twl6040->clk32k);
|
||||
|
||||
/* Allow writes to the chip */
|
||||
regcache_cache_only(twl6040->regmap, false);
|
||||
|
||||
@@ -341,6 +348,8 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
|
||||
twl6040->sysclk = 0;
|
||||
twl6040->mclk = 0;
|
||||
|
||||
clk_disable_unprepare(twl6040->clk32k);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -432,12 +441,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
TWL6040_HPLLENA;
|
||||
break;
|
||||
case 19200000:
|
||||
/*
|
||||
* PLL disabled
|
||||
* (enable PLL if MCLK jitter quality
|
||||
* doesn't meet specification)
|
||||
*/
|
||||
hppllctl |= TWL6040_MCLK_19200KHZ;
|
||||
/* PLL enabled, bypass mode */
|
||||
hppllctl |= TWL6040_MCLK_19200KHZ |
|
||||
TWL6040_HPLLBP | TWL6040_HPLLENA;
|
||||
break;
|
||||
case 26000000:
|
||||
/* PLL enabled, active mode */
|
||||
@@ -445,9 +451,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
TWL6040_HPLLENA;
|
||||
break;
|
||||
case 38400000:
|
||||
/* PLL enabled, active mode */
|
||||
/* PLL enabled, bypass mode */
|
||||
hppllctl |= TWL6040_MCLK_38400KHZ |
|
||||
TWL6040_HPLLENA;
|
||||
TWL6040_HPLLBP | TWL6040_HPLLENA;
|
||||
break;
|
||||
default:
|
||||
dev_err(twl6040->dev,
|
||||
@@ -639,6 +645,12 @@ static int twl6040_probe(struct i2c_client *client,
|
||||
|
||||
i2c_set_clientdata(client, twl6040);
|
||||
|
||||
twl6040->clk32k = devm_clk_get(&client->dev, "clk32k");
|
||||
if (IS_ERR(twl6040->clk32k)) {
|
||||
dev_info(&client->dev, "clk32k is not handled\n");
|
||||
twl6040->clk32k = NULL;
|
||||
}
|
||||
|
||||
twl6040->supplies[0].supply = "vio";
|
||||
twl6040->supplies[1].supply = "v2v1";
|
||||
ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES,
|
||||
@@ -660,6 +672,9 @@ static int twl6040_probe(struct i2c_client *client,
|
||||
mutex_init(&twl6040->mutex);
|
||||
init_completion(&twl6040->ready);
|
||||
|
||||
regmap_register_patch(twl6040->regmap, twl6040_patch,
|
||||
ARRAY_SIZE(twl6040_patch));
|
||||
|
||||
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
|
||||
if (twl6040->rev < 0) {
|
||||
dev_err(&client->dev, "Failed to read revision register: %d\n",
|
||||
@@ -679,6 +694,9 @@ static int twl6040_probe(struct i2c_client *client,
|
||||
GPIOF_OUT_INIT_LOW, "audpwron");
|
||||
if (ret)
|
||||
goto gpio_err;
|
||||
|
||||
/* Clear any pending interrupt */
|
||||
twl6040_reg_read(twl6040, TWL6040_REG_INTID);
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT,
|
||||
@@ -707,10 +725,6 @@ static int twl6040_probe(struct i2c_client *client,
|
||||
goto readyirq_err;
|
||||
}
|
||||
|
||||
/* dual-access registers controlled by I2C only */
|
||||
regmap_register_patch(twl6040->regmap, twl6040_patch,
|
||||
ARRAY_SIZE(twl6040_patch));
|
||||
|
||||
/*
|
||||
* The main functionality of twl6040 to provide audio on OMAP4+ systems.
|
||||
* We can add the ASoC codec child whenever this driver has been loaded.
|
||||
|
@@ -333,7 +333,7 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */
|
||||
{ 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
|
||||
{ 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */
|
||||
{ 0x00000212, 0x0001 }, /* R530 - LDO1 Control 2 */
|
||||
{ 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */
|
||||
{ 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */
|
||||
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
|
||||
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
|
||||
@@ -1037,6 +1037,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_7:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_8:
|
||||
case ARIZONA_COMFORT_NOISE_GENERATOR:
|
||||
case ARIZONA_HAPTICS_CONTROL_1:
|
||||
case ARIZONA_HAPTICS_CONTROL_2:
|
||||
|
@@ -468,10 +468,12 @@ static const struct reg_default wm5110_reg_default[] = {
|
||||
{ 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
|
||||
{ 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
|
||||
{ 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */
|
||||
{ 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */
|
||||
{ 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
|
||||
{ 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
|
||||
{ 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
|
||||
@@ -549,6 +551,7 @@ static const struct reg_default wm5110_reg_default[] = {
|
||||
{ 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */
|
||||
{ 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */
|
||||
{ 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
|
||||
{ 0x000002CB, 0x0000 }, /* R715 - Isolation control */
|
||||
{ 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
|
||||
{ 0x00000300, 0x0000 }, /* R768 - Input Enables */
|
||||
{ 0x00000308, 0x0000 }, /* R776 - Input Rate */
|
||||
@@ -1498,6 +1501,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6:
|
||||
case ARIZONA_COMFORT_NOISE_GENERATOR:
|
||||
case ARIZONA_HAPTICS_CONTROL_1:
|
||||
case ARIZONA_HAPTICS_CONTROL_2:
|
||||
@@ -1580,6 +1585,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_MIC_DETECT_LEVEL_3:
|
||||
case ARIZONA_MIC_DETECT_LEVEL_4:
|
||||
case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
|
||||
case ARIZONA_ISOLATION_CONTROL:
|
||||
case ARIZONA_JACK_DETECT_ANALOGUE:
|
||||
case ARIZONA_INPUT_ENABLES:
|
||||
case ARIZONA_INPUT_ENABLES_STATUS:
|
||||
|
@@ -64,7 +64,7 @@ EXPORT_SYMBOL_GPL(wm8400_block_read);
|
||||
|
||||
static int wm8400_register_codec(struct wm8400 *wm8400)
|
||||
{
|
||||
struct mfd_cell cell = {
|
||||
const struct mfd_cell cell = {
|
||||
.name = "wm8400-codec",
|
||||
.platform_data = wm8400,
|
||||
.pdata_size = sizeof(*wm8400),
|
||||
|
@@ -174,10 +174,10 @@ static const struct reg_default wm8997_reg_default[] = {
|
||||
{ 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
|
||||
{ 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
|
||||
{ 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */
|
||||
{ 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */
|
||||
{ 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */
|
||||
{ 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */
|
||||
{ 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
|
||||
{ 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
|
||||
{ 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
|
||||
@@ -814,10 +814,10 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
|
||||
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
|
||||
case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5:
|
||||
case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6:
|
||||
case ARIZONA_COMFORT_NOISE_GENERATOR:
|
||||
case ARIZONA_HAPTICS_CONTROL_1:
|
||||
case ARIZONA_HAPTICS_CONTROL_2:
|
||||
@@ -846,6 +846,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_RATE_ESTIMATOR_3:
|
||||
case ARIZONA_RATE_ESTIMATOR_4:
|
||||
case ARIZONA_RATE_ESTIMATOR_5:
|
||||
case ARIZONA_DYNAMIC_FREQUENCY_SCALING_1:
|
||||
case ARIZONA_FLL1_CONTROL_1:
|
||||
case ARIZONA_FLL1_CONTROL_2:
|
||||
case ARIZONA_FLL1_CONTROL_3:
|
||||
@@ -880,6 +881,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_FLL2_GPIO_CLOCK:
|
||||
case ARIZONA_MIC_CHARGE_PUMP_1:
|
||||
case ARIZONA_LDO1_CONTROL_1:
|
||||
case ARIZONA_LDO1_CONTROL_2:
|
||||
case ARIZONA_LDO2_CONTROL_1:
|
||||
case ARIZONA_MIC_BIAS_CTRL_1:
|
||||
case ARIZONA_MIC_BIAS_CTRL_2:
|
||||
|
Reference in New Issue
Block a user