For the 3.11 merge we only have one new MFD driver for the Kontron PLD.

But we also have:
 
 - Support for the TPS659038 PMIC from the palmas driver.
 
 - Intel's Coleto Creek and Avoton SoCs support from the lpc_ich driver.
 
 - RTL8411B support from the rtsx driver.
 
 - More DT support for the Arizona, max8998, twl4030-power and the
   ti_am335x_tsadc drivers.
 
 - The SSBI driver move under MFD.
 
 - A conversion to the devm_* API for most of the MFD drivers.
 
 - The twl4030-power got split from twl-core into its own module.
 
 - A major ti_am335x_adc cleanup, leading to a proper DT support.
 
 - Our regular arizona and wm* updates and cleanups from the Wolfson
   folks.
 
 - A better error handling and initialization, and a regulator subdevice
   addition for the 88pm80x driver.
 
 - A bulk platform_set_drvdata() call removal that's no longer need since
   commit 0998d063.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJR2zCaAAoJEIqAPN1PVmxK29EP/ieZf7Z7z7bg/0lEOvtOzACy
 WoCdSGFu5XcHOnlv0Fl1Rr/1AJFQoh4KugkGnVyrlztYVOFymj5VDdd8B43cxMLt
 7ymK/3crIH7uJuOoeDoDr3glLuo0TGB9f5Kv4ITdVD3/+AuqY4VIAisEDb0aWghW
 +v0I3fYeGdwRv+IqO5wacvddSoLa4rmOhnpbVMB2O1Y/LCm/yHI6tAFx1+AfH7y8
 zMHbGFc+gHg1xupJBCnRel0v8J+KNc02G/B1zNom/avL8b/mNXNI8JFxs3bMA0r8
 NpTHJ49OVPbhBQTA4U+BPoG4nzOiAOj0czf9dkGa5cyR8t4C9mmK+s8QHwepzrSG
 qbhCgTqp4bomB1m0RAO+z4F6BHTpmoChpho2btrwN9ZmhMHQeTWnGjjhEwZngpBq
 F22DC6k5ipV0k4962ZHfZ76v2Vot1gfd6zQ5r+2oHMMfWaKgS4L5efP2/wsU9H58
 BxMm84C7OWbgcTRmNn9jl4L9phBD31wvNANfUeMhLMyshnwPK5ZuUdX/+K2rq6h9
 w26Hg62HtKZFv/TEsCBQqpB6zSZa4u/KZzvwEahllQSQGKxIHaNYGtLGzJj9sCM+
 baT/82DFKuEvKfJpUKSBMznImp4WNGEz+8s2w4m/Ssuf30GN2GHjM9Q4gcHJu2mk
 7fTrsSHWYN+EHVzh1Zb8
 =RqMp
 -----END PGP SIGNATURE-----

Merge tag 'mfd-3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next

Pull MFD update from Samuel Ortiz:
 "For the 3.11 merge we only have one new MFD driver for the Kontron
  PLD.

  But we also have:
   - Support for the TPS659038 PMIC from the palmas driver.
   - Intel's Coleto Creek and Avoton SoCs support from the lpc_ich
     driver.
   - RTL8411B support from the rtsx driver.
   - More DT support for the Arizona, max8998, twl4030-power and the
     ti_am335x_tsadc drivers.
   - The SSBI driver move under MFD.
   - A conversion to the devm_* API for most of the MFD drivers.
   - The twl4030-power got split from twl-core into its own module.
   - A major ti_am335x_adc cleanup, leading to a proper DT support.
   - Our regular arizona and wm* updates and cleanups from the Wolfson
     folks.
   - A better error handling and initialization, and a regulator
     subdevice addition for the 88pm80x driver.
   - A bulk platform_set_drvdata() call removal that's no longer need
     since commit 0998d06310 ("device-core: Ensure drvdata = NULL when
     no driver is bound")

* tag 'mfd-3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next: (102 commits)
  mfd: sec: Provide max_register to regmap
  mfd: wm8994: Remove duplicate check for active JACKDET
  MAINTAINERS: Add include directory to MFD file patterns
  mfd: sec: Remove fields not used since regmap conversion
  watchdog: Kontron PLD watchdog timer driver
  mfd: max8998: Add support for Device Tree
  regulator: max8998: Use arrays for specifying voltages in platform data
  mfd: max8998: Add irq domain support
  regulator: palmas: Add TPS659038 support
  mfd: Kontron PLD mfd driver
  mfd: palmas: Add TPS659038 PMIC support
  mfd: palmas: Add SMPS10_BOOST feature
  mfd: palmas: Check if irq is valid
  mfd: lpc_ich: iTCO_wdt patch for Intel Coleto Creek DeviceIDs
  mfd: twl-core: Change TWL6025 references to TWL6032
  mfd: davinci_voicecodec: Fix build breakage
  mfd: vexpress: Make the driver optional for arm and arm64
  mfd: htc-egpio: Use devm_ioremap_nocache() instead of ioremap_nocache()
  mfd: davinci_voicecodec: Convert to use devm_* APIs
  mfd: twl4030-power: Fix relocking on error
  ...
This commit is contained in:
Linus Torvalds 2013-07-10 11:10:27 -07:00
commit 3aa78e0cb5
97 changed files with 4836 additions and 1018 deletions

View file

@ -22,13 +22,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm80x.h>
#include <linux/slab.h>
#define PM800_CHIP_ID (0x00)
/* Interrupt Registers */
#define PM800_INT_STATUS1 (0x05)
#define PM800_ONKEY_INT_STS1 (1 << 0)
@ -113,20 +112,11 @@ enum {
PM800_MAX_IRQ,
};
enum {
/* Procida */
PM800_CHIP_A0 = 0x60,
PM800_CHIP_A1 = 0x61,
PM800_CHIP_B0 = 0x62,
PM800_CHIP_C0 = 0x63,
PM800_CHIP_END = PM800_CHIP_C0,
/* Make sure to update this to the last stepping */
PM8XXX_CHIP_END = PM800_CHIP_END
};
/* PM800: generation identification number */
#define PM800_CHIP_GEN_ID_NUM 0x3
static const struct i2c_device_id pm80x_id_table[] = {
{"88PM800", CHIP_PM800},
{"88PM800", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@ -167,6 +157,13 @@ static struct mfd_cell onkey_devs[] = {
},
};
static struct mfd_cell regulator_devs[] = {
{
.name = "88pm80x-regulator",
.id = -1,
},
};
static const struct regmap_irq pm800_irqs[] = {
/* INT0 */
[PM800_IRQ_ONKEY] = {
@ -315,10 +312,59 @@ out:
return ret;
}
static int device_onkey_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
int ret;
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
NULL);
if (ret) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
return ret;
}
return 0;
}
static int device_rtc_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
int ret;
rtc_devs[0].platform_data = pdata->rtc;
rtc_devs[0].pdata_size =
pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
if (ret) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
return ret;
}
return 0;
}
static int device_regulator_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
int ret;
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs), NULL, 0, NULL);
if (ret) {
dev_err(chip->dev, "Failed to add regulator subdev\n");
return ret;
}
return 0;
}
static int device_irq_init_800(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
@ -362,6 +408,7 @@ static struct regmap_irq_chip pm800_irq_chip = {
.status_base = PM800_INT_STATUS1,
.mask_base = PM800_INT_ENA_1,
.ack_base = PM800_INT_STATUS1,
.mask_invert = 1,
};
static int pm800_pages_init(struct pm80x_chip *chip)
@ -369,77 +416,72 @@ static int pm800_pages_init(struct pm80x_chip *chip)
struct pm80x_subchip *subchip;
struct i2c_client *client = chip->client;
int ret = 0;
subchip = chip->subchip;
/* PM800 block power: i2c addr 0x31 */
if (subchip->power_page_addr) {
subchip->power_page =
i2c_new_dummy(client->adapter, subchip->power_page_addr);
subchip->regmap_power =
devm_regmap_init_i2c(subchip->power_page,
&pm80x_regmap_config);
i2c_set_clientdata(subchip->power_page, chip);
} else
dev_info(chip->dev,
"PM800 block power 0x31: No power_page_addr\n");
if (!subchip || !subchip->power_page_addr || !subchip->gpadc_page_addr)
return -ENODEV;
/* PM800 block GPADC: i2c addr 0x32 */
if (subchip->gpadc_page_addr) {
subchip->gpadc_page = i2c_new_dummy(client->adapter,
subchip->gpadc_page_addr);
subchip->regmap_gpadc =
devm_regmap_init_i2c(subchip->gpadc_page,
&pm80x_regmap_config);
i2c_set_clientdata(subchip->gpadc_page, chip);
} else
dev_info(chip->dev,
"PM800 block GPADC 0x32: No gpadc_page_addr\n");
/* PM800 block power page */
subchip->power_page = i2c_new_dummy(client->adapter,
subchip->power_page_addr);
if (subchip->power_page == NULL) {
ret = -ENODEV;
goto out;
}
return 0;
subchip->regmap_power = devm_regmap_init_i2c(subchip->power_page,
&pm80x_regmap_config);
if (IS_ERR(subchip->regmap_power)) {
ret = PTR_ERR(subchip->regmap_power);
dev_err(chip->dev,
"Failed to allocate regmap_power: %d\n", ret);
goto out;
}
i2c_set_clientdata(subchip->power_page, chip);
/* PM800 block GPADC */
subchip->gpadc_page = i2c_new_dummy(client->adapter,
subchip->gpadc_page_addr);
if (subchip->gpadc_page == NULL) {
ret = -ENODEV;
goto out;
}
subchip->regmap_gpadc = devm_regmap_init_i2c(subchip->gpadc_page,
&pm80x_regmap_config);
if (IS_ERR(subchip->regmap_gpadc)) {
ret = PTR_ERR(subchip->regmap_gpadc);
dev_err(chip->dev,
"Failed to allocate regmap_gpadc: %d\n", ret);
goto out;
}
i2c_set_clientdata(subchip->gpadc_page, chip);
out:
return ret;
}
static void pm800_pages_exit(struct pm80x_chip *chip)
{
struct pm80x_subchip *subchip;
regmap_exit(chip->regmap);
i2c_unregister_device(chip->client);
subchip = chip->subchip;
if (subchip->power_page) {
regmap_exit(subchip->regmap_power);
if (subchip && subchip->power_page)
i2c_unregister_device(subchip->power_page);
}
if (subchip->gpadc_page) {
regmap_exit(subchip->regmap_gpadc);
if (subchip && subchip->gpadc_page)
i2c_unregister_device(subchip->gpadc_page);
}
}
static int device_800_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
int ret, pmic_id;
int ret;
unsigned int val;
ret = regmap_read(chip->regmap, PM800_CHIP_ID, &val);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
goto out;
}
pmic_id = val & PM80X_VERSION_MASK;
if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
chip->version = val;
dev_info(chip->dev,
"88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", val);
} else {
dev_err(chip->dev,
"Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
ret = -EINVAL;
goto out;
}
/*
* alarm wake up bit will be clear in device_irq_init(),
* read before that
@ -468,27 +510,22 @@ static int device_800_init(struct pm80x_chip *chip,
goto out;
}
ret =
mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
NULL);
if (ret < 0) {
ret = device_onkey_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
} else
dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
}
if (pdata && pdata->rtc) {
rtc_devs[0].platform_data = pdata->rtc;
rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out_dev;
} else
dev_info(chip->dev,
"[%s]:Added mfd rtc_devs\n", __func__);
ret = device_rtc_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out;
}
ret = device_regulator_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "Failed to add regulators subdev\n");
goto out;
}
return 0;
@ -507,7 +544,7 @@ static int pm800_probe(struct i2c_client *client,
struct pm80x_platform_data *pdata = client->dev.platform_data;
struct pm80x_subchip *subchip;
ret = pm80x_init(client, id);
ret = pm80x_init(client);
if (ret) {
dev_err(&client->dev, "pm800_init fail\n");
goto out_init;
@ -524,28 +561,31 @@ static int pm800_probe(struct i2c_client *client,
goto err_subchip_alloc;
}
subchip->power_page_addr = pdata->power_page_addr;
subchip->gpadc_page_addr = pdata->gpadc_page_addr;
/* pm800 has 2 addtional pages to support power and gpadc. */
subchip->power_page_addr = client->addr + 1;
subchip->gpadc_page_addr = client->addr + 2;
chip->subchip = subchip;
ret = device_800_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
goto err_subchip_alloc;
}
ret = pm800_pages_init(chip);
if (ret) {
dev_err(&client->dev, "pm800_pages_init failed!\n");
goto err_page_init;
}
ret = device_800_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "Failed to initialize 88pm800 devices\n");
goto err_device_init;
}
if (pdata->plat_config)
pdata->plat_config(chip, pdata);
return 0;
err_device_init:
pm800_pages_exit(chip);
err_page_init:
mfd_remove_devices(chip->dev);
device_irq_exit_800(chip);
err_subchip_alloc:
pm80x_deinit();
out_init:
@ -567,7 +607,7 @@ static int pm800_remove(struct i2c_client *client)
static struct i2c_driver pm800_driver = {
.driver = {
.name = "88PM80X",
.name = "88PM800",
.owner = THIS_MODULE,
.pm = &pm80x_pm_ops,
},

View file

@ -29,10 +29,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#define PM805_CHIP_ID (0x00)
static const struct i2c_device_id pm80x_id_table[] = {
{"88PM805", CHIP_PM805},
{"88PM805", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@ -138,7 +136,7 @@ static struct regmap_irq pm805_irqs[] = {
static int device_irq_init_805(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
@ -192,7 +190,6 @@ static struct regmap_irq_chip pm805_irq_chip = {
static int device_805_init(struct pm80x_chip *chip)
{
int ret = 0;
unsigned int val;
struct regmap *map = chip->regmap;
if (!map) {
@ -200,13 +197,6 @@ static int device_805_init(struct pm80x_chip *chip)
return -EINVAL;
}
ret = regmap_read(map, PM805_CHIP_ID, &val);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
goto out_irq_init;
}
chip->version = val;
chip->regmap_irq_chip = &pm805_irq_chip;
ret = device_irq_init_805(chip);
@ -239,7 +229,7 @@ static int pm805_probe(struct i2c_client *client,
struct pm80x_chip *chip;
struct pm80x_platform_data *pdata = client->dev.platform_data;
ret = pm80x_init(client, id);
ret = pm80x_init(client);
if (ret) {
dev_err(&client->dev, "pm805_init fail!\n");
goto out_init;
@ -249,7 +239,7 @@ static int pm805_probe(struct i2c_client *client,
ret = device_805_init(chip);
if (ret) {
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
dev_err(chip->dev, "Failed to initialize 88pm805 devices\n");
goto err_805_init;
}
@ -276,7 +266,7 @@ static int pm805_remove(struct i2c_client *client)
static struct i2c_driver pm805_driver = {
.driver = {
.name = "88PM80X",
.name = "88PM805",
.owner = THIS_MODULE,
.pm = &pm80x_pm_ops,
},

View file

@ -18,6 +18,23 @@
#include <linux/uaccess.h>
#include <linux/err.h>
/* 88pm80x chips have same definition for chip id register. */
#define PM80X_CHIP_ID (0x00)
#define PM80X_CHIP_ID_NUM(x) (((x) >> 5) & 0x7)
#define PM80X_CHIP_ID_REVISION(x) ((x) & 0x1F)
struct pm80x_chip_mapping {
unsigned int id;
int type;
};
static struct pm80x_chip_mapping chip_mapping[] = {
/* 88PM800 chip id number */
{0x3, CHIP_PM800},
/* 88PM805 chip id number */
{0x0, CHIP_PM805},
};
/*
* workaround: some registers needed by pm805 are defined in pm800, so
* need to use this global variable to maintain the relation between
@ -31,12 +48,13 @@ const struct regmap_config pm80x_regmap_config = {
};
EXPORT_SYMBOL_GPL(pm80x_regmap_config);
int pm80x_init(struct i2c_client *client,
const struct i2c_device_id *id)
int pm80x_init(struct i2c_client *client)
{
struct pm80x_chip *chip;
struct regmap *map;
int ret = 0;
unsigned int val;
int i, ret = 0;
chip =
devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL);
@ -51,10 +69,6 @@ int pm80x_init(struct i2c_client *client,
return ret;
}
chip->id = id->driver_data;
if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
return -EINVAL;
chip->client = client;
chip->regmap = map;
@ -64,6 +78,25 @@ int pm80x_init(struct i2c_client *client,
dev_set_drvdata(chip->dev, chip);
i2c_set_clientdata(chip->client, chip);
ret = regmap_read(chip->regmap, PM80X_CHIP_ID, &val);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(chip_mapping); i++) {
if (chip_mapping[i].id == PM80X_CHIP_ID_NUM(val)) {
chip->type = chip_mapping[i].type;
break;
}
}
if (i == ARRAY_SIZE(chip_mapping)) {
dev_err(chip->dev,
"Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
return -EINVAL;
}
device_init_wakeup(&client->dev, 1);
/*

View file

@ -1150,17 +1150,17 @@ static int pm860x_probe(struct i2c_client *client,
return -EINVAL;
}
chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
chip = devm_kzalloc(&client->dev,
sizeof(struct pm860x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->id = verify_addr(client);
chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
kfree(chip);
return ret;
}
chip->client = client;
@ -1203,8 +1203,6 @@ static int pm860x_remove(struct i2c_client *client)
regmap_exit(chip->regmap_companion);
i2c_unregister_device(chip->companion);
}
regmap_exit(chip->regmap);
kfree(chip);
return 0;
}

View file

@ -53,7 +53,7 @@ config MFD_CROS_EC
help
If you say Y here you get support for the ChromeOS Embedded
Controller (EC) providing keyboard, battery and power services.
You also ned to enable the driver for the bus you are using. The
You also need to enable the driver for the bus you are using. The
protocol for talking to the EC is defined by the bus driver.
config MFD_CROS_EC_I2C
@ -242,6 +242,27 @@ config MFD_JZ4740_ADC
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
config MFD_KEMPLD
tristate "Kontron module PLD device"
select MFD_CORE
help
This is the core driver for the PLD (Programmable Logic Device) found
on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD
device may provide functions like watchdog, GPIO, UART and I2C bus.
The following modules are supported:
* COMe-bIP#
* COMe-bPC2 (ETXexpress-PC)
* COMe-bSC# (ETXexpress-SC T#)
* COMe-cCT6
* COMe-cDC2 (microETXexpress-DC)
* COMe-cPC2 (microETXexpress-PC)
* COMe-mCT10
* ETX-OH
This driver can also be built as a module. If so, the module
will be called kempld-core.
config MFD_88PM800
tristate "Marvell 88PM800"
depends on I2C=y && GENERIC_HARDIRQS
@ -342,6 +363,7 @@ config MFD_MAX8998
bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX8998 and
National Semiconductor LP3974. This is a Power Management IC.
@ -419,7 +441,8 @@ config MFD_PM8XXX
config MFD_PM8921_CORE
tristate "Qualcomm PM8921 PMIC chip"
depends on SSBI && BROKEN
depends on (ARCH_MSM || HEXAGON)
depends on BROKEN
select MFD_CORE
select MFD_PM8XXX
help
@ -1046,6 +1069,12 @@ config MFD_WM5110
help
Support for Wolfson Microelectronics WM5110 low power audio SoC
config MFD_WM8997
bool "Support Wolfson Microelectronics WM8997"
depends on MFD_ARIZONA
help
Support for Wolfson Microelectronics WM8997 low power audio SoC
config MFD_WM8400
bool "Wolfson Microelectronics WM8400"
select MFD_CORE
@ -1144,7 +1173,8 @@ config MCP_UCB1200_TS
endmenu
config VEXPRESS_CONFIG
bool
bool "ARM Versatile Express platform infrastructure"
depends on ARM || ARM64
help
Platform configuration infrastructure for the ARM Ltd.
Versatile Express.

View file

@ -43,6 +43,9 @@ endif
ifneq ($(CONFIG_MFD_WM5110),n)
obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o
endif
ifneq ($(CONFIG_MFD_WM8997),n)
obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o
endif
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
wm831x-objs += wm831x-auxadc.o
@ -126,6 +129,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
obj-$(CONFIG_LPC_ICH) += lpc_ich.o
obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
@ -140,7 +144,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o

View file

@ -312,8 +312,9 @@ static ssize_t aat2870_reg_write_file(struct file *file,
while (*start == ' ')
start++;
if (strict_strtoul(start, 16, &val))
return -EINVAL;
ret = kstrtoul(start, 16, &val);
if (ret)
return ret;
ret = aat2870->write(aat2870, (u8)addr, (u8)val);
if (ret)

View file

@ -491,7 +491,7 @@ static ssize_t ab3100_get_set_reg(struct file *file,
char buf[32];
ssize_t buf_size;
int regp;
unsigned long user_reg;
u8 user_reg;
int err;
int i = 0;
@ -514,34 +514,29 @@ static ssize_t ab3100_get_set_reg(struct file *file,
/*
* Advance pointer to end of string then terminate
* the register string. This is needed to satisfy
* the strict_strtoul() function.
* the kstrtou8() function.
*/
while ((i < buf_size) && (buf[i] != ' '))
i++;
buf[i] = '\0';
err = strict_strtoul(&buf[regp], 16, &user_reg);
err = kstrtou8(&buf[regp], 16, &user_reg);
if (err)
return err;
if (user_reg > 0xff)
return -EINVAL;
/* Either we read or we write a register here */
if (!priv->mode) {
/* Reading */
u8 reg = (u8) user_reg;
u8 regvalue;
ab3100_get_register_interruptible(ab3100, reg, &regvalue);
ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
dev_info(ab3100->dev,
"debug read AB3100 reg[0x%02x]: 0x%02x\n",
reg, regvalue);
user_reg, regvalue);
} else {
int valp;
unsigned long user_value;
u8 reg = (u8) user_reg;
u8 value;
u8 user_value;
u8 regvalue;
/*
@ -557,20 +552,17 @@ static ssize_t ab3100_get_set_reg(struct file *file,
i++;
buf[i] = '\0';
err = strict_strtoul(&buf[valp], 16, &user_value);
err = kstrtou8(&buf[valp], 16, &user_value);
if (err)
return err;
if (user_reg > 0xff)
return -EINVAL;
value = (u8) user_value;
ab3100_set_register_interruptible(ab3100, reg, value);
ab3100_get_register_interruptible(ab3100, reg, &regvalue);
ab3100_set_register_interruptible(ab3100, user_reg, user_value);
ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
dev_info(ab3100->dev,
"debug write reg[0x%02x] with 0x%02x, "
"after readback: 0x%02x\n",
reg, value, regvalue);
user_reg, user_value, regvalue);
}
return buf_size;
}

View file

@ -187,7 +187,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
int err = 0;
int i;
otp = kzalloc(sizeof(struct ab3100_otp), GFP_KERNEL);
otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
if (!otp) {
dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n");
return -ENOMEM;
@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = ab3100_otp_read(otp);
if (err)
goto err_otp_read;
return err;
dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
@ -208,22 +208,19 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = device_create_file(&pdev->dev,
&ab3100_otp_attrs[i]);
if (err)
goto err_create_file;
goto err;
}
/* debugfs entries */
err = ab3100_otp_init_debugfs(&pdev->dev, otp);
if (err)
goto err_init_debugfs;
goto err;
return 0;
err_init_debugfs:
err_create_file:
err:
while (--i >= 0)
device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
err_otp_read:
kfree(otp);
return err;
}
@ -236,7 +233,6 @@ static int __exit ab3100_otp_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev,
&ab3100_otp_attrs[i]);
ab3100_otp_exit_debugfs(otp);
kfree(otp);
return 0;
}

View file

@ -650,6 +650,21 @@ static struct resource ab8500_rtc_resources[] = {
},
};
static struct resource ab8540_rtc_resources[] = {
{
.name = "1S",
.start = AB8540_INT_RTC_1S,
.end = AB8540_INT_RTC_1S,
.flags = IORESOURCE_IRQ,
},
{
.name = "ALARM",
.start = AB8500_INT_RTC_ALARM,
.end = AB8500_INT_RTC_ALARM,
.flags = IORESOURCE_IRQ,
},
};
static struct resource ab8500_poweronkey_db_resources[] = {
{
.name = "ONKEY_DBF",
@ -1050,6 +1065,10 @@ static struct mfd_cell ab8500_devs[] = {
.name = "ab8500-sysctrl",
.of_compatible = "stericsson,ab8500-sysctrl",
},
{
.name = "ab8500-ext-regulator",
.of_compatible = "stericsson,ab8500-ext-regulator",
},
{
.name = "ab8500-regulator",
.of_compatible = "stericsson,ab8500-regulator",
@ -1098,10 +1117,6 @@ static struct mfd_cell ab8500_devs[] = {
.of_compatible = "stericsson,ab8500-pwm",
.id = 3,
},
{
.name = "ab8500-leds",
.of_compatible = "stericsson,ab8500-leds",
},
{
.name = "ab8500-denc",
.of_compatible = "stericsson,ab8500-denc",
@ -1124,6 +1139,7 @@ static struct mfd_cell ab8500_devs[] = {
},
{
.name = "ab8500-codec",
.of_compatible = "stericsson,ab8500-codec",
},
};
@ -1138,6 +1154,9 @@ static struct mfd_cell ab9540_devs[] = {
{
.name = "ab8500-sysctrl",
},
{
.name = "ab8500-ext-regulator",
},
{
.name = "ab8500-regulator",
},
@ -1170,9 +1189,6 @@ static struct mfd_cell ab9540_devs[] = {
.name = "ab8500-pwm",
.id = 1,
},
{
.name = "ab8500-leds",
},
{
.name = "abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
@ -1241,9 +1257,6 @@ static struct mfd_cell ab8505_devs[] = {
.name = "ab8500-pwm",
.id = 1,
},
{
.name = "ab8500-leds",
},
{
.name = "pinctrl-ab8505",
},
@ -1273,6 +1286,9 @@ static struct mfd_cell ab8540_devs[] = {
{
.name = "ab8500-sysctrl",
},
{
.name = "ab8500-ext-regulator",
},
{
.name = "ab8500-regulator",
},
@ -1286,11 +1302,6 @@ static struct mfd_cell ab8540_devs[] = {
.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
.resources = ab8505_gpadc_resources,
},
{
.name = "ab8500-rtc",
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
.resources = ab8500_rtc_resources,
},
{
.name = "ab8500-acc-det",
.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
@ -1305,9 +1316,6 @@ static struct mfd_cell ab8540_devs[] = {
.name = "ab8500-pwm",
.id = 1,
},
{
.name = "ab8500-leds",
},
{
.name = "abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
@ -1331,6 +1339,24 @@ static struct mfd_cell ab8540_devs[] = {
},
};
static struct mfd_cell ab8540_cut1_devs[] = {
{
.name = "ab8500-rtc",
.of_compatible = "stericsson,ab8500-rtc",
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
.resources = ab8500_rtc_resources,
},
};
static struct mfd_cell ab8540_cut2_devs[] = {
{
.name = "ab8540-rtc",
.of_compatible = "stericsson,ab8540-rtc",
.num_resources = ARRAY_SIZE(ab8540_rtc_resources),
.resources = ab8540_rtc_resources,
},
};
static ssize_t show_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -1734,11 +1760,22 @@ static int ab8500_probe(struct platform_device *pdev)
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base, ab8500->domain);
else if (is_ab8540(ab8500))
else if (is_ab8540(ab8500)) {
ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
ARRAY_SIZE(ab8540_devs), NULL,
ab8500->irq_base, ab8500->domain);
else if (is_ab8505(ab8500))
ab8500->irq_base, NULL);
if (ret)
return ret;
if (is_ab8540_1p2_or_earlier(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
ARRAY_SIZE(ab8540_cut1_devs), NULL,
ab8500->irq_base, NULL);
else /* ab8540 >= cut2 */
ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
ARRAY_SIZE(ab8540_cut2_devs), NULL,
ab8500->irq_base, NULL);
} else if (is_ab8505(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
ARRAY_SIZE(ab8505_devs), NULL,
ab8500->irq_base, ab8500->domain);

View file

@ -2757,7 +2757,7 @@ static ssize_t show_irq(struct device *dev,
unsigned int irq_index;
int err;
err = strict_strtoul(attr->attr.name, 0, &name);
err = kstrtoul(attr->attr.name, 0, &name);
if (err)
return err;
@ -2937,7 +2937,6 @@ static struct dentry *ab8500_gpadc_dir;
static int ab8500_debug_probe(struct platform_device *plf)
{
struct dentry *file;
int ret = -ENOMEM;
struct ab8500 *ab8500;
struct resource *res;
debug_bank = AB8500_MISC;
@ -2946,24 +2945,26 @@ static int ab8500_debug_probe(struct platform_device *plf)
ab8500 = dev_get_drvdata(plf->dev.parent);
num_irqs = ab8500->mask_size;
irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL);
irq_count = devm_kzalloc(&plf->dev,
sizeof(*irq_count)*num_irqs, GFP_KERNEL);
if (!irq_count)
return -ENOMEM;
dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
dev_attr = devm_kzalloc(&plf->dev,
sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
if (!dev_attr)
goto out_freeirq_count;
return -ENOMEM;
event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL);
event_name = devm_kzalloc(&plf->dev,
sizeof(*event_name)*num_irqs, GFP_KERNEL);
if (!event_name)
goto out_freedev_attr;
return -ENOMEM;
res = platform_get_resource_byname(plf, 0, "IRQ_AB8500");
if (!res) {
dev_err(&plf->dev, "AB8500 irq not found, err %d\n",
irq_first);
ret = -ENXIO;
goto out_freeevent_name;
return ENXIO;
}
irq_ab8500 = res->start;
@ -2971,16 +2972,14 @@ static int ab8500_debug_probe(struct platform_device *plf)
if (irq_first < 0) {
dev_err(&plf->dev, "First irq not found, err %d\n",
irq_first);
ret = irq_first;
goto out_freeevent_name;
return irq_first;
}
irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
if (irq_last < 0) {
dev_err(&plf->dev, "Last irq not found, err %d\n",
irq_last);
ret = irq_last;
goto out_freeevent_name;
return irq_last;
}
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
@ -3189,22 +3188,13 @@ err:
if (ab8500_dir)
debugfs_remove_recursive(ab8500_dir);
dev_err(&plf->dev, "failed to create debugfs entries.\n");
out_freeevent_name:
kfree(event_name);
out_freedev_attr:
kfree(dev_attr);
out_freeirq_count:
kfree(irq_count);
return ret;
return -ENOMEM;
}
static int ab8500_debug_remove(struct platform_device *plf)
{
debugfs_remove_recursive(ab8500_dir);
kfree(event_name);
kfree(dev_attr);
kfree(irq_count);
return 0;
}

View file

@ -919,7 +919,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
int ret = 0;
struct ab8500_gpadc *gpadc;
gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
gpadc = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_gpadc), GFP_KERNEL);
if (!gpadc) {
dev_err(&pdev->dev, "Error: No memory\n");
return -ENOMEM;
@ -999,8 +999,6 @@ fail_irq:
free_irq(gpadc->irq_sw, gpadc);
free_irq(gpadc->irq_hw, gpadc);
fail:
kfree(gpadc);
gpadc = NULL;
return ret;
}
@ -1025,8 +1023,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
pm_runtime_put_noidle(gpadc->dev);
kfree(gpadc);
gpadc = NULL;
return 0;
}

View file

@ -36,7 +36,9 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
{
struct abx500_device_entry *dev_entry;
dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
dev_entry = devm_kzalloc(dev,
sizeof(struct abx500_device_entry),
GFP_KERNEL);
if (!dev_entry) {
dev_err(dev, "register_ops kzalloc failed");
return -ENOMEM;
@ -54,12 +56,8 @@ void abx500_remove_ops(struct device *dev)
struct abx500_device_entry *dev_entry, *tmp;
list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list)
{
if (dev_entry->dev == dev) {
if (dev_entry->dev == dev)
list_del(&dev_entry->list);
kfree(dev_entry);
}
}
}
EXPORT_SYMBOL(abx500_remove_ops);

View file

@ -223,7 +223,7 @@ static int adp5520_probe(struct i2c_client *client,
return -ENODEV;
}
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@ -244,7 +244,7 @@ static int adp5520_probe(struct i2c_client *client,
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
chip->irq);
goto out_free_chip;
return ret;
}
}
@ -302,9 +302,6 @@ out_free_irq:
if (chip->irq)
free_irq(chip->irq, chip);
out_free_chip:
kfree(chip);
return ret;
}
@ -317,7 +314,6 @@ static int adp5520_remove(struct i2c_client *client)
adp5520_remove_subdevs(chip);
adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
kfree(chip);
return 0;
}

View file

@ -554,6 +554,7 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
{},
};
EXPORT_SYMBOL_GPL(arizona_of_match);
@ -586,6 +587,15 @@ static struct mfd_cell wm5110_devs[] = {
{ .name = "wm5110-codec" },
};
static struct mfd_cell wm8997_devs[] = {
{ .name = "arizona-micsupp" },
{ .name = "arizona-extcon" },
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
{ .name = "arizona-pwm" },
{ .name = "wm8997-codec" },
};
int arizona_dev_init(struct arizona *arizona)
{
struct device *dev = arizona->dev;
@ -608,6 +618,7 @@ int arizona_dev_init(struct arizona *arizona)
switch (arizona->type) {
case WM5102:
case WM5110:
case WM8997:
for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
arizona->core_supplies[i].supply
= wm5102_core_supplies[i];
@ -683,6 +694,7 @@ int arizona_dev_init(struct arizona *arizona)
switch (reg) {
case 0x5102:
case 0x5110:
case 0x8997:
break;
default:
dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
@ -767,6 +779,17 @@ int arizona_dev_init(struct arizona *arizona)
}
apply_patch = wm5110_patch;
break;
#endif
#ifdef CONFIG_MFD_WM8997
case 0x8997:
type_name = "WM8997";
if (arizona->type != WM8997) {
dev_err(arizona->dev, "WM8997 registered as %d\n",
arizona->type);
arizona->type = WM8997;
}
apply_patch = wm8997_patch;
break;
#endif
default:
dev_err(arizona->dev, "Unknown device ID %x\n", reg);
@ -934,6 +957,10 @@ int arizona_dev_init(struct arizona *arizona)
ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
break;
case WM8997:
ret = mfd_add_devices(arizona->dev, -1, wm8997_devs,
ARRAY_SIZE(wm8997_devs), NULL, 0, NULL);
break;
}
if (ret != 0) {

View file

@ -44,6 +44,11 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
case WM5110:
regmap_config = &wm5110_i2c_regmap;
break;
#endif
#ifdef CONFIG_MFD_WM8997
case WM8997:
regmap_config = &wm8997_i2c_regmap;
break;
#endif
default:
dev_err(&i2c->dev, "Unknown device type %ld\n",
@ -80,6 +85,7 @@ static int arizona_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id arizona_i2c_id[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
{ "wm8997", WM8997 },
{ }
};
MODULE_DEVICE_TABLE(i2c, arizona_i2c_id);

View file

@ -208,6 +208,14 @@ int arizona_irq_init(struct arizona *arizona)
ctrlif_error = false;
break;
#endif
#ifdef CONFIG_MFD_WM8997
case WM8997:
aod = &wm8997_aod;
irq = &wm8997_irq;
ctrlif_error = false;
break;
#endif
default:
BUG_ON("Unknown Arizona class device" == NULL);
return -EINVAL;

View file

@ -25,6 +25,8 @@ extern const struct regmap_config wm5102_spi_regmap;
extern const struct regmap_config wm5110_i2c_regmap;
extern const struct regmap_config wm5110_spi_regmap;
extern const struct regmap_config wm8997_i2c_regmap;
extern const struct dev_pm_ops arizona_pm_ops;
extern const struct of_device_id arizona_of_match[];
@ -35,6 +37,9 @@ extern const struct regmap_irq_chip wm5102_irq;
extern const struct regmap_irq_chip wm5110_aod;
extern const struct regmap_irq_chip wm5110_irq;
extern const struct regmap_irq_chip wm8997_aod;
extern const struct regmap_irq_chip wm8997_irq;
int arizona_dev_init(struct arizona *arizona);
int arizona_dev_exit(struct arizona *arizona);
int arizona_irq_init(struct arizona *arizona);

View file

@ -958,7 +958,8 @@ static int __init asic3_probe(struct platform_device *pdev)
unsigned long clksel;
int ret = 0;
asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
asic = devm_kzalloc(&pdev->dev,
sizeof(struct asic3), GFP_KERNEL);
if (asic == NULL) {
printk(KERN_ERR "kzalloc failed\n");
return -ENOMEM;
@ -970,16 +971,14 @@ static int __init asic3_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
ret = -ENOMEM;
dev_err(asic->dev, "no MEM resource\n");
goto out_free;
return -ENOMEM;
}
asic->mapping = ioremap(mem->start, resource_size(mem));
if (!asic->mapping) {
ret = -ENOMEM;
dev_err(asic->dev, "Couldn't ioremap\n");
goto out_free;
return -ENOMEM;
}
asic->irq_base = pdata->irq_base;
@ -1033,9 +1032,6 @@ static int __init asic3_probe(struct platform_device *pdev)
out_unmap:
iounmap(asic->mapping);
out_free:
kfree(asic);
return ret;
}
@ -1058,8 +1054,6 @@ static int asic3_remove(struct platform_device *pdev)
iounmap(asic->mapping);
kfree(asic);
return 0;
}

View file

@ -104,23 +104,19 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
ec_dev->command_sendrecv = cros_ec_command_sendrecv;
if (ec_dev->din_size) {
ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL);
if (!ec_dev->din) {
err = -ENOMEM;
goto fail_din;
}
ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
if (!ec_dev->din)
return -ENOMEM;
}
if (ec_dev->dout_size) {
ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL);
if (!ec_dev->dout) {
err = -ENOMEM;
goto fail_dout;
}
ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
if (!ec_dev->dout)
return -ENOMEM;
}
if (!ec_dev->irq) {
dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq);
goto fail_irq;
return err;
}
err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
@ -128,7 +124,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
"chromeos-ec", ec_dev);
if (err) {
dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
goto fail_irq;
return err;
}
err = mfd_add_devices(dev, 0, cros_devs,
@ -145,11 +141,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
fail_mfd:
free_irq(ec_dev->irq, ec_dev);
fail_irq:
kfree(ec_dev->dout);
fail_dout:
kfree(ec_dev->din);
fail_din:
return err;
}
EXPORT_SYMBOL(cros_ec_register);
@ -158,8 +150,6 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
{
mfd_remove_devices(ec_dev->dev);
free_irq(ec_dev->irq, ec_dev);
kfree(ec_dev->dout);
kfree(ec_dev->din);
return 0;
}

View file

@ -46,56 +46,39 @@ void davinci_vc_write(struct davinci_vc *davinci_vc,
static int __init davinci_vc_probe(struct platform_device *pdev)
{
struct davinci_vc *davinci_vc;
struct resource *res, *mem;
struct resource *res;
struct mfd_cell *cell = NULL;
int ret;
davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL);
davinci_vc = devm_kzalloc(&pdev->dev,
sizeof(struct davinci_vc), GFP_KERNEL);
if (!davinci_vc) {
dev_dbg(&pdev->dev,
"could not allocate memory for private data\n");
return -ENOMEM;
}
davinci_vc->clk = clk_get(&pdev->dev, NULL);
davinci_vc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(davinci_vc->clk)) {
dev_dbg(&pdev->dev,
"could not get the clock for voice codec\n");
ret = -ENODEV;
goto fail1;
return -ENODEV;
}
clk_enable(davinci_vc->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mem resource\n");
ret = -ENODEV;
goto fail2;
}
davinci_vc->pbase = res->start;
davinci_vc->base_size = resource_size(res);
mem = request_mem_region(davinci_vc->pbase, davinci_vc->base_size,
pdev->name);
if (!mem) {
dev_err(&pdev->dev, "VCIF region already claimed\n");
ret = -EBUSY;
goto fail2;
}
davinci_vc->base = ioremap(davinci_vc->pbase, davinci_vc->base_size);
if (!davinci_vc->base) {
dev_err(&pdev->dev, "can't ioremap mem resource.\n");
ret = -ENOMEM;
goto fail3;
davinci_vc->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(davinci_vc->base)) {
ret = PTR_ERR(davinci_vc->base);
goto fail;
}
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
goto fail4;
goto fail;
}
davinci_vc->davinci_vcif.dma_tx_channel = res->start;
@ -106,7 +89,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
goto fail4;
goto fail;
}
davinci_vc->davinci_vcif.dma_rx_channel = res->start;
@ -132,21 +115,13 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
DAVINCI_VC_CELLS, NULL, 0, NULL);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register client devices\n");
goto fail4;
goto fail;
}
return 0;
fail4:
iounmap(davinci_vc->base);
fail3:
release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
fail2:
fail:
clk_disable(davinci_vc->clk);
clk_put(davinci_vc->clk);
davinci_vc->clk = NULL;
fail1:
kfree(davinci_vc);
return ret;
}
@ -157,14 +132,7 @@ static int davinci_vc_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev);
iounmap(davinci_vc->base);
release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
clk_disable(davinci_vc->clk);
clk_put(davinci_vc->clk);
davinci_vc->clk = NULL;
kfree(davinci_vc);
return 0;
}

View file

@ -16,8 +16,8 @@
#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
#define PRCM_ACLK_MGT (0x004)
#define PRCM_SVACLK_MGT (0x008)
#define PRCM_SIACLK_MGT (0x00C)
#define PRCM_SVAMMCSPCLK_MGT (0x008)
#define PRCM_SIAMMDSPCLK_MGT (0x00C)
#define PRCM_SGACLK_MGT (0x014)
#define PRCM_UARTCLK_MGT (0x018)
#define PRCM_MSP02CLK_MGT (0x01C)

View file

@ -270,7 +270,7 @@ static int __init egpio_probe(struct platform_device *pdev)
int ret;
/* Initialize ei data structure. */
ei = kzalloc(sizeof(*ei), GFP_KERNEL);
ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
if (!ei)
return -ENOMEM;
@ -286,7 +286,8 @@ static int __init egpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
goto fail;
ei->base_addr = ioremap_nocache(res->start, resource_size(res));
ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!ei->base_addr)
goto fail;
pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
@ -306,7 +307,9 @@ static int __init egpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ei);
ei->nchips = pdata->num_chips;
ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
ei->chip = devm_kzalloc(&pdev->dev,
sizeof(struct egpio_chip) * ei->nchips,
GFP_KERNEL);
if (!ei->chip) {
ret = -ENOMEM;
goto fail;
@ -361,7 +364,6 @@ static int __init egpio_probe(struct platform_device *pdev)
fail:
printk(KERN_ERR "EGPIO failed to setup\n");
kfree(ei);
return ret;
}
@ -379,9 +381,6 @@ static int __exit egpio_remove(struct platform_device *pdev)
irq_set_chained_handler(ei->chained_irq, NULL);
device_init_wakeup(&pdev->dev, 0);
}
iounmap(ei->base_addr);
kfree(ei->chip);
kfree(ei);
return 0;
}

View file

@ -514,8 +514,8 @@ static int htcpld_setup_chips(struct platform_device *pdev)
/* Setup each chip's output GPIOs */
htcpld->nchips = pdata->num_chip;
htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips,
GFP_KERNEL);
htcpld->chip = devm_kzalloc(dev, sizeof(struct htcpld_chip) * htcpld->nchips,
GFP_KERNEL);
if (!htcpld->chip) {
dev_warn(dev, "Unable to allocate memory for chips\n");
return -ENOMEM;
@ -580,12 +580,11 @@ static int htcpld_core_probe(struct platform_device *pdev)
return -ENXIO;
}
htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL);
htcpld = devm_kzalloc(dev, sizeof(struct htcpld_data), GFP_KERNEL);
if (!htcpld)
return -ENOMEM;
/* Find chained irq */
ret = -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
int flags;
@ -598,7 +597,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
flags, pdev->name, htcpld);
if (ret) {
dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret);
goto fail;
return ret;
} else
device_init_wakeup(dev, 0);
}
@ -609,7 +608,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
/* Setup the htcpld chips */
ret = htcpld_setup_chips(pdev);
if (ret)
goto fail;
return ret;
/* Request the GPIO(s) for the int reset and set them up */
if (pdata->int_reset_gpio_hi) {
@ -644,10 +643,6 @@ static int htcpld_core_probe(struct platform_device *pdev)
dev_info(dev, "Initialized successfully\n");
return 0;
fail:
kfree(htcpld);
return ret;
}
/* The I2C Driver -- used internally */

View file

@ -147,7 +147,7 @@ static int __init pasic3_probe(struct platform_device *pdev)
if (!request_mem_region(r->start, resource_size(r), "pasic3"))
return -EBUSY;
asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL);
asic = devm_kzalloc(dev, sizeof(struct pasic3_data), GFP_KERNEL);
if (!asic)
return -ENOMEM;
@ -156,7 +156,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
asic->mapping = ioremap(r->start, resource_size(r));
if (!asic->mapping) {
dev_err(dev, "couldn't ioremap PASIC3\n");
kfree(asic);
return -ENOMEM;
}
@ -195,7 +194,6 @@ static int pasic3_remove(struct platform_device *pdev)
iounmap(asic->mapping);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, resource_size(r));
kfree(asic);
return 0;
}

View file

@ -438,7 +438,6 @@ static int intel_msic_remove(struct platform_device *pdev)
struct intel_msic *msic = platform_get_drvdata(pdev);
intel_msic_remove_devices(msic);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -183,11 +183,10 @@ static int cmodio_pci_probe(struct pci_dev *dev,
struct cmodio_device *priv;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&dev->dev, "unable to allocate private data\n");
ret = -ENOMEM;
goto out_return;
return -ENOMEM;
}
pci_set_drvdata(dev, priv);
@ -197,7 +196,7 @@ static int cmodio_pci_probe(struct pci_dev *dev,
ret = pci_enable_device(dev);
if (ret) {
dev_err(&dev->dev, "unable to enable device\n");
goto out_free_priv;
return ret;
}
pci_set_master(dev);
@ -248,9 +247,7 @@ out_pci_release_regions:
pci_release_regions(dev);
out_pci_disable_device:
pci_disable_device(dev);
out_free_priv:
kfree(priv);
out_return:
return ret;
}
@ -263,7 +260,6 @@ static void cmodio_pci_remove(struct pci_dev *dev)
iounmap(priv->ctrl);
pci_release_regions(dev);
pci_disable_device(dev);
kfree(priv);
}
#define PCI_VENDOR_ID_JANZ 0x13c3

View file

@ -86,13 +86,13 @@ static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
{
if (atomic_inc_return(&adc->clk_ref) == 1)
clk_enable(adc->clk);
clk_prepare_enable(adc->clk);
}
static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
{
if (atomic_dec_return(&adc->clk_ref) == 0)
clk_disable(adc->clk);
clk_disable_unprepare(adc->clk);
}
static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
@ -294,7 +294,6 @@ static int jz4740_adc_probe(struct platform_device *pdev)
err_clk_put:
clk_put(adc->clk);
err_iounmap:
platform_set_drvdata(pdev, NULL);
iounmap(adc->base);
err_release_mem_region:
release_mem_region(adc->mem->start, resource_size(adc->mem));
@ -317,8 +316,6 @@ static int jz4740_adc_remove(struct platform_device *pdev)
clk_put(adc->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}

641
drivers/mfd/kempld-core.c Normal file
View file

@ -0,0 +1,641 @@
/*
* Kontron PLD MFD core driver
*
* Copyright (c) 2010-2013 Kontron Europe GmbH
* Author: Michael Brunner <michael.brunner@kontron.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/kempld.h>
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/io.h>
#include <linux/delay.h>
#define MAX_ID_LEN 4
static char force_device_id[MAX_ID_LEN + 1] = "";
module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0);
MODULE_PARM_DESC(force_device_id, "Override detected product");
/*
* Get hardware mutex to block firmware from accessing the pld.
* It is possible for the firmware may hold the mutex for an extended length of
* time. This function will block until access has been granted.
*/
static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
{
/* The mutex bit will read 1 until access has been granted */
while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
msleep(1);
}
static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
{
/* The harware mutex is released when 1 is written to the mutex bit. */
iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
}
static int kempld_get_info_generic(struct kempld_device_data *pld)
{
u16 version;
u8 spec;
kempld_get_mutex(pld);
version = kempld_read16(pld, KEMPLD_VERSION);
spec = kempld_read8(pld, KEMPLD_SPEC);
pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
if (spec == 0xff) {
pld->info.spec_minor = 0;
pld->info.spec_major = 1;
} else {
pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
}
if (pld->info.spec_major > 0)
pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
else
pld->feature_mask = 0;
kempld_release_mutex(pld);
return 0;
}
enum kempld_cells {
KEMPLD_I2C = 0,
KEMPLD_WDT,
KEMPLD_GPIO,
KEMPLD_UART,
};
static struct mfd_cell kempld_devs[] = {
[KEMPLD_I2C] = {
.name = "kempld-i2c",
},
[KEMPLD_WDT] = {
.name = "kempld-wdt",
},
[KEMPLD_GPIO] = {
.name = "kempld-gpio",
},
[KEMPLD_UART] = {
.name = "kempld-uart",
},
};
#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs)
static int kempld_register_cells_generic(struct kempld_device_data *pld)
{
struct mfd_cell devs[KEMPLD_MAX_DEVS];
int i = 0;
if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
devs[i++] = kempld_devs[KEMPLD_I2C];
if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
devs[i++] = kempld_devs[KEMPLD_WDT];
if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
devs[i++] = kempld_devs[KEMPLD_GPIO];
if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
devs[i++] = kempld_devs[KEMPLD_UART];
return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
}
static struct resource kempld_ioresource = {
.start = KEMPLD_IOINDEX,
.end = KEMPLD_IODATA,
.flags = IORESOURCE_IO,
};
static const struct kempld_platform_data kempld_platform_data_generic = {
.pld_clock = KEMPLD_CLK,
.ioresource = &kempld_ioresource,
.get_hardware_mutex = kempld_get_hardware_mutex,
.release_hardware_mutex = kempld_release_hardware_mutex,
.get_info = kempld_get_info_generic,
.register_cells = kempld_register_cells_generic,
};
static struct platform_device *kempld_pdev;
static int kempld_create_platform_device(const struct dmi_system_id *id)
{
struct kempld_platform_data *pdata = id->driver_data;
int ret;
kempld_pdev = platform_device_alloc("kempld", -1);
if (!kempld_pdev)
return -ENOMEM;
ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
if (ret)
goto err;
ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
if (ret)
goto err;
ret = platform_device_add(kempld_pdev);
if (ret)
goto err;
return 0;
err:
platform_device_put(kempld_pdev);
return ret;
}
/**
* kempld_read8 - read 8 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
*
* kempld_get_mutex must be called prior to calling this function.
*/
u8 kempld_read8(struct kempld_device_data *pld, u8 index)
{
iowrite8(index, pld->io_index);
return ioread8(pld->io_data);
}
EXPORT_SYMBOL_GPL(kempld_read8);
/**
* kempld_write8 - write 8 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
* @data: new register value
*
* kempld_get_mutex must be called prior to calling this function.
*/
void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
{
iowrite8(index, pld->io_index);
iowrite8(data, pld->io_data);
}
EXPORT_SYMBOL_GPL(kempld_write8);
/**
* kempld_read16 - read 16 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
*
* kempld_get_mutex must be called prior to calling this function.
*/
u16 kempld_read16(struct kempld_device_data *pld, u8 index)
{
return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
}
EXPORT_SYMBOL_GPL(kempld_read16);
/**
* kempld_write16 - write 16 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
* @data: new register value
*
* kempld_get_mutex must be called prior to calling this function.
*/
void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
{
kempld_write8(pld, index, (u8)data);
kempld_write8(pld, index + 1, (u8)(data >> 8));
}
EXPORT_SYMBOL_GPL(kempld_write16);
/**
* kempld_read32 - read 32 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
*
* kempld_get_mutex must be called prior to calling this function.
*/
u32 kempld_read32(struct kempld_device_data *pld, u8 index)
{
return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
}
EXPORT_SYMBOL_GPL(kempld_read32);
/**
* kempld_write32 - write 32 bit register
* @pld: kempld_device_data structure describing the PLD
* @index: register index on the chip
* @data: new register value
*
* kempld_get_mutex must be called prior to calling this function.
*/
void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
{
kempld_write16(pld, index, (u16)data);
kempld_write16(pld, index + 2, (u16)(data >> 16));
}
EXPORT_SYMBOL_GPL(kempld_write32);
/**
* kempld_get_mutex - acquire PLD mutex
* @pld: kempld_device_data structure describing the PLD
*/
void kempld_get_mutex(struct kempld_device_data *pld)
{
struct kempld_platform_data *pdata = pld->dev->platform_data;
mutex_lock(&pld->lock);
pdata->get_hardware_mutex(pld);
}
EXPORT_SYMBOL_GPL(kempld_get_mutex);
/**
* kempld_release_mutex - release PLD mutex
* @pld: kempld_device_data structure describing the PLD
*/
void kempld_release_mutex(struct kempld_device_data *pld)
{
struct kempld_platform_data *pdata = pld->dev->platform_data;
pdata->release_hardware_mutex(pld);
mutex_unlock(&pld->lock);
}
EXPORT_SYMBOL_GPL(kempld_release_mutex);
/**
* kempld_get_info - update device specific information
* @pld: kempld_device_data structure describing the PLD
*
* This function calls the configured board specific kempld_get_info_XXXX
* function which is responsible for gathering information about the specific
* hardware. The information is then stored within the pld structure.
*/
static int kempld_get_info(struct kempld_device_data *pld)
{
struct kempld_platform_data *pdata = pld->dev->platform_data;
return pdata->get_info(pld);
}
/*
* kempld_register_cells - register cell drivers
*
* This function registers cell drivers for the detected hardware by calling
* the configured kempld_register_cells_XXXX function which is responsible
* to detect and register the needed cell drivers.
*/
static int kempld_register_cells(struct kempld_device_data *pld)
{
struct kempld_platform_data *pdata = pld->dev->platform_data;
return pdata->register_cells(pld);
}
static int kempld_detect_device(struct kempld_device_data *pld)
{
char *version_type;
u8 index_reg;
int ret;
mutex_lock(&pld->lock);
/* Check for empty IO space */
index_reg = ioread8(pld->io_index);
if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
mutex_unlock(&pld->lock);
return -ENODEV;
}
/* Release hardware mutex if aquired */
if (!(index_reg & KEMPLD_MUTEX_KEY))
iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
mutex_unlock(&pld->lock);
ret = kempld_get_info(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 %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);
return kempld_register_cells(pld);
}
static int kempld_probe(struct platform_device *pdev)
{
struct kempld_platform_data *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
struct kempld_device_data *pld;
struct resource *ioport;
int ret;
pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
if (!pld)
return -ENOMEM;
ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!ioport)
return -EINVAL;
pld->io_base = devm_ioport_map(dev, ioport->start,
ioport->end - ioport->start);
if (!pld->io_base)
return -ENOMEM;
pld->io_index = pld->io_base;
pld->io_data = pld->io_base + 1;
pld->pld_clock = pdata->pld_clock;
pld->dev = dev;
mutex_init(&pld->lock);
platform_set_drvdata(pdev, pld);
ret = kempld_detect_device(pld);
if (ret)
return ret;
return 0;
}
static int kempld_remove(struct platform_device *pdev)
{
struct kempld_device_data *pld = platform_get_drvdata(pdev);
struct kempld_platform_data *pdata = pld->dev->platform_data;
mfd_remove_devices(&pdev->dev);
pdata->release_hardware_mutex(pld);
return 0;
}
static struct platform_driver kempld_driver = {
.driver = {
.name = "kempld",
.owner = THIS_MODULE,
},
.probe = kempld_probe,
.remove = kempld_remove,
};
static struct dmi_system_id __initdata kempld_dmi_table[] = {
{
.ident = "CCR2",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CCR6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR2",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR2",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR2",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CNTG",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CNTG",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CNTX",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "PXT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "FRI2",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "FRI2",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "MBR1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "NTC1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "NTC1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "NTC1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "NUP1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "UNP1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "UNP1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "UNTG",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "UNTG",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "UUP6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
},
{}
};
MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
static int __init kempld_init(void)
{
const struct dmi_system_id *id;
int ret;
if (force_device_id[0]) {
for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++)
if (strstr(id->ident, force_device_id))
if (id->callback && id->callback(id))
break;
if (id->matches[0].slot == DMI_NONE)
return -ENODEV;
} else {
if (!dmi_check_system(kempld_dmi_table))
return -ENODEV;
}
ret = platform_driver_register(&kempld_driver);
if (ret)
return ret;
return 0;
}
static void __exit kempld_exit(void)
{
if (kempld_pdev)
platform_device_unregister(kempld_pdev);
platform_driver_unregister(&kempld_driver);
}
module_init(kempld_init);
module_exit(kempld_exit);
MODULE_DESCRIPTION("KEM PLD Core Driver");
MODULE_AUTHOR("Michael Brunner <[email protected]>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:kempld-core");

View file

@ -51,6 +51,8 @@
* document number TBD : Lynx Point
* document number TBD : Lynx Point-LP
* document number TBD : Wellsburg
* document number TBD : Avoton SoC
* document number TBD : Coleto Creek
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -207,6 +209,8 @@ enum lpc_chipsets {
LPC_LPT, /* Lynx Point */
LPC_LPT_LP, /* Lynx Point-LP */
LPC_WBG, /* Wellsburg */
LPC_AVN, /* Avoton SoC */
LPC_COLETO, /* Coleto Creek */
};
struct lpc_ich_info lpc_chipset_info[] = {
@ -491,6 +495,14 @@ struct lpc_ich_info lpc_chipset_info[] = {
.name = "Wellsburg",
.iTCO_version = 2,
},
[LPC_AVN] = {
.name = "Avoton SoC",
.iTCO_version = 1,
},
[LPC_COLETO] = {
.name = "Coleto Creek",
.iTCO_version = 2,
},
};
/*
@ -704,6 +716,11 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
{ PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x1f38), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
@ -973,18 +990,7 @@ static struct pci_driver lpc_ich_driver = {
.remove = lpc_ich_remove,
};
static int __init lpc_ich_init(void)
{
return pci_register_driver(&lpc_ich_driver);
}
static void __exit lpc_ich_exit(void)
{
pci_unregister_driver(&lpc_ich_driver);
}
module_init(lpc_ich_init);
module_exit(lpc_ich_exit);
module_pci_driver(lpc_ich_driver);
MODULE_AUTHOR("Aaron Sierra <[email protected]>");
MODULE_DESCRIPTION("LPC interface for Intel ICH");

View file

@ -37,6 +37,7 @@
static struct mfd_cell max77686_devs[] = {
{ .name = "max77686-pmic", },
{ .name = "max77686-rtc", },
{ .name = "max77686-clk", },
};
static struct regmap_config max77686_regmap_config = {
@ -84,12 +85,12 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
pdata = max77686_i2c_parse_dt_pdata(&i2c->dev);
if (!pdata) {
ret = -EIO;
dev_err(&i2c->dev, "No platform data found.\n");
goto err;
return -EIO;
}
max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
max77686 = devm_kzalloc(&i2c->dev,
sizeof(struct max77686_dev), GFP_KERNEL);
if (max77686 == NULL)
return -ENOMEM;
@ -107,7 +108,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(max77686->regmap);
dev_err(max77686->dev, "Failed to allocate register map: %d\n",
ret);
kfree(max77686);
return ret;
}
@ -115,8 +115,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
MAX77686_REG_DEVICE_ID, &data) < 0) {
dev_err(max77686->dev,
"device not found on this channel (this is not an error)\n");
ret = -ENODEV;
goto err;
return -ENODEV;
} else
dev_info(max77686->dev, "device found\n");
@ -127,17 +126,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
if (ret < 0) {
mfd_remove_devices(max77686->dev);
i2c_unregister_device(max77686->rtc);
}
if (ret < 0)
goto err_mfd;
return ret;
err_mfd:
mfd_remove_devices(max77686->dev);
i2c_unregister_device(max77686->rtc);
err:
kfree(max77686);
return ret;
}
@ -147,7 +140,6 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max77686->dev);
i2c_unregister_device(max77686->rtc);
kfree(max77686);
return 0;
}

View file

@ -170,7 +170,8 @@ static int max8925_probe(struct i2c_client *client,
return -EINVAL;
}
chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
chip = devm_kzalloc(&client->dev,
sizeof(struct max8925_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->i2c = client;
@ -199,7 +200,6 @@ static int max8925_remove(struct i2c_client *client)
max8925_device_exit(chip);
i2c_unregister_device(chip->adc);
i2c_unregister_device(chip->rtc);
kfree(chip);
return 0;
}

View file

@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/max8998-private.h>
struct max8998_irq_data {
@ -99,7 +100,8 @@ static struct max8998_irq_data max8998_irqs[] = {
static inline struct max8998_irq_data *
irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
{
return &max8998_irqs[irq - max8998->irq_base];
struct irq_data *data = irq_get_irq_data(irq);
return &max8998_irqs[data->hwirq];
}
static void max8998_irq_lock(struct irq_data *data)
@ -176,8 +178,14 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
/* Report */
for (i = 0; i < MAX8998_IRQ_NR; i++) {
if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
handle_nested_irq(max8998->irq_base + i);
if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) {
irq = irq_find_mapping(max8998->irq_domain, i);
if (WARN_ON(!irq)) {
disable_irq_nosync(max8998->irq);
return IRQ_NONE;
}
handle_nested_irq(irq);
}
}
return IRQ_HANDLED;
@ -185,27 +193,40 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
int max8998_irq_resume(struct max8998_dev *max8998)
{
if (max8998->irq && max8998->irq_base)
max8998_irq_thread(max8998->irq_base, max8998);
if (max8998->irq && max8998->irq_domain)
max8998_irq_thread(max8998->irq, max8998);
return 0;
}
static int max8998_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
struct max8997_dev *max8998 = d->host_data;
irq_set_chip_data(irq, max8998);
irq_set_chip_and_handler(irq, &max8998_irq_chip, handle_edge_irq);
irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
irq_set_noprobe(irq);
#endif
return 0;
}
static struct irq_domain_ops max8998_irq_domain_ops = {
.map = max8998_irq_domain_map,
};
int max8998_irq_init(struct max8998_dev *max8998)
{
int i;
int cur_irq;
int ret;
struct irq_domain *domain;
if (!max8998->irq) {
dev_warn(max8998->dev,
"No interrupt specified, no interrupts\n");
max8998->irq_base = 0;
return 0;
}
if (!max8998->irq_base) {
dev_err(max8998->dev,
"No interrupt base specified, no interrupts\n");
return 0;
}
@ -221,19 +242,13 @@ int max8998_irq_init(struct max8998_dev *max8998)
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
/* register with genirq */
for (i = 0; i < MAX8998_IRQ_NR; i++) {
cur_irq = i + max8998->irq_base;
irq_set_chip_data(cur_irq, max8998);
irq_set_chip_and_handler(cur_irq, &max8998_irq_chip,
handle_edge_irq);
irq_set_nested_thread(cur_irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
domain = irq_domain_add_simple(NULL, MAX8998_IRQ_NR,
max8998->irq_base, &max8998_irq_domain_ops, max8998);
if (!domain) {
dev_err(max8998->dev, "could not create irq domain\n");
return -ENODEV;
}
max8998->irq_domain = domain;
ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,

View file

@ -20,12 +20,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
@ -128,6 +131,56 @@ 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[] = {
{ .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 },
{ .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 },
{ .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 },
{},
};
MODULE_DEVICE_TABLE(of, max8998_dt_match);
#endif
/*
* Only the common platform data elements for max8998 are parsed here from the
* device tree. Other sub-modules of max8998 such as pmic, rtc and others have
* to parse their own platform data elements from device tree.
*
* The max8998 platform data structure is instantiated here and the drivers for
* the sub-modules need not instantiate another instance while parsing their
* platform data.
*/
static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
struct device *dev)
{
struct max8998_platform_data *pd;
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd)
return ERR_PTR(-ENOMEM);
pd->ono = irq_of_parse_and_map(dev->of_node, 1);
/*
* ToDo: the 'wakeup' member in the platform data is more of a linux
* specfic information. Hence, there is no binding for that yet and
* not parsed here.
*/
return pd;
}
static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(max8998_dt_match, i2c->dev.of_node);
return (int)match->data;
}
return (int)id->driver_data;
}
static int max8998_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -139,11 +192,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (max8998 == NULL)
return -ENOMEM;
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
pdata = max8998_i2c_parse_dt_pdata(&i2c->dev);
if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto err;
}
}
i2c_set_clientdata(i2c, max8998);
max8998->dev = &i2c->dev;
max8998->i2c = i2c;
max8998->irq = i2c->irq;
max8998->type = id->driver_data;
max8998->type = max8998_i2c_get_driver_data(i2c, id);
max8998->pdata = pdata;
if (pdata) {
max8998->ono = pdata->ono;
max8998->irq_base = pdata->irq_base;
@ -158,7 +220,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(max8998->dev);
switch (id->driver_data) {
switch (max8998->type) {
case TYPE_LP3974:
ret = mfd_add_devices(max8998->dev, -1,
lp3974_devs, ARRAY_SIZE(lp3974_devs),
@ -314,6 +376,7 @@ static struct i2c_driver max8998_i2c_driver = {
.name = "max8998",
.owner = THIS_MODULE,
.pm = &max8998_pm,
.of_match_table = of_match_ptr(max8998_dt_match),
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,

View file

@ -225,8 +225,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
if (ret == 0)
return 0;
platform_set_drvdata(dev, NULL);
err_ioremap:
iounmap(m->base1);
iounmap(m->base0);
@ -252,7 +250,6 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
platform_set_drvdata(dev, NULL);
mcp_host_del(mcp);
iounmap(m->base1);
iounmap(m->base0);

View file

@ -23,78 +23,7 @@
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/palmas.h>
#include <linux/of_platform.h>
enum palmas_ids {
PALMAS_PMIC_ID,
PALMAS_GPIO_ID,
PALMAS_LEDS_ID,
PALMAS_WDT_ID,
PALMAS_RTC_ID,
PALMAS_PWRBUTTON_ID,
PALMAS_GPADC_ID,
PALMAS_RESOURCE_ID,
PALMAS_CLK_ID,
PALMAS_PWM_ID,
PALMAS_USB_ID,
};
static struct resource palmas_rtc_resources[] = {
{
.start = PALMAS_RTC_ALARM_IRQ,
.end = PALMAS_RTC_ALARM_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static const struct mfd_cell palmas_children[] = {
{
.name = "palmas-pmic",
.id = PALMAS_PMIC_ID,
},
{
.name = "palmas-gpio",
.id = PALMAS_GPIO_ID,
},
{
.name = "palmas-leds",
.id = PALMAS_LEDS_ID,
},
{
.name = "palmas-wdt",
.id = PALMAS_WDT_ID,
},
{
.name = "palmas-rtc",
.id = PALMAS_RTC_ID,
.resources = &palmas_rtc_resources[0],
.num_resources = ARRAY_SIZE(palmas_rtc_resources),
},
{
.name = "palmas-pwrbutton",
.id = PALMAS_PWRBUTTON_ID,
},
{
.name = "palmas-gpadc",
.id = PALMAS_GPADC_ID,
},
{
.name = "palmas-resource",
.id = PALMAS_RESOURCE_ID,
},
{
.name = "palmas-clk",
.id = PALMAS_CLK_ID,
},
{
.name = "palmas-pwm",
.id = PALMAS_PWM_ID,
},
{
.name = "palmas-usb",
.id = PALMAS_USB_ID,
}
};
#include <linux/of_device.h>
static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
{
@ -302,6 +231,21 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c,
palmas_set_pdata_irq_flag(i2c, pdata);
}
static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST;
static unsigned int tps659038_features;
static const struct of_device_id of_palmas_match_tbl[] = {
{
.compatible = "ti,palmas",
.data = &palmas_features,
},
{
.compatible = "ti,tps659038",
.data = &tps659038_features,
},
{ },
};
static int palmas_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@ -309,9 +253,9 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
struct palmas_platform_data *pdata;
struct device_node *node = i2c->dev.of_node;
int ret = 0, i;
unsigned int reg, addr;
unsigned int reg, addr, *features;
int slave;
struct mfd_cell *children;
const struct of_device_id *match;
pdata = dev_get_platdata(&i2c->dev);
@ -333,9 +277,16 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, palmas);
palmas->dev = &i2c->dev;
palmas->id = id->driver_data;
palmas->irq = i2c->irq;
match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev);
if (!match)
return -ENODATA;
features = (unsigned int *)match->data;
palmas->features = *features;
for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
if (i == 0)
palmas->i2c_clients[i] = i2c;
@ -362,6 +313,11 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
}
}
if (!palmas->irq) {
dev_warn(palmas->dev, "IRQ missing: skipping irq request\n");
goto no_irq;
}
/* Change interrupt line output polarity */
if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH)
reg = PALMAS_POLARITY_CTRL_INT_POLARITY;
@ -388,6 +344,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err;
no_irq:
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
PALMAS_PRIMARY_SECONDARY_PAD1);
@ -472,42 +429,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
return ret;
}
children = kmemdup(palmas_children, sizeof(palmas_children),
GFP_KERNEL);
if (!children) {
ret = -ENOMEM;
goto err_irq;
}
children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata;
children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata);
children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata;
children[PALMAS_RESOURCE_ID].pdata_size =
sizeof(*pdata->resource_pdata);
children[PALMAS_USB_ID].platform_data = pdata->usb_pdata;
children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata);
children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata;
children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata);
ret = mfd_add_devices(palmas->dev, -1,
children, ARRAY_SIZE(palmas_children),
NULL, 0,
regmap_irq_get_domain(palmas->irq_data));
kfree(children);
if (ret < 0)
goto err_devices;
return ret;
err_devices:
mfd_remove_devices(palmas->dev);
err_irq:
regmap_del_irq_chip(palmas->irq, palmas->irq_data);
err:
@ -533,11 +456,6 @@ static const struct i2c_device_id palmas_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas", },
{ /* end */ }
};
static struct i2c_driver palmas_i2c_driver = {
.driver = {
.name = "palmas",

View file

@ -35,12 +35,33 @@ static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
return val & 0x0F;
}
static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
{
u8 val = 0;
rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
if (val & 0x2)
return 1;
else
return 0;
}
static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, CD_PAD_CTL,
CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
}
static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
{
if (rtl8411b_is_qfn48(pcr))
rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5);
return rtsx_pci_write_register(pcr, CD_PAD_CTL,
CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
}
static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
@ -214,6 +235,20 @@ static const struct pcr_ops rtl8411_pcr_ops = {
.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
};
static const struct pcr_ops rtl8411b_pcr_ops = {
.extra_init_hw = rtl8411b_extra_init_hw,
.optimize_phy = NULL,
.turn_on_led = rtl8411_turn_on_led,
.turn_off_led = rtl8411_turn_off_led,
.enable_auto_blink = rtl8411_enable_auto_blink,
.disable_auto_blink = rtl8411_disable_auto_blink,
.card_power_on = rtl8411_card_power_on,
.card_power_off = rtl8411_card_power_off,
.switch_output_voltage = rtl8411_switch_output_voltage,
.cd_deglitch = rtl8411_cd_deglitch,
.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
};
/* SD Pull Control Enable:
* SD_DAT[3:0] ==> pull up
* SD_CD ==> pull up
@ -276,6 +311,74 @@ static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
0,
};
static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
0,
};
static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
0,
};
void rtl8411_init_params(struct rtsx_pcr *pcr)
{
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
@ -288,3 +391,32 @@ void rtl8411_init_params(struct rtsx_pcr *pcr)
pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl;
pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl;
}
void rtl8411b_init_params(struct rtsx_pcr *pcr)
{
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
pcr->num_slots = 2;
pcr->ops = &rtl8411b_pcr_ops;
pcr->ic_version = rtl8411_get_ic_version(pcr);
if (rtl8411b_is_qfn48(pcr)) {
pcr->sd_pull_ctl_enable_tbl =
rtl8411b_qfn48_sd_pull_ctl_enable_tbl;
pcr->sd_pull_ctl_disable_tbl =
rtl8411b_qfn48_sd_pull_ctl_disable_tbl;
pcr->ms_pull_ctl_enable_tbl =
rtl8411b_qfn48_ms_pull_ctl_enable_tbl;
pcr->ms_pull_ctl_disable_tbl =
rtl8411b_qfn48_ms_pull_ctl_disable_tbl;
} else {
pcr->sd_pull_ctl_enable_tbl =
rtl8411b_qfn64_sd_pull_ctl_enable_tbl;
pcr->sd_pull_ctl_disable_tbl =
rtl8411b_qfn64_sd_pull_ctl_disable_tbl;
pcr->ms_pull_ctl_enable_tbl =
rtl8411b_qfn64_ms_pull_ctl_enable_tbl;
pcr->ms_pull_ctl_disable_tbl =
rtl8411b_qfn64_ms_pull_ctl_disable_tbl;
}
}

View file

@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, }
};
@ -1038,6 +1039,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5249:
rts5249_init_params(pcr);
break;
case 0x5287:
rtl8411b_init_params(pcr);
break;
}
dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",

View file

@ -33,5 +33,6 @@ void rts5229_init_params(struct rtsx_pcr *pcr);
void rtl8411_init_params(struct rtsx_pcr *pcr);
void rts5227_init_params(struct rtsx_pcr *pcr);
void rts5249_init_params(struct rtsx_pcr *pcr);
void rtl8411b_init_params(struct rtsx_pcr *pcr);
#endif

View file

@ -25,6 +25,9 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/rtc.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regmap.h>
static struct mfd_cell s5m8751_devs[] = {
@ -105,6 +108,26 @@ static struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
static struct regmap_config s2mps11_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S2MPS11_REG_L38CTRL,
};
static struct regmap_config s5m8763_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S5M8763_REG_LBCNFG2,
};
static struct regmap_config s5m8767_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S5M8767_REG_LDO28CTRL,
};
#ifdef CONFIG_OF
/*
@ -160,6 +183,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sec_platform_data *pdata = i2c->dev.platform_data;
const struct regmap_config *regmap;
struct sec_pmic_dev *sec_pmic;
int ret;
@ -190,7 +214,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_pmic->pdata = pdata;
}
sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
switch (sec_pmic->device_type) {
case S2MPS11X:
regmap = &s2mps11_regmap_config;
break;
case S5M8763X:
regmap = &s5m8763_regmap_config;
break;
case S5M8767X:
regmap = &s5m8767_regmap_config;
break;
default:
regmap = &sec_regmap_config;
break;
}
sec_pmic->regmap = devm_regmap_init_i2c(i2c, regmap);
if (IS_ERR(sec_pmic->regmap)) {
ret = PTR_ERR(sec_pmic->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@ -230,13 +269,12 @@ static int sec_pmic_probe(struct i2c_client *i2c,
BUG();
}
if (ret < 0)
if (ret)
goto err;
return ret;
err:
mfd_remove_devices(sec_pmic->dev);
sec_irq_exit(sec_pmic);
i2c_unregister_device(sec_pmic->rtc);
return ret;

333
drivers/mfd/ssbi.c Normal file
View file

@ -0,0 +1,333 @@
/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2010, Google Inc.
*
* Original authors: Code Aurora Forum
*
* Author: Dima Zavin <dima@android.com>
* - Largely rewritten from original to not be an i2c driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/ssbi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
/* SSBI 2.0 controller registers */
#define SSBI2_CMD 0x0008
#define SSBI2_RD 0x0010
#define SSBI2_STATUS 0x0014
#define SSBI2_MODE2 0x001C
/* SSBI_CMD fields */
#define SSBI_CMD_RDWRN (1 << 24)
/* SSBI_STATUS fields */
#define SSBI_STATUS_RD_READY (1 << 2)
#define SSBI_STATUS_READY (1 << 1)
#define SSBI_STATUS_MCHN_BUSY (1 << 0)
/* SSBI_MODE2 fields */
#define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04
#define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT)
#define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
(((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
SSBI_MODE2_REG_ADDR_15_8_MASK))
/* SSBI PMIC Arbiter command registers */
#define SSBI_PA_CMD 0x0000
#define SSBI_PA_RD_STATUS 0x0004
/* SSBI_PA_CMD fields */
#define SSBI_PA_CMD_RDWRN (1 << 24)
#define SSBI_PA_CMD_ADDR_MASK 0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/
/* SSBI_PA_RD_STATUS fields */
#define SSBI_PA_RD_STATUS_TRANS_DONE (1 << 27)
#define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26)
#define SSBI_TIMEOUT_US 100
struct ssbi {
struct device *slave;
void __iomem *base;
spinlock_t lock;
enum ssbi_controller_type controller_type;
int (*read)(struct ssbi *, u16 addr, u8 *buf, int len);
int (*write)(struct ssbi *, u16 addr, u8 *buf, int len);
};
#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev))
static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
{
return readl(ssbi->base + reg);
}
static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg)
{
writel(val, ssbi->base + reg);
}
/*
* Via private exchange with one of the original authors, the hardware
* should generally finish a transaction in about 5us. The worst
* case, is when using the arbiter and both other CPUs have just
* started trying to use the SSBI bus will result in a time of about
* 20us. It should never take longer than this.
*
* As such, this wait merely spins, with a udelay.
*/
static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask)
{
u32 timeout = SSBI_TIMEOUT_US;
u32 val;
while (timeout--) {
val = ssbi_readl(ssbi, SSBI2_STATUS);
if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0))
return 0;
udelay(1);
}
return -ETIMEDOUT;
}
static int
ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
{
u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16);
int ret = 0;
if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
ssbi_writel(ssbi, mode2, SSBI2_MODE2);
}
while (len) {
ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
if (ret)
goto err;
ssbi_writel(ssbi, cmd, SSBI2_CMD);
ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0);
if (ret)
goto err;
*buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff;
len--;
}
err:
return ret;
}
static int
ssbi_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
{
int ret = 0;
if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
ssbi_writel(ssbi, mode2, SSBI2_MODE2);
}
while (len) {
ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
if (ret)
goto err;
ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD);
ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY);
if (ret)
goto err;
buf++;
len--;
}
err:
return ret;
}
/*
* See ssbi_wait_mask for an explanation of the time and the
* busywait.
*/
static inline int
ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data)
{
u32 timeout = SSBI_TIMEOUT_US;
u32 rd_status = 0;
ssbi_writel(ssbi, cmd, SSBI_PA_CMD);
while (timeout--) {
rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED)
return -EPERM;
if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) {
if (data)
*data = rd_status & 0xff;
return 0;
}
udelay(1);
}
return -ETIMEDOUT;
}
static int
ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
{
u32 cmd;
int ret = 0;
cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8;
while (len) {
ret = ssbi_pa_transfer(ssbi, cmd, buf);
if (ret)
goto err;
buf++;
len--;
}
err:
return ret;
}
static int
ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
{
u32 cmd;
int ret = 0;
while (len) {
cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf;
ret = ssbi_pa_transfer(ssbi, cmd, NULL);
if (ret)
goto err;
buf++;
len--;
}
err:
return ret;
}
int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
{
struct ssbi *ssbi = to_ssbi(dev);
unsigned long flags;
int ret;
spin_lock_irqsave(&ssbi->lock, flags);
ret = ssbi->read(ssbi, addr, buf, len);
spin_unlock_irqrestore(&ssbi->lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(ssbi_read);
int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len)
{
struct ssbi *ssbi = to_ssbi(dev);
unsigned long flags;
int ret;
spin_lock_irqsave(&ssbi->lock, flags);
ret = ssbi->write(ssbi, addr, buf, len);
spin_unlock_irqrestore(&ssbi->lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(ssbi_write);
static int ssbi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct resource *mem_res;
struct ssbi *ssbi;
const char *type;
ssbi = devm_kzalloc(&pdev->dev, sizeof(*ssbi), GFP_KERNEL);
if (!ssbi)
return -ENOMEM;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssbi->base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(ssbi->base))
return PTR_ERR(ssbi->base);
platform_set_drvdata(pdev, ssbi);
type = of_get_property(np, "qcom,controller-type", NULL);
if (type == NULL) {
dev_err(&pdev->dev, "Missing qcom,controller-type property\n");
return -EINVAL;
}
dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type);
if (strcmp(type, "ssbi") == 0)
ssbi->controller_type = MSM_SBI_CTRL_SSBI;
else if (strcmp(type, "ssbi2") == 0)
ssbi->controller_type = MSM_SBI_CTRL_SSBI2;
else if (strcmp(type, "pmic-arbiter") == 0)
ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER;
else {
dev_err(&pdev->dev, "Unknown qcom,controller-type\n");
return -EINVAL;
}
if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
ssbi->read = ssbi_pa_read_bytes;
ssbi->write = ssbi_pa_write_bytes;
} else {
ssbi->read = ssbi_read_bytes;
ssbi->write = ssbi_write_bytes;
}
spin_lock_init(&ssbi->lock);
return of_platform_populate(np, NULL, NULL, &pdev->dev);
}
static struct of_device_id ssbi_match_table[] = {
{ .compatible = "qcom,ssbi" },
{}
};
MODULE_DEVICE_TABLE(of, ssbi_match_table);
static struct platform_driver ssbi_driver = {
.probe = ssbi_probe,
.driver = {
.name = "ssbi",
.owner = THIS_MODULE,
.of_match_table = ssbi_match_table,
},
};
module_platform_driver(ssbi_driver);
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
MODULE_ALIAS("platform:ssbi");
MODULE_AUTHOR("Dima Zavin <[email protected]>");

View file

@ -422,7 +422,6 @@ static int t7l66xb_remove(struct platform_device *dev)
iounmap(t7l66xb->scr);
release_resource(&t7l66xb->rscr);
mfd_remove_devices(&dev->dev);
platform_set_drvdata(dev, NULL);
kfree(t7l66xb);
return ret;

View file

@ -217,7 +217,6 @@ static int tc6387xb_remove(struct platform_device *dev)
release_resource(&tc6387xb->rscr);
clk_disable(tc6387xb->clk32k);
clk_put(tc6387xb->clk32k);
platform_set_drvdata(dev, NULL);
kfree(tc6387xb);
return 0;

View file

@ -756,7 +756,6 @@ static int tc6393xb_remove(struct platform_device *dev)
clk_disable(tc6393xb->clk);
iounmap(tc6393xb->scr);
release_resource(&tc6393xb->rscr);
platform_set_drvdata(dev, NULL);
clk_put(tc6393xb->clk);
kfree(tc6393xb);

View file

@ -22,10 +22,10 @@
#include <linux/regmap.h>
#include <linux/mfd/core.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mfd/ti_am335x_tscadc.h>
#include <linux/input/ti_am335x_tsc.h>
#include <linux/platform_data/ti_am335x_adc.h>
static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg)
{
@ -48,6 +48,32 @@ static const struct regmap_config tscadc_regmap_config = {
.val_bits = 32,
};
void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc)
{
tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache);
}
EXPORT_SYMBOL_GPL(am335x_tsc_se_update);
void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val)
{
spin_lock(&tsadc->reg_lock);
tsadc->reg_se_cache |= val;
spin_unlock(&tsadc->reg_lock);
am335x_tsc_se_update(tsadc);
}
EXPORT_SYMBOL_GPL(am335x_tsc_se_set);
void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val)
{
spin_lock(&tsadc->reg_lock);
tsadc->reg_se_cache &= ~val;
spin_unlock(&tsadc->reg_lock);
am335x_tsc_se_update(tsadc);
}
EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
static void tscadc_idle_config(struct ti_tscadc_dev *config)
{
unsigned int idleconfig;
@ -63,27 +89,48 @@ static int ti_tscadc_probe(struct platform_device *pdev)
struct ti_tscadc_dev *tscadc;
struct resource *res;
struct clk *clk;
struct mfd_tscadc_board *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct mfd_cell *cell;
struct property *prop;
const __be32 *cur;
u32 val;
int err, ctrl;
int clk_value, clock_rate;
int tsc_wires, adc_channels = 0, total_channels;
int tsc_wires = 0, adc_channels = 0, total_channels;
int readouts = 0;
if (!pdata) {
dev_err(&pdev->dev, "Could not find platform data\n");
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "Could not find valid DT data.\n");
return -EINVAL;
}
if (pdata->adc_init)
adc_channels = pdata->adc_init->adc_channels;
node = of_get_child_by_name(pdev->dev.of_node, "tsc");
of_property_read_u32(node, "ti,wires", &tsc_wires);
of_property_read_u32(node, "ti,coordiante-readouts", &readouts);
tsc_wires = pdata->tsc_init->wires;
node = of_get_child_by_name(pdev->dev.of_node, "adc");
of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
adc_channels++;
if (val > 7) {
dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n",
val);
return -EINVAL;
}
}
total_channels = tsc_wires + adc_channels;
if (total_channels > 8) {
dev_err(&pdev->dev, "Number of i/p channels more than 8\n");
return -EINVAL;
}
if (total_channels == 0) {
dev_err(&pdev->dev, "Need atleast one channel.\n");
return -EINVAL;
}
if (readouts * 2 + 2 + adc_channels > 16) {
dev_err(&pdev->dev, "Too many step configurations requested\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@ -129,6 +176,7 @@ static int ti_tscadc_probe(struct platform_device *pdev)
goto ret;
}
spin_lock_init(&tscadc->reg_lock);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@ -173,26 +221,37 @@ static int ti_tscadc_probe(struct platform_device *pdev)
ctrl |= CNTRLREG_TSCSSENB;
tscadc_writel(tscadc, REG_CTRL, ctrl);
tscadc->used_cells = 0;
tscadc->tsc_cell = -1;
tscadc->adc_cell = -1;
/* TSC Cell */
cell = &tscadc->cells[TSC_CELL];
cell->name = "tsc";
cell->platform_data = tscadc;
cell->pdata_size = sizeof(*tscadc);
if (tsc_wires > 0) {
tscadc->tsc_cell = tscadc->used_cells;
cell = &tscadc->cells[tscadc->used_cells++];
cell->name = "TI-am335x-tsc";
cell->of_compatible = "ti,am3359-tsc";
cell->platform_data = &tscadc;
cell->pdata_size = sizeof(tscadc);
}
/* ADC Cell */
cell = &tscadc->cells[ADC_CELL];
cell->name = "tiadc";
cell->platform_data = tscadc;
cell->pdata_size = sizeof(*tscadc);
if (adc_channels > 0) {
tscadc->adc_cell = tscadc->used_cells;
cell = &tscadc->cells[tscadc->used_cells++];
cell->name = "TI-am335x-adc";
cell->of_compatible = "ti,am3359-adc";
cell->platform_data = &tscadc;
cell->pdata_size = sizeof(tscadc);
}
err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
TSCADC_CELLS, NULL, 0, NULL);
tscadc->used_cells, NULL, 0, NULL);
if (err < 0)
goto err_disable_clk;
device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, tscadc);
return 0;
err_disable_clk:
@ -239,7 +298,7 @@ static int tscadc_resume(struct device *dev)
CNTRLREG_STEPID | CNTRLREG_4WIRE;
tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
tscadc_idle_config(tscadc_dev);
tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB);
am335x_tsc_se_update(tscadc_dev);
restore = tscadc_readl(tscadc_dev, REG_CTRL);
tscadc_writel(tscadc_dev, REG_CTRL,
(restore | CNTRLREG_TSCSSENB));
@ -256,11 +315,18 @@ static const struct dev_pm_ops tscadc_pm_ops = {
#define TSCADC_PM_OPS NULL
#endif
static const struct of_device_id ti_tscadc_dt_ids[] = {
{ .compatible = "ti,am3359-tscadc", },
{ }
};
MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids);
static struct platform_driver ti_tscadc_driver = {
.driver = {
.name = "ti_tscadc",
.name = "ti_am3359-tscadc",
.owner = THIS_MODULE,
.pm = TSCADC_PM_OPS,
.of_match_table = of_match_ptr(ti_tscadc_dt_ids),
},
.probe = ti_tscadc_probe,
.remove = ti_tscadc_remove,

View file

@ -162,7 +162,6 @@ int tps65912_device_init(struct tps65912 *tps65912)
err:
kfree(init_data);
mfd_remove_devices(tps65912->dev);
kfree(tps65912);
return ret;
}
@ -170,7 +169,6 @@ void tps65912_device_exit(struct tps65912 *tps65912)
{
mfd_remove_devices(tps65912->dev);
tps65912_irq_exit(tps65912);
kfree(tps65912);
}
MODULE_AUTHOR("Margarita Olaya <[email protected]>");

View file

@ -77,7 +77,8 @@ static int tps65912_i2c_probe(struct i2c_client *i2c,
{
struct tps65912 *tps65912;
tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
tps65912 = devm_kzalloc(&i2c->dev,
sizeof(struct tps65912), GFP_KERNEL);
if (tps65912 == NULL)
return -ENOMEM;

View file

@ -85,7 +85,8 @@ static int tps65912_spi_probe(struct spi_device *spi)
{
struct tps65912 *tps65912;
tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
tps65912 = devm_kzalloc(&spi->dev,
sizeof(struct tps65912), GFP_KERNEL);
if (tps65912 == NULL)
return -ENOMEM;

View file

@ -118,7 +118,7 @@
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6025_BASEADD_CHARGER 0x00DA
#define TWL6032_BASEADD_CHARGER 0x00DA
#define TWL6030_BASEADD_LED 0x00F4
/* subchip/slave 2 0x4A - DFT */
@ -718,9 +718,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
| REGULATOR_CHANGE_STATUS,
};
if (features & TWL6025_SUBCLASS) {
if (features & TWL6032_SUBCLASS) {
usb3v3.supply = "ldousb";
regulator = TWL6025_REG_LDOUSB;
regulator = TWL6032_REG_LDOUSB;
} else {
usb3v3.supply = "vusb";
regulator = TWL6030_REG_VUSB;
@ -747,8 +747,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
usb3v3.dev_name = dev_name(child);
} else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) &&
twl_class_is_6030()) {
if (features & TWL6025_SUBCLASS)
child = add_regulator(TWL6025_REG_LDOUSB,
if (features & TWL6032_SUBCLASS)
child = add_regulator(TWL6032_REG_LDOUSB,
pdata->ldousb, features);
else
child = add_regulator(TWL6030_REG_VUSB,
@ -872,7 +872,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
/* twl6030 regulators */
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
!(features & TWL6025_SUBCLASS)) {
!(features & TWL6032_SUBCLASS)) {
child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1,
features);
if (IS_ERR(child))
@ -952,60 +952,60 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
return PTR_ERR(child);
}
/* twl6025 regulators */
/* twl6032 regulators */
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
(features & TWL6025_SUBCLASS)) {
child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
(features & TWL6032_SUBCLASS)) {
child = add_regulator(TWL6032_REG_LDO5, pdata->ldo5,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
child = add_regulator(TWL6032_REG_LDO1, pdata->ldo1,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
child = add_regulator(TWL6032_REG_LDO7, pdata->ldo7,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
child = add_regulator(TWL6032_REG_LDO6, pdata->ldo6,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
child = add_regulator(TWL6032_REG_LDOLN, pdata->ldoln,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
child = add_regulator(TWL6032_REG_LDO2, pdata->ldo2,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
child = add_regulator(TWL6032_REG_LDO4, pdata->ldo4,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
child = add_regulator(TWL6032_REG_LDO3, pdata->ldo3,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
child = add_regulator(TWL6032_REG_SMPS3, pdata->smps3,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
child = add_regulator(TWL6032_REG_SMPS4, pdata->smps4,
features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
child = add_regulator(TWL6032_REG_VIO, pdata->vio6025,
features);
if (IS_ERR(child))
return PTR_ERR(child);
@ -1023,6 +1023,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
return PTR_ERR(child);
}
if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
pdata->power, sizeof(*pdata->power), false,
0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
return 0;
}
@ -1176,10 +1184,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
if ((id->driver_data) & TWL6030_CLASS) {
twl_priv->twl_id = TWL6030_CLASS_ID;
twl_priv->twl_map = &twl6030_map[0];
/* The charger base address is different in twl6025 */
if ((id->driver_data) & TWL6025_SUBCLASS)
/* The charger base address is different in twl6032 */
if ((id->driver_data) & TWL6032_SUBCLASS)
twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
TWL6025_BASEADD_CHARGER;
TWL6032_BASEADD_CHARGER;
twl_regmap_config = twl6030_regmap_config;
} else {
twl_priv->twl_id = TWL4030_CLASS_ID;
@ -1234,10 +1242,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
WARN(status < 0, "Error: reading twl_idcode register value\n");
}
/* load power event scripts */
if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
twl4030_power_init(pdata->power);
/* Maybe init the T2 Interrupt subsystem */
if (client->irq) {
if (twl_class_is_4030()) {
@ -1292,7 +1296,7 @@ static const struct i2c_device_id twl_ids[] = {
{ "tps65921", TPS_SUBSET }, /* fewer LDOs; no codec, no LED
and vibrator. Charger in USB module*/
{ "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */
{ "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
{ "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(i2c, twl_ids);
@ -1305,17 +1309,7 @@ static struct i2c_driver twl_driver = {
.remove = twl_remove,
};
static int __init twl_init(void)
{
return i2c_add_driver(&twl_driver);
}
subsys_initcall(twl_init);
static void __exit twl_exit(void)
{
i2c_del_driver(&twl_driver);
}
module_exit(twl_exit);
module_i2c_driver(twl_driver);
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("I2C Core interface for TWL");

View file

@ -261,10 +261,8 @@ static int twl4030_audio_probe(struct platform_device *pdev)
ret = -ENODEV;
}
if (ret) {
platform_set_drvdata(pdev, NULL);
if (ret)
twl4030_audio_dev = NULL;
}
return ret;
}
@ -272,7 +270,6 @@ static int twl4030_audio_probe(struct platform_device *pdev)
static int twl4030_audio_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
platform_set_drvdata(pdev, NULL);
twl4030_audio_dev = NULL;
return 0;

View file

@ -570,6 +570,7 @@ static struct irq_chip twl4030_sih_irq_chip = {
.irq_set_type = twl4030_sih_set_type,
.irq_bus_lock = twl4030_sih_bus_lock,
.irq_bus_sync_unlock = twl4030_sih_bus_sync_unlock,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
/*----------------------------------------------------------------------*/

View file

@ -775,12 +775,10 @@ static int twl4030_madc_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq\n");
goto err_irq;
goto err_i2c;
}
twl4030_madc = madc;
return 0;
err_irq:
platform_set_drvdata(pdev, NULL);
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
@ -796,7 +794,6 @@ static int twl4030_madc_remove(struct platform_device *pdev)
struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
free_irq(platform_get_irq(pdev, 0), madc);
platform_set_drvdata(pdev, NULL);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
kfree(madc);

View file

@ -28,6 +28,7 @@
#include <linux/pm.h>
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <asm/mach-types.h>
@ -492,6 +493,39 @@ int twl4030_remove_script(u8 flags)
return err;
}
int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
{
int err;
int i;
u8 address = twl4030_start_script_address;
for (i = 0; i < pdata->num; i++) {
err = load_twl4030_script(pdata->scripts[i], address);
if (err)
return err;
address += pdata->scripts[i]->size;
}
return 0;
}
int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
{
struct twl4030_resconfig *resconfig = pdata->resource_config;
int err;
if (resconfig) {
while (resconfig->resource) {
err = twl4030_configure_resource(resconfig);
if (err)
return err;
resconfig++;
}
}
return 0;
}
/*
* In master mode, start the power off sequence.
* After a successful execution, TWL shuts down the power to the SoC
@ -507,43 +541,58 @@ void twl4030_power_off(void)
pr_err("TWL4030 Unable to power off\n");
}
void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
struct device_node *node)
{
if (pdata && pdata->use_poweroff)
return true;
if (of_property_read_bool(node, "ti,use_poweroff"))
return true;
return false;
}
int twl4030_power_probe(struct platform_device *pdev)
{
struct twl4030_power_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
int err = 0;
int i;
struct twl4030_resconfig *resconfig;
u8 val, address = twl4030_start_script_address;
int err2 = 0;
u8 val;
if (!pdata && !node) {
dev_err(&pdev->dev, "Platform data is missing\n");
return -EINVAL;
}
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
goto unlock;
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
TWL4030_PM_MASTER_KEY_CFG2,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
goto unlock;
for (i = 0; i < twl4030_scripts->num; i++) {
err = load_twl4030_script(twl4030_scripts->scripts[i], address);
if (err)
goto load;
address += twl4030_scripts->scripts[i]->size;
if (err) {
pr_err("TWL4030 Unable to unlock registers\n");
return err;
}
resconfig = twl4030_scripts->resource_config;
if (resconfig) {
while (resconfig->resource) {
err = twl4030_configure_resource(resconfig);
if (err)
goto resource;
resconfig++;
if (pdata) {
/* TODO: convert to device tree */
err = twl4030_power_configure_scripts(pdata);
if (err) {
pr_err("TWL4030 failed to load scripts\n");
goto relock;
}
err = twl4030_power_configure_resources(pdata);
if (err) {
pr_err("TWL4030 failed to configure resource\n");
goto relock;
}
}
/* Board has to be wired properly to use this feature */
if (twl4030_scripts->use_poweroff && !pm_power_off) {
if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
/* Default for SEQ_OFFSYNC is set, lets ensure this */
err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
@ -564,22 +613,43 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}
relock:
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
if (err2) {
pr_err("TWL4030 Unable to relock registers\n");
return;
return err2;
}
unlock:
if (err)
pr_err("TWL4030 Unable to unlock registers\n");
return;
load:
if (err)
pr_err("TWL4030 failed to load scripts\n");
return;
resource:
if (err)
pr_err("TWL4030 failed to configure resource\n");
return;
return err;
}
static int twl4030_power_remove(struct platform_device *pdev)
{
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id twl4030_power_of_match[] = {
{.compatible = "ti,twl4030-power", },
{ },
};
MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
#endif
static struct platform_driver twl4030_power_driver = {
.driver = {
.name = "twl4030_power",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl4030_power_of_match),
},
.probe = twl4030_power_probe,
.remove = twl4030_power_remove,
};
module_platform_driver(twl4030_power_driver);
MODULE_AUTHOR("Nokia Corporation");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("Power management for TWL4030");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:twl4030_power");

View file

@ -351,6 +351,8 @@ void __init vexpress_sysreg_of_early_init(void)
}
#ifdef CONFIG_GPIOLIB
#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
[VEXPRESS_GPIO_##_name] = { \
.reg = _reg, \
@ -445,6 +447,8 @@ struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
.leds = vexpress_sysreg_leds,
};
#endif
static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
@ -480,6 +484,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
setup_timer(&vexpress_sysreg_config_timer,
vexpress_sysreg_config_complete, 0);
vexpress_sysreg_dev = &pdev->dev;
#ifdef CONFIG_GPIOLIB
vexpress_sysreg_gpio_chip.dev = &pdev->dev;
err = gpiochip_add(&vexpress_sysreg_gpio_chip);
if (err) {
@ -490,11 +497,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
return err;
}
vexpress_sysreg_dev = &pdev->dev;
platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
sizeof(vexpress_sysreg_leds_pdata));
#endif
device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);

View file

@ -259,20 +259,6 @@ static int wm8994_suspend(struct device *dev)
break;
}
switch (wm8994->type) {
case WM1811:
ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
if (ret < 0) {
dev_err(dev, "Failed to read jackdet: %d\n", ret);
} else if (ret & WM1811_JACKDET_MODE_MASK) {
dev_dbg(dev, "CODEC still active, ignoring suspend\n");
return 0;
}
break;
default:
break;
}
/* Disable LDO pulldowns while the device is suspended if we
* don't know that something will be driving them. */
if (!wm8994->ldo_ena_always_driven)
@ -652,6 +638,17 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
return ret;
}
/* Explicitly put the device into reset in case regulators
* don't get disabled in order to ensure we know the device
* state.
*/
ret = wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
if (ret != 0) {
dev_err(wm8994->dev, "Failed to reset device: %d\n", ret);
return ret;
}
if (regmap_patch) {
ret = regmap_register_patch(wm8994->regmap, regmap_patch,
patch_regs);

View file

@ -14,10 +14,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/regmap.h>
#include <linux/mfd/wm8994/core.h>
@ -138,6 +140,55 @@ static struct regmap_irq_chip wm8994_irq_chip = {
.runtime_pm = true,
};
static void wm8994_edge_irq_enable(struct irq_data *data)
{
}
static void wm8994_edge_irq_disable(struct irq_data *data)
{
}
static struct irq_chip wm8994_edge_irq_chip = {
.name = "wm8994_edge",
.irq_disable = wm8994_edge_irq_disable,
.irq_enable = wm8994_edge_irq_enable,
};
static irqreturn_t wm8994_edge_irq(int irq, void *data)
{
struct wm8994 *wm8994 = data;
while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0));
return IRQ_HANDLED;
}
static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct wm8994 *wm8994 = h->host_data;
irq_set_chip_data(virq, wm8994);
irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq);
irq_set_nested_thread(virq, 1);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(virq);
#endif
return 0;
}
static struct irq_domain_ops wm8994_edge_irq_ops = {
.map = wm8994_edge_irq_map,
.xlate = irq_domain_xlate_twocell,
};
int wm8994_irq_init(struct wm8994 *wm8994)
{
int ret;
@ -156,10 +207,51 @@ int wm8994_irq_init(struct wm8994 *wm8994)
if (pdata->irq_flags)
irqflags = pdata->irq_flags;
ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
irqflags,
wm8994->irq_base, &wm8994_irq_chip,
&wm8994->irq_data);
/* use a GPIO for edge triggered controllers */
if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) {
dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n",
wm8994->irq, pdata->irq_gpio,
gpio_to_irq(pdata->irq_gpio));
wm8994->irq = gpio_to_irq(pdata->irq_gpio);
}
ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio,
GPIOF_IN, "WM8994 IRQ");
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n",
ret);
return ret;
}
wm8994->edge_irq = irq_domain_add_linear(NULL, 1,
&wm8994_edge_irq_ops,
wm8994);
ret = regmap_add_irq_chip(wm8994->regmap,
irq_create_mapping(wm8994->edge_irq,
0),
IRQF_ONESHOT,
wm8994->irq_base, &wm8994_irq_chip,
&wm8994->irq_data);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get IRQ: %d\n",
ret);
return ret;
}
ret = request_threaded_irq(wm8994->irq,
NULL, wm8994_edge_irq,
irqflags,
"WM8994 edge", wm8994);
} else {
ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
irqflags,
wm8994->irq_base, &wm8994_irq_chip,
&wm8994->irq_data);
}
if (ret != 0) {
dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
return ret;

1525
drivers/mfd/wm8997-tables.c Normal file

File diff suppressed because it is too large Load diff