Commit 30304e5a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6

Pull MFD changes from Samuel Ortiz:
 - 4 new drivers: Freescale i.MX on-chip Anatop, Ricoh's RC5T583 and
   TI's TPS65090 and TPS65217.
 - New variants support (8420, 8520 ab9540), cleanups and bug fixes for
   the abx500 and db8500 ST-E chipsets.
 - Some minor fixes and update for the wm8994 from Mark.
 - The beginning of a long term TWL cleanup effort coming from the TI
   folks.
 - Various fixes and cleanups for the s5m, TPS659xx, pm860x, and MAX8997
   drivers.

Fix up trivial conflicts due to duplicate patches and header file
cleanups (<linux/device.h> removal etc).

* tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (97 commits)
  gpio/twl: Add DT support to gpio-twl4030 driver
  gpio/twl: Allocate irq_desc dynamically for SPARSE_IRQ support
  mfd: Detach twl6040 from the pmic mfd driver
  mfd: Replace twl-* pr_ macros by the dev_ equivalent and do various cleanups
  mfd: Micro-optimization on twl4030 IRQ handler
  mfd: Make twl4030 SIH SPARSE_IRQ capable
  mfd: Move twl-core IRQ allocation into twl[4030|6030]-irq files
  mfd: Remove references already defineid in header file from twl-core
  mfd: Remove unneeded header from twl-core
  mfd: Make twl-core not depend on pdata->irq_base/end
  ARM: OMAP2+: board-omap4-*: Do not use anymore TWL6030_IRQ_BASE in board files
  mfd: Return twl6030_mmc_card_detect IRQ for board setup
  Revert "mfd: Add platform data for MAX8997 haptic driver"
  mfd: Add support for TPS65090
  mfd: Add some da9052-i2c section annotations
  mfd: Build rtc5t583 only if I2C config is selected to y.
  mfd: Add anatop mfd driver
  mfd: Fix compilation error in tps65910.h
  mfd: Add 8420 variant to db8500-prcmu
  mfd: Add 8520 PRCMU variant to db8500-prcmu
  ...
parents 750f7706 b8589e2a
twl4030 GPIO controller bindings
Required properties:
- compatible:
- "ti,twl4030-gpio" for twl4030 GPIO controller
- #gpio-cells : Should be two.
- first cell is the pin number
- second cell is used to specify optional parameters (unused)
- gpio-controller : Marks the device node as a GPIO controller.
- #interrupt-cells : Should be 2.
- interrupt-controller: Mark the device node as an interrupt controller
The first cell is the GPIO number.
The second cell is not used.
Example:
twl_gpio: gpio {
compatible = "ti,twl4030-gpio";
#gpio-cells = <2>;
gpio-controller;
#interrupt-cells = <2>;
interrupt-controller;
};
......@@ -490,21 +490,22 @@ static struct platform_device omap_vwlan_device = {
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
int ret = 0;
int irq = 0;
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct omap_mmc_platform_data *pdata = dev->platform_data;
/* Setting MMC1 Card detect Irq */
if (pdev->id == 0) {
ret = twl6030_mmc_card_detect_config();
if (ret)
irq = twl6030_mmc_card_detect_config();
if (irq < 0) {
pr_err("Failed configuring MMC1 card detect\n");
pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
MMCDETECT_INTR_OFFSET;
return irq;
}
pdata->slots[0].card_detect_irq = irq;
pdata->slots[0].card_detect = twl6030_mmc_card_detect;
}
return ret;
return 0;
}
static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
......
......@@ -238,7 +238,7 @@ struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
int ret = 0;
int irq = 0;
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct omap_mmc_platform_data *pdata = dev->platform_data;
......@@ -249,14 +249,15 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
}
/* Setting MMC1 Card detect Irq */
if (pdev->id == 0) {
ret = twl6030_mmc_card_detect_config();
if (ret)
irq = twl6030_mmc_card_detect_config();
if (irq < 0) {
dev_err(dev, "%s: Error card detect config(%d)\n",
__func__, ret);
else
pdata->slots[0].card_detect = twl6030_mmc_card_detect;
__func__, irq);
return irq;
}
pdata->slots[0].card_detect = twl6030_mmc_card_detect;
}
return ret;
return 0;
}
static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
......
......@@ -17,6 +17,8 @@
#include <linux/mfd/wm831x/gpio.h>
#include <linux/mfd/wm8994/pdata.h>
#include <linux/regulator/machine.h>
#include <sound/wm5100.h>
#include <sound/wm8996.h>
#include <sound/wm8962.h>
......@@ -153,6 +155,14 @@ static const struct i2c_board_info wm1259_devs[] = {
},
};
static struct regulator_init_data wm8994_ldo1 = {
.supply_regulator = "WALLVDD",
};
static struct regulator_init_data wm8994_ldo2 = {
.supply_regulator = "WALLVDD",
};
static struct wm8994_pdata wm8994_pdata = {
.gpio_base = CODEC_GPIO_BASE,
.gpio_defaults = {
......@@ -160,8 +170,8 @@ static struct wm8994_pdata wm8994_pdata = {
},
.irq_base = CODEC_IRQ_BASE,
.ldo = {
{ .supply = "WALLVDD" },
{ .supply = "WALLVDD" },
{ .init_data = &wm8994_ldo1, },
{ .init_data = &wm8994_ldo2, },
},
};
......
......@@ -13,7 +13,7 @@
#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START
#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \
+ AB8500_NR_IRQS)
+ AB8500_MAX_NR_IRQS)
/* TC35892 */
#define TC35892_NR_INTERNAL_IRQS 8
......
......@@ -22,11 +22,11 @@ static struct cpufreq_frequency_table freq_table[] = {
},
[1] = {
.index = 1,
.frequency = 300000,
.frequency = 400000,
},
[2] = {
.index = 2,
.frequency = 600000,
.frequency = 800000,
},
[3] = {
/* Used for MAX_OPP, if available */
......@@ -113,12 +113,9 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
if (!prcmu_is_u8400()) {
freq_table[1].frequency = 400000;
freq_table[2].frequency = 800000;
if (prcmu_has_arm_maxopp())
freq_table[3].frequency = 1000000;
}
if (prcmu_has_arm_maxopp())
freq_table[3].frequency = 1000000;
pr_info("db8500-cpufreq : Available frequencies:\n");
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
......
......@@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
struct stmpe_gpio_platform_data *pdata;
struct stmpe_gpio *stmpe_gpio;
int ret;
int irq;
int irq = 0;
pdata = stmpe->pdata->gpio;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
if (!stmpe_gpio)
......@@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->chip.dev = &pdev->dev;
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
if (irq >= 0)
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
else
dev_info(&pdev->dev,
"device configured in no-irq mode; "
"irqs are not available\n");
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
goto out_free;
ret = stmpe_gpio_irq_init(stmpe_gpio);
if (ret)
goto out_disable;
if (irq >= 0) {
ret = stmpe_gpio_irq_init(stmpe_gpio);
if (ret)
goto out_disable;
ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
"stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
}
}
ret = gpiochip_add(&stmpe_gpio->chip);
......@@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
return 0;
out_freeirq:
free_irq(irq, stmpe_gpio);
if (irq >= 0)
free_irq(irq, stmpe_gpio);
out_removeirq:
stmpe_gpio_irq_remove(stmpe_gpio);
if (irq >= 0)
stmpe_gpio_irq_remove(stmpe_gpio);
out_disable:
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
out_free:
......@@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
free_irq(irq, stmpe_gpio);
stmpe_gpio_irq_remove(stmpe_gpio);
if (irq >= 0) {
free_irq(irq, stmpe_gpio);
stmpe_gpio_irq_remove(stmpe_gpio);
}
platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio);
......
......@@ -32,6 +32,8 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/i2c/twl.h>
......@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
* and vMMC2 power supplies based on card presence.
*/
pdata = chip->dev->platform_data;
value |= pdata->mmc_cd & 0x03;
if (pdata)
value |= pdata->mmc_cd & 0x03;
status = gpio_twl4030_write(REG_GPIO_CTRL, value);
}
......@@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev);
static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
{
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
int ret;
struct device_node *node = pdev->dev.of_node;
int ret, irq_base;
/* maybe setup IRQs */
if (pdata->irq_base) {
if (is_module()) {
dev_err(&pdev->dev,
"can't dispatch IRQs from modules\n");
goto no_irqs;
}
ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
if (ret < 0)
return ret;
WARN_ON(ret != pdata->irq_base);
twl4030_gpio_irq_base = ret;
if (is_module()) {
dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
goto no_irqs;
}
irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
return irq_base;
}
irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
&irq_domain_simple_ops, NULL);
ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
if (ret < 0)
return ret;
twl4030_gpio_irq_base = irq_base;
no_irqs:
/*
* NOTE: boards may waste power if they don't set pullups
* and pulldowns correctly ... default for non-ULPI pins is
* pulldown, and some other pins may have external pullups
* or pulldowns. Careful!
*/
ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
if (ret)
dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
pdata->pullups, pdata->pulldowns,
ret);
ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
if (ret)
dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
pdata->debounce, pdata->mmc_cd,
ret);
twl_gpiochip.base = pdata->gpio_base;
twl_gpiochip.base = -1;
twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
twl_gpiochip.dev = &pdev->dev;
/* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
* is (still) clear if use_leds is set.
*/
if (pdata->use_leds)
twl_gpiochip.ngpio += 2;
if (pdata) {
twl_gpiochip.base = pdata->gpio_base;
/*
* NOTE: boards may waste power if they don't set pullups
* and pulldowns correctly ... default for non-ULPI pins is
* pulldown, and some other pins may have external pullups
* or pulldowns. Careful!
*/
ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
if (ret)
dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
pdata->pullups, pdata->pulldowns,
ret);
ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
if (ret)
dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
pdata->debounce, pdata->mmc_cd,
ret);
/*
* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
* is (still) clear if use_leds is set.
*/
if (pdata->use_leds)
twl_gpiochip.ngpio += 2;
}
ret = gpiochip_add(&twl_gpiochip);
if (ret < 0) {
dev_err(&pdev->dev,
"could not register gpiochip, %d\n",
ret);
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl_gpiochip.ngpio = 0;
gpio_twl4030_remove(pdev);
} else if (pdata->setup) {
} else if (pdata && pdata->setup) {
int status;
status = pdata->setup(&pdev->dev,
......@@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
int status;
if (pdata->teardown) {
if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev,
pdata->gpio_base, TWL4030_GPIO_MAX);
if (status) {
......@@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
return -EIO;
}
static const struct of_device_id twl_gpio_match[] = {
{ .compatible = "ti,twl4030-gpio", },
{ },
};
MODULE_DEVICE_TABLE(of, twl_gpio_match);
/* Note: this hardware lives inside an I2C-based multi-function device. */
MODULE_ALIAS("platform:twl4030_gpio");
static struct platform_driver gpio_twl4030_driver = {
.driver.name = "twl4030_gpio",
.driver.owner = THIS_MODULE,
.driver = {
.name = "twl4030_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl_gpio_match),
},
.probe = gpio_twl4030_probe,
.remove = gpio_twl4030_remove,
};
......
......@@ -59,7 +59,7 @@ static int mc13783_adc_read(struct device *dev,
ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
MC13XXX_ADC_MODE_MULT_CHAN,
channel, sample);
channel, 0, 0, sample);
if (ret)
return ret;
......
......@@ -105,6 +105,8 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1);
return 0;
out_irq:
......@@ -129,10 +131,34 @@ static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pm860x_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
return 0;
}
static int pm860x_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
static struct platform_driver pm860x_onkey_driver = {
.driver = {
.name = "88pm860x-onkey",
.owner = THIS_MODULE,
.pm = &pm860x_onkey_pm_ops,
},
.probe = pm860x_onkey_probe,
.remove = __devexit_p(pm860x_onkey_remove),
......
......@@ -39,6 +39,7 @@ struct mc13783_ts_priv {
struct delayed_work work;
struct workqueue_struct *workq;
unsigned int sample[4];
struct mc13xxx_ts_platform_data *touch;
};
static irqreturn_t mc13783_ts_handler(int irq, void *data)
......@@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work)
unsigned int channel = 12;
if (mc13xxx_adc_do_conversion(priv->mc13xxx,
mode, channel, priv->sample) == 0)
mode, channel,
priv->touch->ato, priv->touch->atox,
priv->sample) == 0)
mc13783_ts_report_sample(priv);
}
......@@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
priv->idev = idev;
priv->touch = dev_get_platdata(&pdev->dev);
if (!priv->touch) {
dev_err(&pdev->dev, "missing platform data\n");
ret = -ENODEV;
goto err_free_mem;
}
/*
* We need separate workqueue because mc13783_adc_do_conversion
......
......@@ -114,6 +114,27 @@ static inline int __blink_ctl_mask(int port)
return ret;
}
static int led_power_set(struct pm860x_chip *chip, int port, int on)
{
int ret = -EINVAL;
switch (port) {
case PM8606_LED1_RED:
case PM8606_LED1_GREEN:
case PM8606_LED1_BLUE:
ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
pm8606_osc_disable(chip, RGB1_ENABLE);
break;
case PM8606_LED2_RED:
case PM8606_LED2_GREEN:
case PM8606_LED2_BLUE:
ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
pm8606_osc_disable(chip, RGB2_ENABLE);
break;
}
return ret;
}
static void pm860x_led_work(struct work_struct *work)
{
......@@ -126,6 +147,7 @@ static void pm860x_led_work(struct work_struct *work)
chip = led->chip;
mutex_lock(&led->lock);
if ((led->current_brightness == 0) && led->brightness) {
led_power_set(chip, led->port, 1);
if (led->iset) {
pm860x_set_bits(led->i2c, __led_off(led->port),
LED_CURRENT_MASK, led->iset);
......@@ -149,6 +171,7 @@ static void pm860x_led_work(struct work_struct *work)
LED_CURRENT_MASK, 0);
mask = __blink_ctl_mask(led->port);
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
led_power_set(chip, led->port, 0);
}
}
led->current_brightness = led->brightness;
......
......@@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip)
free_irq(chip->core_irq, chip);
}
int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
{
int ret = -EIO;
struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
chip->client : chip->companion;
dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
__func__, chip->osc_vote,
chip->osc_status);
mutex_lock(&chip->osc_lock);
/* Update voting status */
chip->osc_vote |= client;
/* If reference group is off - turn on*/
if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
/* Enable Reference group Vsys */
if (pm860x_set_bits(i2c, PM8606_VSYS,
PM8606_VSYS_EN, PM8606_VSYS_EN))
goto out;
/*Enable Internal Oscillator */
if (pm860x_set_bits(i2c, PM8606_MISC,
PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
goto out;
/* Update status (only if writes succeed) */
chip->osc_status = PM8606_REF_GP_OSC_ON;
}
mutex_unlock(&chip->osc_lock);
dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
__func__, chip->osc_vote,
chip->osc_status, ret);
return 0;
out:
mutex_unlock(&chip->osc_lock);
return ret;
}
EXPORT_SYMBOL(pm8606_osc_enable);
int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
{
int ret = -EIO;
struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
chip->client : chip->companion;
dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
__func__, chip->osc_vote,
chip->osc_status);
mutex_lock(&chip->osc_lock);
/*Update voting status */
chip->osc_vote &= ~(client);
/* If reference group is off and this is the last client to release
* - turn off */
if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
(chip->osc_vote == REF_GP_NO_CLIENTS)) {
chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
/* Disable Reference group Vsys */
if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
goto out;
/* Disable Internal Oscillator */
if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
goto out;
chip->osc_status = PM8606_REF_GP_OSC_OFF;
}
mutex_unlock(&chip->osc_lock);
dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
__func__, chip->osc_vote,
chip->osc_status, ret);
return 0;
out:
mutex_unlock(&chip->osc_lock);
return ret;
}
EXPORT_SYMBOL(pm8606_osc_disable);
static void __devinit device_osc_init(struct i2c_client *i2c)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
mutex_init(&chip->osc_lock);
/* init portofino reference group voting and status */
/* Disable Reference group Vsys */
pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
/* Disable Internal Oscillator */
pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
chip->osc_vote = REF_GP_NO_CLIENTS;
chip->osc_status = PM8606_REF_GP_OSC_OFF;
}
static void __devinit device_bk_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
......@@ -767,6 +862,15 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
return;
}
static void __devinit device_8606_init(struct pm860x_chip *chip,
struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
device_osc_init(i2c);
device_bk_init(chip, pdata);
device_led_init(chip, pdata);
}
int __devinit pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
......@@ -774,8 +878,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
switch (chip->id) {
case CHIP_PM8606:
device_bk_init(chip, pdata);
device_led_init(chip, pdata);
device_8606_init(chip, chip->client, pdata);
break;
case CHIP_PM8607:
device_8607_init(chip, chip->client, pdata);
......@@ -785,8 +888,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
if (chip->companion) {
switch (chip->id) {
case CHIP_PM8607:
device_bk_init(chip, pdata);
device_led_init(chip, pdata);
device_8606_init(chip, chip->companion, pdata);
break;
case CHIP_PM8606:
device_8607_init(chip, chip->companion, pdata);
......
......@@ -334,10 +334,35 @@ static int __devexit pm860x_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pm860x_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct pm860x_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
enable_irq_wake(chip->core_irq);
return 0;
}
static int pm860x_resume(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct pm860x_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
disable_irq_wake(chip->core_irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
static struct i2c_driver pm860x_driver = {
.driver = {
.name = "88PM860x",
.owner = THIS_MODULE,
.pm = &pm860x_pm_ops,
},
.probe = pm860x_probe,
.remove = __devexit_p(pm860x_remove),
......
......@@ -143,6 +143,21 @@ config TPS6507X
This driver can also be built as a module. If so, the module
will be called tps6507x.
config MFD_TPS65217
tristate "TPS65217 Power Management / White LED chips"
depends on I2C
select MFD_CORE
select REGMAP_I2C
help
If you say yes here you get support for the TPS65217 series of
Power Management / White LED chips.
These include voltage regulators, lithium ion/polymer battery
charger, wled and other features that are often used in portable
devices.
This driver can also be built as a module. If so, the module
will be called tps65217.
config MFD_TPS6586X
bool "TPS6586x Power Management chips"
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
......@@ -162,6 +177,7 @@ config MFD_TPS65910
depends on I2C=y && GPIOLIB
select MFD_CORE
select GPIO_TPS65910
select REGMAP_I2C
help
if you say yes here you get support for the TPS65910 series of
Power Management chips.
......@@ -171,7 +187,7 @@ config MFD_TPS65912
depends on GPIOLIB
config MFD_TPS65912_I2C
bool "TPS95612 Power Management chip with I2C"
bool "TPS65912 Power Management chip with I2C"
select MFD_CORE
select MFD_TPS65912
depends on I2C=y && GPIOLIB
......@@ -400,7 +416,7 @@ config MFD_MAX8997
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
help
Say yes here to support for Maxim Semiconductor MAX8998/8966.
Say yes here to support for Maxim Semiconductor MAX8997/8966.
This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
MUIC controls on chip.
This driver provides common support for accessing the device;
......@@ -812,6 +828,18 @@ config MFD_PM8XXX_IRQ
config TPS65911_COMPARATOR
tristate
config MFD_TPS65090
bool "TPS65090 Power Management chips"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
If you say yes here you get support for the TPS65090 series of
Power Management chips.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
......@@ -831,6 +859,28 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
config MFD_RC5T583
bool "Ricoh RC5T583 Power Management system device"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
Select this option to get support for the RICOH583 Power
Management system device.
This driver provides common support for accessing the device
through i2c interface. The device supports multiple sub-devices
like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
Additional drivers must be enabled in order to use the
different functionality of the device.
config MFD_ANATOP
bool "Support for Freescale i.MX on-chip ANATOP controller"
depends on SOC_IMX6Q
help
Select this option to enable Freescale i.MX on-chip ANATOP
MFD controller. This controller embeds regulator and
thermal devices for Freescale i.MX platforms.
endmenu
endif
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
obj-$(CONFIG_MFD_TPS65217) += tps65217.o
obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o
tps65912-objs := tps65912-core.o tps65912-irq.o
obj-$(CONFIG_MFD_TPS65912) += tps65912.o
......@@ -109,6 +110,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
......@@ -32,6 +32,7 @@
#define AB8500_IT_SOURCE6_REG 0x05
#define AB8500_IT_SOURCE7_REG 0x06
#define AB8500_IT_SOURCE8_REG 0x07
#define AB9540_IT_SOURCE13_REG 0x0C
#define AB8500_IT_SOURCE19_REG 0x12
#define AB8500_IT_SOURCE20_REG 0x13
#define AB8500_IT_SOURCE21_REG 0x14
......@@ -53,6 +54,7 @@
#define AB8500_IT_LATCH9_REG 0x28
#define AB8500_IT_LATCH10_REG 0x29
#define AB8500_IT_LATCH12_REG 0x2B
#define AB9540_IT_LATCH13_REG 0x2C
#define AB8500_IT_LATCH19_REG 0x32
#define AB8500_IT_LATCH20_REG 0x33
#define AB8500_IT_LATCH21_REG 0x34
......@@ -90,21 +92,39 @@
#define AB8500_IT_MASK24_REG 0x57
#define AB8500_REV_REG 0x80
#define AB8500_IC_NAME_REG 0x82
#define AB8500_SWITCH_OFF_STATUS 0x00
#define AB8500_TURN_ON_STATUS 0x00
#define AB9540_MODEM_CTRL2_REG 0x23
#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
/*
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
* numbers are indexed into this array with (num / 8).
* numbers are indexed into this array with (num / 8). The interupts are
* defined in linux/mfd/ab8500.h
*
* This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
* offset 0.
*/
/* AB8500 support */
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
/* AB9540 support */
static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
};
static const char ab8500_version_str[][7] = {
[AB8500_VERSION_AB8500] = "AB8500",
[AB8500_VERSION_AB8505] = "AB8505",
[AB8500_VERSION_AB9540] = "AB9540",
[AB8500_VERSION_AB8540] = "AB8540",
};
static int ab8500_get_chip_id(struct device *dev)
{
struct ab8500 *ab8500;
......@@ -127,9 +147,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
ret = mutex_lock_interruptible(&ab8500->lock);
if (ret)
return ret;
mutex_lock(&ab8500->lock);
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
......@@ -156,9 +174,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
* bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
ret = mutex_lock_interruptible(&ab8500->lock);
if (ret)
return ret;
mutex_lock(&ab8500->lock);
ret = ab8500->read(ab8500, addr);
if (ret < 0)
......@@ -185,31 +201,38 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
int ret;
u8 data;
/* put the u8 bank and u8 reg together into a an u16.
* bank on higher 8 bits and reg in lower */
u16 addr = ((u16)bank) << 8 | reg;
ret = mutex_lock_interruptible(&ab8500->lock);
if (ret)
return ret;
mutex_lock(&ab8500->lock);
ret = ab8500->read(ab8500, addr);
if (ret < 0) {
dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
addr, ret);
goto out;
}
if (ab8500->write_masked == NULL) {
u8 data;
data = (u8)ret;
data = (~bitmask & data) | (bitmask & bitvalues);
ret = ab8500->read(ab8500, addr);
if (ret < 0) {
dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
addr, ret);
goto out;
}
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
addr, ret);
data = (u8)ret;
data = (~bitmask & data) | (bitmask & bitvalues);
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
addr, ret);
dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
data);
goto out;
}
ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
if (ret < 0)
dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
ret);
out:
mutex_unlock(&ab8500->lock);
return ret;
......@@ -248,7 +271,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
for (i = 0; i < ab8500->mask_size; i++) {
u8 old = ab8500->oldmask[i];
u8 new = ab8500->mask[i];
int reg;
......@@ -256,14 +279,17 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
if (new == old)
continue;
/* Interrupt register 12 doesn't exist prior to version 2.0 */
if (ab8500_irq_regoffset[i] == 11 &&
ab8500->chip_id < AB8500_CUT2P0)
/*
* Interrupt register 12 doesn't exist prior to AB8500 version
* 2.0
*/
if (ab8500->irq_reg_offset[i] == 11 &&
is_ab8500_1p1_or_earlier(ab8500))
continue;
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
}
......@@ -306,13 +332,16 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
dev_vdbg(ab8500->dev, "interrupt\n");
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
int regoffset = ab8500_irq_regoffset[i];
for (i = 0; i < ab8500->mask_size; i++) {
int regoffset = ab8500->irq_reg_offset[i];
int status;
u8 value;
/* Interrupt register 12 doesn't exist prior to version 2.0 */
if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
/*
* Interrupt register 12 doesn't exist prior to AB8500 version
* 2.0
*/
if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
continue;
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
......@@ -336,8 +365,16 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
int num_irqs;
if (is_ab9540(ab8500))
num_irqs = AB9540_NR_IRQS;
else if (is_ab8505(ab8500))
num_irqs = AB8505_NR_IRQS;
else
num_irqs = AB8500_NR_IRQS;
for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, ab8500);
irq_set_chip_and_handler(irq, &ab8500_irq_chip,
handle_simple_irq);
......@@ -356,8 +393,16 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
int num_irqs;
for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
if (is_ab9540(ab8500))
num_irqs = AB9540_NR_IRQS;
else if (is_ab8505(ab8500))
num_irqs = AB8505_NR_IRQS;
else
num_irqs = AB8500_NR_IRQS;
for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
......@@ -366,6 +411,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
}
}
/* AB8500 GPIO Resources */
static struct resource __devinitdata ab8500_gpio_resources[] = {
{
.name = "GPIO_INT6",
......@@ -375,6 +421,28 @@ static struct resource __devinitdata ab8500_gpio_resources[] = {
}
};
/* AB9540 GPIO Resources */
static struct resource __devinitdata ab9540_gpio_resources[] = {
{
.name = "GPIO_INT6",
.start = AB8500_INT_GPIO6R,
.end = AB8500_INT_GPIO41F,
.flags = IORESOURCE_IRQ,
},
{
.name = "GPIO_INT14",
.start = AB9540_INT_GPIO50R,
.end = AB9540_INT_GPIO54R,
.flags = IORESOURCE_IRQ,
},
{
.name = "GPIO_INT15",
.start = AB9540_INT_GPIO50F,
.end = AB9540_INT_GPIO54F,
.flags = IORESOURCE_IRQ,
}
};
static struct resource __devinitdata ab8500_gpadc_resources[] = {
{
.name = "HW_CONV_END",
......@@ -490,12 +558,6 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
.end = AB8500_INT_USB_LINK_STATUS,
.flags = IORESOURCE_IRQ,
},
{
.name = "USB_CHARGE_DET_DONE",
.start = AB8500_INT_USB_CHG_DET_DONE,
.end = AB8500_INT_USB_CHG_DET_DONE,
.flags = IORESOURCE_IRQ,
},
{
.name = "VBUS_OVV",
.start = AB8500_INT_VBUS_OVV,
......@@ -534,14 +596,8 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
},
{
.name = "USB_CHARGER_NOT_OKR",
.start = AB8500_INT_USB_CHARGER_NOT_OK,
.end = AB8500_INT_USB_CHARGER_NOT_OK,
.flags = IORESOURCE_IRQ,
},
{
.name = "USB_CHARGER_NOT_OKF",
.start = AB8500_INT_USB_CHARGER_NOT_OKF,
.end = AB8500_INT_USB_CHARGER_NOT_OKF,
.start = AB8500_INT_USB_CHARGER_NOT_OKR,
.end = AB8500_INT_USB_CHARGER_NOT_OKR,
.flags = IORESOURCE_IRQ,
},
{
......@@ -616,6 +672,12 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
.end = AB8500_INT_CC_INT_CALIB,
.flags = IORESOURCE_IRQ,
},
{
.name = "CCEOC",
.start = AB8500_INT_CCEOC,
.end = AB8500_INT_CCEOC,
.flags = IORESOURCE_IRQ,
},
};
static struct resource __devinitdata ab8500_chargalg_resources[] = {};
......@@ -630,8 +692,8 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
},
{
.name = "IRQ_LAST",
.start = AB8500_INT_USB_CHARGER_NOT_OKF,
.end = AB8500_INT_USB_CHARGER_NOT_OKF,
.start = AB8500_INT_XTAL32K_KO,
.end = AB8500_INT_XTAL32K_KO,
.flags = IORESOURCE_IRQ,
},
};
......@@ -691,7 +753,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = {
},
};
static struct mfd_cell __devinitdata ab8500_devs[] = {
static struct mfd_cell __devinitdata abx500_common_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
......@@ -705,11 +767,6 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
{
.name = "ab8500-regulator",
},
{
.name = "ab8500-gpio",
.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
.resources = ab8500_gpio_resources,
},
{
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
......@@ -748,11 +805,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
{
.name = "ab8500-codec",
},
{
.name = "ab8500-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
{
.name = "ab8500-poweron-key",
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
......@@ -781,6 +834,32 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
},
};
static struct mfd_cell __devinitdata ab8500_devs[] = {
{
.name = "ab8500-gpio",
.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
.resources = ab8500_gpio_resources,
},
{
.name = "ab8500-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
};
static struct mfd_cell __devinitdata ab9540_devs[] = {
{
.name = "ab8500-gpio",
.num_resources = ARRAY_SIZE(ab9540_gpio_resources),
.resources = ab9540_gpio_resources,
},
{
.name = "ab9540-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
};
static ssize_t show_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -842,9 +921,64 @@ static ssize_t show_turn_on_status(struct device *dev,
return sprintf(buf, "%#x\n", value);
}
static ssize_t show_ab9540_dbbrstn(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ab8500 *ab8500;
int ret;
u8 value;
ab8500 = dev_get_drvdata(dev);
ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
AB9540_MODEM_CTRL2_REG, &value);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n",
(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
}
static ssize_t store_ab9540_dbbrstn(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct ab8500 *ab8500;
int ret = count;
int err;
u8 bitvalues;
ab8500 = dev_get_drvdata(dev);
if (count > 0) {
switch (buf[0]) {
case '0':
bitvalues = 0;
break;
case '1':
bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
break;
default:
goto exit;
}
err = mask_and_set_register_interruptible(ab8500,
AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
if (err)
dev_info(ab8500->dev,
"Failed to set DBBRSTN %c, err %#x\n",
buf[0], err);
}
exit:
return ret;
}
static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
show_ab9540_dbbrstn, store_ab9540_dbbrstn);
static struct attribute *ab8500_sysfs_entries[] = {
&dev_attr_chip_id.attr,
......@@ -853,11 +987,23 @@ static struct attribute *ab8500_sysfs_entries[] = {
NULL,
};
static struct attribute *ab9540_sysfs_entries[] = {
&dev_attr_chip_id.attr,
&dev_attr_switch_off_status.attr,
&dev_attr_turn_on_status.attr,
&dev_attr_dbbrstn.attr,
NULL,
};
static struct attribute_group ab8500_attr_group = {
.attrs = ab8500_sysfs_entries,
};
int __devinit ab8500_init(struct ab8500 *ab8500)
static struct attribute_group ab9540_attr_group = {
.attrs = ab9540_sysfs_entries,
};
int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
int ret;
......@@ -870,25 +1016,45 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
mutex_init(&ab8500->lock);
mutex_init(&ab8500->irq_lock);
if (version != AB8500_VERSION_UNDEFINED)
ab8500->version = version;
else {
ret = get_register_interruptible(ab8500, AB8500_MISC,
AB8500_IC_NAME_REG, &value);
if (ret < 0)
return ret;
ab8500->version = value;
}
ret = get_register_interruptible(ab8500, AB8500_MISC,
AB8500_REV_REG, &value);
if (ret < 0)
return ret;
switch (value) {
case AB8500_CUT1P0:
case AB8500_CUT1P1:
case AB8500_CUT2P0:
case AB8500_CUT3P0:
case AB8500_CUT3P3:
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
break;
default:
dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
return -EINVAL;
}
ab8500->chip_id = value;
dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
ab8500_version_str[ab8500->version],
ab8500->chip_id >> 4,
ab8500->chip_id & 0x0F);
/* Configure AB8500 or AB9540 IRQ */
if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
ab8500->mask_size = AB9540_NUM_IRQ_REGS;
ab8500->irq_reg_offset = ab9540_irq_regoffset;
} else {
ab8500->mask_size = AB8500_NUM_IRQ_REGS;
ab8500->irq_reg_offset = ab8500_irq_regoffset;
}
ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
if (!ab8500->mask)
return -ENOMEM;
ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
if (!ab8500->oldmask) {
ret = -ENOMEM;
goto out_freemask;
}
/*
* ab8500 has switched off due to (SWITCH_OFF_STATUS):
* 0x01 Swoff bit programming
......@@ -911,30 +1077,33 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
plat->init(ab8500);
/* Clear and mask all interrupts */
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
/* Interrupt register 12 doesn't exist prior to version 2.0 */
if (ab8500_irq_regoffset[i] == 11 &&
ab8500->chip_id < AB8500_CUT2P0)
for (i = 0; i < ab8500->mask_size; i++) {
/*
* Interrupt register 12 doesn't exist prior to AB8500 version
* 2.0
*/
if (ab8500->irq_reg_offset[i] == 11 &&
is_ab8500_1p1_or_earlier(ab8500))
continue;
get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
&value);
set_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
}
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
if (ret)
return ret;
goto out_freeoldmask;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
for (i = 0; i < ab8500->mask_size; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
if (ab8500->irq_base) {
ret = ab8500_irq_init(ab8500);
if (ret)
return ret;
goto out_freeoldmask;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
......@@ -943,17 +1112,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
goto out_removeirq;
}
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
ARRAY_SIZE(abx500_common_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base);
else
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base);
if (ret)
dev_err(ab8500->dev, "error creating sysfs entries\n");
goto out_freeirq;
return ret;
if (is_ab9540(ab8500))
ret = sysfs_create_group(&ab8500->dev->kobj,
&ab9540_attr_group);
else
ret = sysfs_create_group(&ab8500->dev->kobj,
&ab8500_attr_group);
if (ret)
dev_err(ab8500->dev, "error creating sysfs entries\n");
else
return ret;
out_freeirq:
if (ab8500->irq_base)
......@@ -961,18 +1147,27 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
out_removeirq:
if (ab8500->irq_base)
ab8500_irq_remove(ab8500);
out_freeoldmask:
kfree(ab8500->oldmask);
out_freemask:
kfree(ab8500->mask);
return ret;
}
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
if (is_ab9540(ab8500))
sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
else
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
ab8500_irq_remove(ab8500);
}
kfree(ab8500->oldmask);
kfree(ab8500->mask);
return 0;
}
......
......@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/db8500-prcmu.h>
#include <linux/mfd/dbx500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
......@@ -23,6 +23,18 @@ static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
return ret;
}
static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
u8 data)
{
int ret;
ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
&mask, 1);
if (ret < 0)
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
......@@ -38,6 +50,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
static int __devinit ab8500_i2c_probe(struct platform_device *plf)
{
const struct platform_device_id *platid = platform_get_device_id(plf);
struct ab8500 *ab8500;
struct resource *resource;
int ret;
......@@ -58,13 +71,15 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf)
ab8500->read = ab8500_i2c_read;
ab8500->write = ab8500_i2c_write;
ab8500->write_masked = ab8500_i2c_write_masked;
platform_set_drvdata(plf, ab8500);
ret = ab8500_init(ab8500);
ret = ab8500_init(ab8500, platid->driver_data);
if (ret)
kfree(ab8500);
return ret;
}
......@@ -78,13 +93,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf)
return 0;
}
static const struct platform_device_id ab8500_id[] = {
{ "ab8500-i2c", AB8500_VERSION_AB8500 },
{ "ab8505-i2c", AB8500_VERSION_AB8505 },
{ "ab9540-i2c", AB8500_VERSION_AB9540 },
{ "ab8540-i2c", AB8500_VERSION_AB8540 },
{ }
};
static struct platform_driver ab8500_i2c_driver = {
.driver = {
.name = "ab8500-i2c",
.owner = THIS_MODULE,
},
.probe = ab8500_i2c_probe,
.remove = __devexit_p(ab8500_i2c_remove)
.remove = __devexit_p(ab8500_i2c_remove),
.id_table = ab8500_id,
};
static int __init ab8500_i2c_init(void)
......
/*
* Anatop MFD driver
*
* Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
* Copyright (C) 2012 Linaro
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/mfd/anatop.h>
u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
int bit_width)
{
u32 val, mask;
if (bit_width == 32)
mask = ~0;
else
mask = (1 << bit_width) - 1;
val = readl(adata->ioreg + addr);
val = (val >> bit_shift) & mask;
return val;
}
EXPORT_SYMBOL_GPL(anatop_get_bits);
void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
int bit_width, u32 data)
{
u32 val, mask;
if (bit_width == 32)
mask = ~0;
else
mask = (1 << bit_width) - 1;
spin_lock(&adata->reglock);
val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
writel((data << bit_shift) | val, adata->ioreg + addr);
spin_unlock(&adata->reglock);
}
EXPORT_SYMBOL_GPL(anatop_set_bits);
static const struct of_device_id of_anatop_match[] = {
{ .compatible = "fsl,imx6q-anatop", },
{ },
};
static int __devinit of_anatop_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void *ioreg;
struct anatop *drvdata;
ioreg = of_iomap(np, 0);
if (!ioreg)
return -EADDRNOTAVAIL;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->ioreg = ioreg;
spin_lock_init(&drvdata->reglock);
platform_set_drvdata(pdev, drvdata);
of_platform_populate(np, of_anatop_match, NULL, dev);
return 0;
}
static int __devexit of_anatop_remove(struct platform_device *pdev)
{
struct anatop *drvdata;
drvdata = platform_get_drvdata(pdev);
iounmap(drvdata->ioreg);
return 0;
}
static struct platform_driver anatop_of_driver = {
.driver = {
.name = "anatop-mfd",
.owner = THIS_MODULE,
.of_match_table = of_anatop_match,
},
.probe = of_anatop_probe,
.remove = of_anatop_remove,
};
static int __init anatop_init(void)
{
return platform_driver_register(&anatop_of_driver);
}
postcore_initcall(anatop_init);
static void __exit anatop_exit(void)
{
platform_driver_unregister(&anatop_of_driver);
}
module_exit(anatop_exit);
MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
MODULE_DESCRIPTION("ANATOP MFD driver");
MODULE_LICENSE("GPL v2");
......@@ -525,6 +525,11 @@ static void asic3_gpio_set(struct gpio_chip *chip,
return;
}
static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
}
static __init int asic3_gpio_probe(struct platform_device *pdev,
u16 *gpio_config, int num)
{
......@@ -976,6 +981,7 @@ static int __init asic3_probe(struct platform_device *pdev)
asic->gpio.set = asic3_gpio_set;
asic->gpio.direction_input = asic3_gpio_direction_input;
asic->gpio.direction_output = asic3_gpio_direction_output;
asic->gpio.to_irq = asic3_gpio_to_irq;
ret = asic3_gpio_probe(pdev,
pdata->gpio_config,
......
......@@ -16,7 +16,6 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/module.h>
......@@ -647,8 +646,6 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
struct irq_desc *desc;
int ret;
mutex_init(&da9052->io_lock);
if (pdata && pdata->init != NULL)
pdata->init(da9052);
......
......@@ -74,24 +74,27 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
ret = da9052_i2c_enable_multiwrite(da9052);
if (ret < 0)
goto err;
goto err_regmap;
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
goto err;
goto err_regmap;
return 0;
err_regmap:
regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
static int da9052_i2c_remove(struct i2c_client *client)
static int __devexit da9052_i2c_remove(struct i2c_client *client)
{
struct da9052 *da9052 = i2c_get_clientdata(client);
da9052_device_exit(da9052);
regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
......@@ -107,7 +110,7 @@ static struct i2c_device_id da9052_i2c_id[] = {
static struct i2c_driver da9052_i2c_driver = {
.probe = da9052_i2c_probe,
.remove = da9052_i2c_remove,
.remove = __devexit_p(da9052_i2c_remove),
.id_table = da9052_i2c_id,
.driver = {
.name = "da9052",
......
......@@ -21,7 +21,7 @@
#include <linux/mfd/da9052/da9052.h>
static int da9052_spi_probe(struct spi_device *spi)
static int __devinit da9052_spi_probe(struct spi_device *spi)
{
int ret;
const struct spi_device_id *id = spi_get_device_id(spi);
......@@ -52,20 +52,23 @@ static int da9052_spi_probe(struct spi_device *spi)
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
goto err;
goto err_regmap;
return 0;
err_regmap:
regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
static int da9052_spi_remove(struct spi_device *spi)
static int __devexit da9052_spi_remove(struct spi_device *spi)
{
struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
da9052_device_exit(da9052);
regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
......
......@@ -30,6 +30,7 @@
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
......@@ -39,11 +40,6 @@
/* Offset for the firmware version within the TCPM */
#define PRCMU_FW_VERSION_OFFSET 0xA4
/* PRCMU project numbers, defined by PRCMU FW */
#define PRCMU_PROJECT_ID_8500V1_0 1
#define PRCMU_PROJECT_ID_8500V2_0 2
#define PRCMU_PROJECT_ID_8400V2_0 3
/* Index of different voltages to be used when accessing AVSData */
#define PRCM_AVS_BASE 0x2FC
#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
......@@ -137,6 +133,8 @@
#define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0)
#define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1)
#define PRCM_REQ_MB1_PLL_ON_OFF (PRCM_REQ_MB1 + 0x4)
#define PLL_SOC0_OFF 0x1
#define PLL_SOC0_ON 0x2
#define PLL_SOC1_OFF 0x4
#define PLL_SOC1_ON 0x8
......@@ -266,6 +264,11 @@
#define WAKEUP_BIT_GPIO7 BIT(30)
#define WAKEUP_BIT_GPIO8 BIT(31)
static struct {
bool valid;
struct prcmu_fw_version version;
} fw_info;
/*
* This vector maps irq numbers to the bits in the bit field used in
* communication with the PRCMU firmware.
......@@ -341,11 +344,13 @@ static struct {
* mb1_transfer - state needed for mailbox 1 communication.
* @lock: The transaction lock.
* @work: The transaction completion structure.
* @ape_opp: The current APE OPP.
* @ack: Reply ("acknowledge") data.
*/
static struct {
struct mutex lock;
struct completion work;
u8 ape_opp;
struct {
u8 header;
u8 arm_opp;
......@@ -413,79 +418,102 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
/* Spinlocks */
static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock);
static DEFINE_SPINLOCK(gpiocr_lock);
/* Global var to runtime determine TCDM base for v2 or v1 */
static __iomem void *tcdm_base;
struct clk_mgt {
unsigned int offset;
void __iomem *reg;
u32 pllsw;
int branch;
bool clk38div;
};
enum {
PLL_RAW,
PLL_FIX,
PLL_DIV
};
static DEFINE_SPINLOCK(clk_mgt_lock);
#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
{ (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(SGACLK),
CLK_MGT_ENTRY(UARTCLK),
CLK_MGT_ENTRY(MSP02CLK),
CLK_MGT_ENTRY(MSP1CLK),
CLK_MGT_ENTRY(I2CCLK),
CLK_MGT_ENTRY(SDMMCCLK),
CLK_MGT_ENTRY(SLIMCLK),
CLK_MGT_ENTRY(PER1CLK),
CLK_MGT_ENTRY(PER2CLK),
CLK_MGT_ENTRY(PER3CLK),
CLK_MGT_ENTRY(PER5CLK),
CLK_MGT_ENTRY(PER6CLK),
CLK_MGT_ENTRY(PER7CLK),
CLK_MGT_ENTRY(LCDCLK),
CLK_MGT_ENTRY(BMLCLK),
CLK_MGT_ENTRY(HSITXCLK),
CLK_MGT_ENTRY(HSIRXCLK),
CLK_MGT_ENTRY(HDMICLK),
CLK_MGT_ENTRY(APEATCLK),
CLK_MGT_ENTRY(APETRACECLK),
CLK_MGT_ENTRY(MCDECLK),
CLK_MGT_ENTRY(IPI2CCLK),
CLK_MGT_ENTRY(DSIALTCLK),
CLK_MGT_ENTRY(DMACLK),
CLK_MGT_ENTRY(B2R2CLK),
CLK_MGT_ENTRY(TVCLK),
CLK_MGT_ENTRY(SSPCLK),
CLK_MGT_ENTRY(RNGCLK),
CLK_MGT_ENTRY(UICCCLK),
CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
};
struct dsiclk {
u32 divsel_mask;
u32 divsel_shift;
u32 divsel;
};
static struct dsiclk dsiclk[2] = {
{
.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
},
{
.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
}
};
static struct regulator *hwacc_regulator[NUM_HW_ACC];
static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
static bool hwacc_enabled[NUM_HW_ACC];
static bool hwacc_ret_enabled[NUM_HW_ACC];
static const char *hwacc_regulator_name[NUM_HW_ACC] = {
[HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp",
[HW_ACC_SVAPIPE] = "hwacc-sva-pipe",
[HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp",
[HW_ACC_SIAPIPE] = "hwacc-sia-pipe",
[HW_ACC_SGA] = "hwacc-sga",
[HW_ACC_B2R2] = "hwacc-b2r2",
[HW_ACC_MCDE] = "hwacc-mcde",
[HW_ACC_ESRAM1] = "hwacc-esram1",
[HW_ACC_ESRAM2] = "hwacc-esram2",
[HW_ACC_ESRAM3] = "hwacc-esram3",
[HW_ACC_ESRAM4] = "hwacc-esram4",
struct dsiescclk {
u32 en;
u32 div_mask;
u32 div_shift;
};
static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
[HW_ACC_SVAMMDSP] = "hwacc-sva-mmdsp-ret",
[HW_ACC_SIAMMDSP] = "hwacc-sia-mmdsp-ret",
[HW_ACC_ESRAM1] = "hwacc-esram1-ret",
[HW_ACC_ESRAM2] = "hwacc-esram2-ret",
[HW_ACC_ESRAM3] = "hwacc-esram3-ret",
[HW_ACC_ESRAM4] = "hwacc-esram4-ret",
static struct dsiescclk dsiescclk[3] = {
{
.en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
.div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
.div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
},
{
.en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
.div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
.div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
},
{
.en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
.div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
.div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
}
};
/*
......@@ -503,9 +531,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
/* PLLDIV=12, PLLSW=4 (PLLDDR) */
#define PRCMU_DSI_CLOCK_SETTING 0x0000008C
/* PLLDIV=8, PLLSW=4 (PLLDDR) */
#define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088
/* DPI 50000000 Hz */
#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
(16 << PRCMU_CLK_PLL_DIV_SHIFT))
......@@ -514,9 +539,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
/* D=101, N=1, R=4, SELDIV2=0 */
#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165
/* D=70, N=1, R=3, SELDIV2=0 */
#define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146
#define PRCMU_ENABLE_PLLDSI 0x00000001
#define PRCMU_DISABLE_PLLDSI 0x00000000
#define PRCMU_RELEASE_RESET_DSS 0x0000400C
......@@ -528,30 +550,17 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
static struct {
u8 project_number;
u8 api_version;
u8 func_version;
u8 errata;
} prcmu_version;
int db8500_prcmu_enable_dsipll(void)
{
int i;
unsigned int plldsifreq;
/* Clear DSIPLL_RESETN */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
/* Unclamp DSIPLL in/out */
writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
if (prcmu_is_u8400())
plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
else
plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
/* Set DSI PLL FREQ */
writel(plldsifreq, PRCM_PLLDSI_FREQ);
writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
/* Enable Escape clocks */
writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
......@@ -583,12 +592,6 @@ int db8500_prcmu_disable_dsipll(void)
int db8500_prcmu_set_display_clocks(void)
{
unsigned long flags;
unsigned int dsiclk;
if (prcmu_is_u8400())
dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
else
dsiclk = PRCMU_DSI_CLOCK_SETTING;
spin_lock_irqsave(&clk_mgt_lock, flags);
......@@ -596,7 +599,7 @@ int db8500_prcmu_set_display_clocks(void)
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
writel(dsiclk, PRCM_HDMICLK_MGT);
writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
......@@ -608,43 +611,41 @@ int db8500_prcmu_set_display_clocks(void)
return 0;
}
/**
* prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
*/
void prcmu_enable_spi2(void)
u32 db8500_prcmu_read(unsigned int reg)
{
return readl(_PRCMU_BASE + reg);
}
void db8500_prcmu_write(unsigned int reg, u32 value)
{
u32 reg;
unsigned long flags;
spin_lock_irqsave(&gpiocr_lock, flags);
reg = readl(PRCM_GPIOCR);
writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
spin_unlock_irqrestore(&gpiocr_lock, flags);
spin_lock_irqsave(&prcmu_lock, flags);
writel(value, (_PRCMU_BASE + reg));
spin_unlock_irqrestore(&prcmu_lock, flags);
}
/**
* prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
*/
void prcmu_disable_spi2(void)
void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
{
u32 reg;
u32 val;
unsigned long flags;
spin_lock_irqsave(&gpiocr_lock, flags);
reg = readl(PRCM_GPIOCR);
writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
spin_unlock_irqrestore(&gpiocr_lock, flags);
spin_lock_irqsave(&prcmu_lock, flags);
val = readl(_PRCMU_BASE + reg);
val = ((val & ~mask) | (value & mask));
writel(val, (_PRCMU_BASE + reg));
spin_unlock_irqrestore(&prcmu_lock, flags);
}
bool prcmu_has_arm_maxopp(void)
struct prcmu_fw_version *prcmu_get_fw_version(void)
{
return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
return fw_info.valid ? &fw_info.version : NULL;
}
bool prcmu_is_u8400(void)
bool prcmu_has_arm_maxopp(void)
{
return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
}
/**
......@@ -787,6 +788,124 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
return 0;
}
u8 db8500_prcmu_get_power_state_result(void)
{
return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
}
/* This function decouple the gic from the prcmu */
int db8500_prcmu_gic_decouple(void)
{
u32 val = readl(PRCM_A9_MASK_REQ);
/* Set bit 0 register value to 1 */
writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
PRCM_A9_MASK_REQ);
/* Make sure the register is updated */
readl(PRCM_A9_MASK_REQ);
/* Wait a few cycles for the gic mask completion */
udelay(1);
return 0;
}
/* This function recouple the gic with the prcmu */
int db8500_prcmu_gic_recouple(void)
{
u32 val = readl(PRCM_A9_MASK_REQ);
/* Set bit 0 register value to 0 */
writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
return 0;
}
#define PRCMU_GIC_NUMBER_REGS 5
/*
* This function checks if there are pending irq on the gic. It only
* makes sense if the gic has been decoupled before with the
* db8500_prcmu_gic_decouple function. Disabling an interrupt only
* disables the forwarding of the interrupt to any CPU interface. It
* does not prevent the interrupt from changing state, for example
* becoming pending, or active and pending if it is already
* active. Hence, we have to check the interrupt is pending *and* is
* active.
*/
bool db8500_prcmu_gic_pending_irq(void)
{
u32 pr; /* Pending register */
u32 er; /* Enable register */
void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
int i;
/* 5 registers. STI & PPI not skipped */
for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
if (pr & er)
return true; /* There is a pending interrupt */
}
return false;
}
/*
* This function checks if there are pending interrupt on the
* prcmu which has been delegated to monitor the irqs with the
* db8500_prcmu_copy_gic_settings function.
*/
bool db8500_prcmu_pending_irq(void)
{
u32 it, im;
int i;
for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
it = readl(PRCM_ARMITVAL31TO0 + i * 4);
im = readl(PRCM_ARMITMSK31TO0 + i * 4);
if (it & im)
return true; /* There is a pending interrupt */
}
return false;
}
/*
* This function checks if the specified cpu is in in WFI. It's usage
* makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
* function. Of course passing smp_processor_id() to this function will
* always return false...
*/
bool db8500_prcmu_is_cpu_in_wfi(int cpu)
{
return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
PRCM_ARM_WFI_STANDBY_WFI0;
}
/*
* This function copies the gic SPI settings to the prcmu in order to
* monitor them and abort/finish the retention/off sequence or state.
*/
int db8500_prcmu_copy_gic_settings(void)
{
u32 er; /* Enable register */
void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
int i;
/* We skip the STI and PPI */
for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
er = readl_relaxed(dist_base +
GIC_DIST_ENABLE_SET + (i + 1) * 4);
writel(er, PRCM_ARMITMSK31TO0 + i * 4);
}
return 0;
}
/* This function should only be called while mb0_transfer.lock is held. */
static void config_wakeups(void)
{
......@@ -909,23 +1028,23 @@ int db8500_prcmu_get_arm_opp(void)
}
/**
* prcmu_get_ddr_opp - get the current DDR OPP
* db8500_prcmu_get_ddr_opp - get the current DDR OPP
*
* Returns: the current DDR OPP
*/
int prcmu_get_ddr_opp(void)
int db8500_prcmu_get_ddr_opp(void)
{
return readb(PRCM_DDR_SUBSYS_APE_MINBW);
}
/**
* set_ddr_opp - set the appropriate DDR OPP
* db8500_set_ddr_opp - set the appropriate DDR OPP
* @opp: The new DDR operating point to which transition is to be made
* Returns: 0 on success, non-zero on failure
*
* This function sets the operating point of the DDR.
*/
int prcmu_set_ddr_opp(u8 opp)
int db8500_prcmu_set_ddr_opp(u8 opp)
{
if (opp < DDR_100_OPP || opp > DDR_25_OPP)
return -EINVAL;
......@@ -935,25 +1054,82 @@ int prcmu_set_ddr_opp(u8 opp)
return 0;
}
/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
static void request_even_slower_clocks(bool enable)
{
void __iomem *clock_reg[] = {
PRCM_ACLK_MGT,
PRCM_DMACLK_MGT
};
unsigned long flags;
unsigned int i;
spin_lock_irqsave(&clk_mgt_lock, flags);
/* Grab the HW semaphore. */
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
u32 val;
u32 div;
val = readl(clock_reg[i]);
div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
if (enable) {
if ((div <= 1) || (div > 15)) {
pr_err("prcmu: Bad clock divider %d in %s\n",
div, __func__);
goto unlock_and_return;
}
div <<= 1;
} else {
if (div <= 2)
goto unlock_and_return;
div >>= 1;
}
val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
(div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
writel(val, clock_reg[i]);
}
unlock_and_return:
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
spin_unlock_irqrestore(&clk_mgt_lock, flags);
}
/**
* set_ape_opp - set the appropriate APE OPP
* db8500_set_ape_opp - set the appropriate APE OPP
* @opp: The new APE operating point to which transition is to be made
* Returns: 0 on success, non-zero on failure
*
* This function sets the operating point of the APE.
*/
int prcmu_set_ape_opp(u8 opp)
int db8500_prcmu_set_ape_opp(u8 opp)
{
int r = 0;
if (opp == mb1_transfer.ape_opp)
return 0;
mutex_lock(&mb1_transfer.lock);
if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
request_even_slower_clocks(false);
if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
goto skip_message;
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
(tcdm_base + PRCM_REQ_MB1_APE_OPP));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb1_transfer.work);
......@@ -962,17 +1138,24 @@ int prcmu_set_ape_opp(u8 opp)
(mb1_transfer.ack.ape_opp != opp))
r = -EIO;
skip_message:
if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
(r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
request_even_slower_clocks(true);
if (!r)
mb1_transfer.ape_opp = opp;
mutex_unlock(&mb1_transfer.lock);
return r;
}
/**
* prcmu_get_ape_opp - get the current APE OPP
* db8500_prcmu_get_ape_opp - get the current APE OPP
*
* Returns: the current APE OPP
*/
int prcmu_get_ape_opp(void)
int db8500_prcmu_get_ape_opp(void)
{
return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
}
......@@ -1056,7 +1239,9 @@ static int request_pll(u8 clock, bool enable)
{
int r = 0;
if (clock == PRCMU_PLLSOC1)
if (clock == PRCMU_PLLSOC0)
clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
else if (clock == PRCMU_PLLSOC1)
clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
else
return -EINVAL;
......@@ -1080,132 +1265,6 @@ static int request_pll(u8 clock, bool enable)
return r;
}
/**
* prcmu_set_hwacc - set the power state of a h/w accelerator
* @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
* @state: The new power state (enum hw_acc_state).
*
* This function sets the power state of a hardware accelerator.
* This function should not be called from interrupt context.
*
* NOTE! Deprecated, to be removed when all users switched over to use the
* regulator framework API.
*/
int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
{
int r = 0;
bool ram_retention = false;
bool enable, enable_ret;
/* check argument */
BUG_ON(hwacc_dev >= NUM_HW_ACC);
/* get state of switches */
enable = hwacc_enabled[hwacc_dev];
enable_ret = hwacc_ret_enabled[hwacc_dev];
/* set flag if retention is possible */
switch (hwacc_dev) {
case HW_ACC_SVAMMDSP:
case HW_ACC_SIAMMDSP:
case HW_ACC_ESRAM1:
case HW_ACC_ESRAM2:
case HW_ACC_ESRAM3:
case HW_ACC_ESRAM4:
ram_retention = true;
break;
}
/* check argument */
BUG_ON(state > HW_ON);
BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
/* modify enable flags */
switch (state) {
case HW_OFF:
enable_ret = false;
enable = false;
break;
case HW_ON:
enable = true;
break;
case HW_OFF_RAMRET:
enable_ret = true;
enable = false;
break;
}
/* get regulator (lazy) */
if (hwacc_regulator[hwacc_dev] == NULL) {
hwacc_regulator[hwacc_dev] = regulator_get(NULL,
hwacc_regulator_name[hwacc_dev]);
if (IS_ERR(hwacc_regulator[hwacc_dev])) {
pr_err("prcmu: failed to get supply %s\n",
hwacc_regulator_name[hwacc_dev]);
r = PTR_ERR(hwacc_regulator[hwacc_dev]);
goto out;
}
}
if (ram_retention) {
if (hwacc_ret_regulator[hwacc_dev] == NULL) {
hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
hwacc_ret_regulator_name[hwacc_dev]);
if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
pr_err("prcmu: failed to get supply %s\n",
hwacc_ret_regulator_name[hwacc_dev]);
r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
goto out;
}
}
}
/* set regulators */
if (ram_retention) {
if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
if (r < 0) {
pr_err("prcmu_set_hwacc: ret enable failed\n");
goto out;
}
hwacc_ret_enabled[hwacc_dev] = true;
}
}
if (enable && !hwacc_enabled[hwacc_dev]) {
r = regulator_enable(hwacc_regulator[hwacc_dev]);
if (r < 0) {
pr_err("prcmu_set_hwacc: enable failed\n");
goto out;
}
hwacc_enabled[hwacc_dev] = true;
}
if (!enable && hwacc_enabled[hwacc_dev]) {
r = regulator_disable(hwacc_regulator[hwacc_dev]);
if (r < 0) {
pr_err("prcmu_set_hwacc: disable failed\n");
goto out;
}
hwacc_enabled[hwacc_dev] = false;
}
if (ram_retention) {
if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
if (r < 0) {
pr_err("prcmu_set_hwacc: ret disable failed\n");
goto out;
}
hwacc_ret_enabled[hwacc_dev] = false;
}
}
out:
return r;
}
EXPORT_SYMBOL(prcmu_set_hwacc);
/**
* db8500_prcmu_set_epod - set the state of a EPOD (power domain)
* @epod_id: The EPOD to set
......@@ -1375,7 +1434,7 @@ static int request_timclk(bool enable)
return 0;
}
static int request_reg_clock(u8 clock, bool enable)
static int request_clock(u8 clock, bool enable)
{
u32 val;
unsigned long flags;
......@@ -1386,14 +1445,14 @@ static int request_reg_clock(u8 clock, bool enable)
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
val = readl(clk_mgt[clock].reg);
if (enable) {
val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
} else {
clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
}
writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
writel(val, clk_mgt[clock].reg);
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
......@@ -1413,7 +1472,7 @@ static int request_sga_clock(u8 clock, bool enable)
writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
}
ret = request_reg_clock(clock, enable);
ret = request_clock(clock, enable);
if (!ret && !enable) {
val = readl(PRCM_CGATING_BYPASS);
......@@ -1423,6 +1482,78 @@ static int request_sga_clock(u8 clock, bool enable)
return ret;
}
static inline bool plldsi_locked(void)
{
return (readl(PRCM_PLLDSI_LOCKP) &
(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
}
static int request_plldsi(bool enable)
{
int r = 0;
u32 val;
writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
val = readl(PRCM_PLLDSI_ENABLE);
if (enable)
val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
else
val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
writel(val, PRCM_PLLDSI_ENABLE);
if (enable) {
unsigned int i;
bool locked = plldsi_locked();
for (i = 10; !locked && (i > 0); --i) {
udelay(100);
locked = plldsi_locked();
}
if (locked) {
writel(PRCM_APE_RESETN_DSIPLL_RESETN,
PRCM_APE_RESETN_SET);
} else {
writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
PRCM_MMIP_LS_CLAMP_SET);
val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
writel(val, PRCM_PLLDSI_ENABLE);
r = -EAGAIN;
}
} else {
writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
}
return r;
}
static int request_dsiclk(u8 n, bool enable)
{
u32 val;
val = readl(PRCM_DSI_PLLOUT_SEL);
val &= ~dsiclk[n].divsel_mask;
val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
dsiclk[n].divsel_shift);
writel(val, PRCM_DSI_PLLOUT_SEL);
return 0;
}
static int request_dsiescclk(u8 n, bool enable)
{
u32 val;
val = readl(PRCM_DSITVCLK_DIV);
enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
writel(val, PRCM_DSITVCLK_DIV);
return 0;
}
/**
* db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
* @clock: The clock for which the request is made.
......@@ -1433,21 +1564,435 @@ static int request_sga_clock(u8 clock, bool enable)
*/
int db8500_prcmu_request_clock(u8 clock, bool enable)
{
switch(clock) {
case PRCMU_SGACLK:
if (clock == PRCMU_SGACLK)
return request_sga_clock(clock, enable);
case PRCMU_TIMCLK:
else if (clock < PRCMU_NUM_REG_CLOCKS)
return request_clock(clock, enable);
else if (clock == PRCMU_TIMCLK)
return request_timclk(enable);
case PRCMU_SYSCLK:
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
else if (clock == PRCMU_PLLDSI)
return request_plldsi(enable);
else if (clock == PRCMU_SYSCLK)
return request_sysclk(enable);
case PRCMU_PLLSOC1:
else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
return request_pll(clock, enable);
else
return -EINVAL;
}
static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
int branch)
{
u64 rate;
u32 val;
u32 d;
u32 div = 1;
val = readl(reg);
rate = src_rate;
rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
if (d > 1)
div *= d;
d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
if (d > 1)
div *= d;
if (val & PRCM_PLL_FREQ_SELDIV2)
div *= 2;
if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
(val & PRCM_PLL_FREQ_DIV2EN) &&
((reg == PRCM_PLLSOC0_FREQ) ||
(reg == PRCM_PLLDDR_FREQ))))
div *= 2;
(void)do_div(rate, div);
return (unsigned long)rate;
}
#define ROOT_CLOCK_RATE 38400000
static unsigned long clock_rate(u8 clock)
{
u32 val;
u32 pllsw;
unsigned long rate = ROOT_CLOCK_RATE;
val = readl(clk_mgt[clock].reg);
if (val & PRCM_CLK_MGT_CLK38) {
if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
rate /= 2;
return rate;
}
val |= clk_mgt[clock].pllsw;
pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
else
return 0;
if ((clock == PRCMU_SGACLK) &&
(val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
u64 r = (rate * 10);
(void)do_div(r, 25);
return (unsigned long)r;
}
val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
if (val)
return rate / val;
else
return 0;
}
static unsigned long dsiclk_rate(u8 n)
{
u32 divsel;
u32 div = 1;
divsel = readl(PRCM_DSI_PLLOUT_SEL);
divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
divsel = dsiclk[n].divsel;
switch (divsel) {
case PRCM_DSI_PLLOUT_SEL_PHI_4:
div *= 2;
case PRCM_DSI_PLLOUT_SEL_PHI_2:
div *= 2;
case PRCM_DSI_PLLOUT_SEL_PHI:
return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
PLL_RAW) / div;
default:
break;
return 0;
}
}
static unsigned long dsiescclk_rate(u8 n)
{
u32 div;
div = readl(PRCM_DSITVCLK_DIV);
div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
}
unsigned long prcmu_clock_rate(u8 clock)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
return clock_rate(clock);
else if (clock == PRCMU_TIMCLK)
return ROOT_CLOCK_RATE / 16;
else if (clock == PRCMU_SYSCLK)
return ROOT_CLOCK_RATE;
else if (clock == PRCMU_PLLSOC0)
return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
else if (clock == PRCMU_PLLSOC1)
return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
else if (clock == PRCMU_PLLDDR)
return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
else if (clock == PRCMU_PLLDSI)
return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
PLL_RAW);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
return dsiclk_rate(clock - PRCMU_DSI0CLK);
else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
else
return 0;
}
static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
{
if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
return ROOT_CLOCK_RATE;
clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
else
return 0;
}
static u32 clock_divider(unsigned long src_rate, unsigned long rate)
{
u32 div;
div = (src_rate / rate);
if (div == 0)
return 1;
if (rate < (src_rate / div))
div++;
return div;
}
static long round_clock_rate(u8 clock, unsigned long rate)
{
u32 val;
u32 div;
unsigned long src_rate;
long rounded_rate;
val = readl(clk_mgt[clock].reg);
src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
clk_mgt[clock].branch);
div = clock_divider(src_rate, rate);
if (val & PRCM_CLK_MGT_CLK38) {
if (clk_mgt[clock].clk38div) {
if (div > 2)
div = 2;
} else {
div = 1;
}
} else if ((clock == PRCMU_SGACLK) && (div == 3)) {
u64 r = (src_rate * 10);
(void)do_div(r, 25);
if (r <= rate)
return (unsigned long)r;
}
rounded_rate = (src_rate / min(div, (u32)31));
return rounded_rate;
}
#define MIN_PLL_VCO_RATE 600000000ULL
#define MAX_PLL_VCO_RATE 1680640000ULL
static long round_plldsi_rate(unsigned long rate)
{
long rounded_rate = 0;
unsigned long src_rate;
unsigned long rem;
u32 r;
src_rate = clock_rate(PRCMU_HDMICLK);
rem = rate;
for (r = 7; (rem > 0) && (r > 0); r--) {
u64 d;
d = (r * rate);
(void)do_div(d, src_rate);
if (d < 6)
d = 6;
else if (d > 255)
d = 255;
d *= src_rate;
if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
((r * MAX_PLL_VCO_RATE) < (2 * d)))
continue;
(void)do_div(d, r);
if (rate < d) {
if (rounded_rate == 0)
rounded_rate = (long)d;
break;
}
if ((rate - d) < rem) {
rem = (rate - d);
rounded_rate = (long)d;
}
}
return rounded_rate;
}
static long round_dsiclk_rate(unsigned long rate)
{
u32 div;
unsigned long src_rate;
long rounded_rate;
src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
PLL_RAW);
div = clock_divider(src_rate, rate);
rounded_rate = (src_rate / ((div > 2) ? 4 : div));
return rounded_rate;
}
static long round_dsiescclk_rate(unsigned long rate)
{
u32 div;
unsigned long src_rate;
long rounded_rate;
src_rate = clock_rate(PRCMU_TVCLK);
div = clock_divider(src_rate, rate);
rounded_rate = (src_rate / min(div, (u32)255));
return rounded_rate;
}
long prcmu_round_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
return round_clock_rate(clock, rate);
else if (clock == PRCMU_PLLDSI)
return round_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
return round_dsiclk_rate(rate);
else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
return round_dsiescclk_rate(rate);
else
return (long)prcmu_clock_rate(clock);
}
static void set_clock_rate(u8 clock, unsigned long rate)
{
u32 val;
u32 div;
unsigned long src_rate;
unsigned long flags;
spin_lock_irqsave(&clk_mgt_lock, flags);
/* Grab the HW semaphore. */
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
val = readl(clk_mgt[clock].reg);
src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
clk_mgt[clock].branch);
div = clock_divider(src_rate, rate);
if (val & PRCM_CLK_MGT_CLK38) {
if (clk_mgt[clock].clk38div) {
if (div > 1)
val |= PRCM_CLK_MGT_CLK38DIV;
else
val &= ~PRCM_CLK_MGT_CLK38DIV;
}
} else if (clock == PRCMU_SGACLK) {
val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
if (div == 3) {
u64 r = (src_rate * 10);
(void)do_div(r, 25);
if (r <= rate) {
val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
div = 0;
}
}
val |= min(div, (u32)31);
} else {
val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
val |= min(div, (u32)31);
}
writel(val, clk_mgt[clock].reg);
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
spin_unlock_irqrestore(&clk_mgt_lock, flags);
}
static int set_plldsi_rate(unsigned long rate)
{
unsigned long src_rate;
unsigned long rem;
u32 pll_freq = 0;
u32 r;
src_rate = clock_rate(PRCMU_HDMICLK);
rem = rate;
for (r = 7; (rem > 0) && (r > 0); r--) {
u64 d;
u64 hwrate;
d = (r * rate);
(void)do_div(d, src_rate);
if (d < 6)
d = 6;
else if (d > 255)
d = 255;
hwrate = (d * src_rate);
if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
continue;
(void)do_div(hwrate, r);
if (rate < hwrate) {
if (pll_freq == 0)
pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
(r << PRCM_PLL_FREQ_R_SHIFT));
break;
}
if ((rate - hwrate) < rem) {
rem = (rate - hwrate);
pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
(r << PRCM_PLL_FREQ_R_SHIFT));
}
}
if (pll_freq == 0)
return -EINVAL;
pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
writel(pll_freq, PRCM_PLLDSI_FREQ);
return 0;
}
static void set_dsiclk_rate(u8 n, unsigned long rate)
{
u32 val;
u32 div;
div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
(div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
/* else */ PRCM_DSI_PLLOUT_SEL_PHI_4;
val = readl(PRCM_DSI_PLLOUT_SEL);
val &= ~dsiclk[n].divsel_mask;
val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
writel(val, PRCM_DSI_PLLOUT_SEL);
}
static void set_dsiescclk_rate(u8 n, unsigned long rate)
{
u32 val;
u32 div;
div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
val = readl(PRCM_DSITVCLK_DIV);
val &= ~dsiescclk[n].div_mask;
val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
writel(val, PRCM_DSITVCLK_DIV);
}
int prcmu_set_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
return request_reg_clock(clock, enable);
return -EINVAL;
set_clock_rate(clock, rate);
else if (clock == PRCMU_PLLDSI)
return set_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
return 0;
}
int db8500_prcmu_config_esram0_deep_sleep(u8 state)
......@@ -1476,7 +2021,7 @@ int db8500_prcmu_config_esram0_deep_sleep(u8 state)
return 0;
}
int prcmu_config_hotdog(u8 threshold)
int db8500_prcmu_config_hotdog(u8 threshold)
{
mutex_lock(&mb4_transfer.lock);
......@@ -1494,7 +2039,7 @@ int prcmu_config_hotdog(u8 threshold)
return 0;
}
int prcmu_config_hotmon(u8 low, u8 high)
int db8500_prcmu_config_hotmon(u8 low, u8 high)
{
mutex_lock(&mb4_transfer.lock);
......@@ -1533,7 +2078,7 @@ static int config_hot_period(u16 val)
return 0;
}
int prcmu_start_temp_sense(u16 cycles32k)
int db8500_prcmu_start_temp_sense(u16 cycles32k)
{
if (cycles32k == 0xFFFF)
return -EINVAL;
......@@ -1541,7 +2086,7 @@ int prcmu_start_temp_sense(u16 cycles32k)
return config_hot_period(cycles32k);
}
int prcmu_stop_temp_sense(void)
int db8500_prcmu_stop_temp_sense(void)
{
return config_hot_period(0xFFFF);
}
......@@ -1570,7 +2115,7 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
}
int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
BUG_ON(num == 0 || num > 0xf);
return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
......@@ -1578,17 +2123,17 @@ int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
A9WDOG_AUTO_OFF_DIS);
}
int prcmu_enable_a9wdog(u8 id)
int db8500_prcmu_enable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
}
int prcmu_disable_a9wdog(u8 id)
int db8500_prcmu_disable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
}
int prcmu_kick_a9wdog(u8 id)
int db8500_prcmu_kick_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
}
......@@ -1596,16 +2141,8 @@ int prcmu_kick_a9wdog(u8 id)
/*
* timeout is 28 bit, in ms.
*/
#define MAX_WATCHDOG_TIMEOUT 131000
int prcmu_load_a9wdog(u8 id, u32 timeout)
int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
{
if (timeout > MAX_WATCHDOG_TIMEOUT)
/*
* Due to calculation bug in prcmu fw, timeouts
* can't be bigger than 131 seconds.
*/
return -EINVAL;
return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
(id & A9WDOG_ID_MASK) |
/*
......@@ -1618,41 +2155,6 @@ int prcmu_load_a9wdog(u8 id, u32 timeout)
(u8)((timeout >> 20) & 0xff));
}
/**
* prcmu_set_clock_divider() - Configure the clock divider.
* @clock: The clock for which the request is made.
* @divider: The clock divider. (< 32)
*
* This function should only be used by the clock implementation.
* Do not use it from any other place!
*/
int prcmu_set_clock_divider(u8 clock, u8 divider)
{
u32 val;
unsigned long flags;
if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
return -EINVAL;
spin_lock_irqsave(&clk_mgt_lock, flags);
/* Grab the HW semaphore. */
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
val |= (u32)divider;
writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
spin_unlock_irqrestore(&clk_mgt_lock, flags);
return 0;
}
/**
* prcmu_abb_read() - Read register value(s) from the ABB.
* @slave: The I2C slave address.
......@@ -1675,6 +2177,7 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
......@@ -1700,16 +2203,19 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
}
/**
* prcmu_abb_write() - Write register value(s) to the ABB.
* prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The value(s) to write.
* @mask: The mask(s) to use.
* @size: The number of registers to write.
*
* Reads register value(s) from the ABB.
* Writes masked register value(s) to the ABB.
* For each @value, only the bits set to 1 in the corresponding @mask
* will be written. The other bits are not changed.
* @size has to be 1 for the current firmware version.
*/
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
{
int r;
......@@ -1721,6 +2227,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
......@@ -1742,6 +2249,23 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
return r;
}
/**
* prcmu_abb_write() - Write register value(s) to the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The value(s) to write.
* @size: The number of registers to write.
*
* Writes register value(s) to the ABB.
* @size has to be 1 for the current firmware version.
*/
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
u8 mask = ~0;
return prcmu_abb_write_masked(slave, reg, value, &mask, size);
}
/**
* prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
*/
......@@ -1850,9 +2374,9 @@ u16 db8500_prcmu_get_reset_code(void)
}
/**
* prcmu_reset_modem - ask the PRCMU to reset modem
* db8500_prcmu_reset_modem - ask the PRCMU to reset modem
*/
void prcmu_modem_reset(void)
void db8500_prcmu_modem_reset(void)
{
mutex_lock(&mb1_transfer.lock);
......@@ -2099,6 +2623,26 @@ static struct irq_chip prcmu_irq_chip = {
.irq_unmask = prcmu_irq_unmask,
};
static char *fw_project_name(u8 project)
{
switch (project) {
case PRCMU_FW_PROJECT_U8500:
return "U8500";
case PRCMU_FW_PROJECT_U8500_C2:
return "U8500 C2";
case PRCMU_FW_PROJECT_U9500:
return "U9500";
case PRCMU_FW_PROJECT_U9500_C2:
return "U9500 C2";
case PRCMU_FW_PROJECT_U8520:
return "U8520";
case PRCMU_FW_PROJECT_U8420:
return "U8420";
default:
return "Unknown";
}
}
void __init db8500_prcmu_early_init(void)
{
unsigned int i;
......@@ -2108,11 +2652,13 @@ void __init db8500_prcmu_early_init(void)
if (tcpm_base != NULL) {
u32 version;
version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
prcmu_version.project_number = version & 0xFF;
prcmu_version.api_version = (version >> 8) & 0xFF;
prcmu_version.func_version = (version >> 16) & 0xFF;
prcmu_version.errata = (version >> 24) & 0xFF;
pr_info("PRCMU firmware version %d.%d.%d\n",
fw_info.version.project = version & 0xFF;
fw_info.version.api_version = (version >> 8) & 0xFF;
fw_info.version.func_version = (version >> 16) & 0xFF;
fw_info.version.errata = (version >> 24) & 0xFF;
fw_info.valid = true;
pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
fw_project_name(fw_info.version.project),
(version >> 8) & 0xFF, (version >> 16) & 0xFF,
(version >> 24) & 0xFF);
iounmap(tcpm_base);
......@@ -2130,6 +2676,7 @@ void __init db8500_prcmu_early_init(void)
init_completion(&mb0_transfer.ac_wake_work);
mutex_init(&mb1_transfer.lock);
init_completion(&mb1_transfer.work);
mb1_transfer.ape_opp = APE_NO_CHANGE;
mutex_init(&mb2_transfer.lock);
init_completion(&mb2_transfer.work);
spin_lock_init(&mb2_transfer.auto_pm_lock);
......@@ -2154,7 +2701,7 @@ void __init db8500_prcmu_early_init(void)
}
}
static void __init db8500_prcmu_init_clkforce(void)
static void __init init_prcm_registers(void)
{
u32 val;
......@@ -2186,19 +2733,17 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
REGULATOR_SUPPLY("vcore", "uart1"),
REGULATOR_SUPPLY("vcore", "uart2"),
REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
};
static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
/* CG2900 and CW1200 power to off-chip peripherals */
REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
/* AV8100 regulator */
REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
};
static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
REGULATOR_SUPPLY("vsupply", "b2r2.0"),
REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
REGULATOR_SUPPLY("vsupply", "mcde"),
};
......@@ -2235,6 +2780,7 @@ static struct regulator_consumer_supply db8500_esram12_consumers[] = {
static struct regulator_consumer_supply db8500_esram34_consumers[] = {
REGULATOR_SUPPLY("v-esram34", "mcde"),
REGULATOR_SUPPLY("esram34", "cm_control"),
REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
};
static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
......@@ -2291,7 +2837,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
.supply_regulator = "db8500-vape",
/* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sva-mmdsp",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2307,7 +2853,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
.supply_regulator = "db8500-vape",
/* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sva-pipe",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2316,7 +2862,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
},
[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
.supply_regulator = "db8500-vape",
/* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sia-mmdsp",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2331,7 +2877,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
.supply_regulator = "db8500-vape",
/* dependency to u8500-vape is handled outside regulator framework */
.constraints = {
.name = "db8500-sia-pipe",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2359,7 +2905,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
},
[DB8500_REGULATOR_SWITCH_ESRAM12] = {
.supply_regulator = "db8500-vape",
/*
* esram12 is set in retention and supplied by Vsafe when Vape is off,
* no need to hold Vape
*/
.constraints = {
.name = "db8500-esram12",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2374,7 +2923,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
},
},
[DB8500_REGULATOR_SWITCH_ESRAM34] = {
.supply_regulator = "db8500-vape",
/*
* esram34 is set in retention and supplied by Vsafe when Vape is off,
* no need to hold Vape
*/
.constraints = {
.name = "db8500-esram34",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
......@@ -2412,7 +2964,7 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
if (ux500_is_svp())
return -ENODEV;
db8500_prcmu_init_clkforce();
init_prcm_registers();
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
......
......@@ -17,41 +17,41 @@
#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
#define PRCM_SVACLK_MGT_OFF 0x008
#define PRCM_SIACLK_MGT_OFF 0x00C
#define PRCM_SGACLK_MGT_OFF 0x014
#define PRCM_UARTCLK_MGT_OFF 0x018
#define PRCM_MSP02CLK_MGT_OFF 0x01C
#define PRCM_I2CCLK_MGT_OFF 0x020
#define PRCM_SDMMCCLK_MGT_OFF 0x024
#define PRCM_SLIMCLK_MGT_OFF 0x028
#define PRCM_PER1CLK_MGT_OFF 0x02C
#define PRCM_PER2CLK_MGT_OFF 0x030
#define PRCM_PER3CLK_MGT_OFF 0x034
#define PRCM_PER5CLK_MGT_OFF 0x038
#define PRCM_PER6CLK_MGT_OFF 0x03C
#define PRCM_PER7CLK_MGT_OFF 0x040
#define PRCM_PWMCLK_MGT_OFF 0x044 /* for DB5500 */
#define PRCM_IRDACLK_MGT_OFF 0x048 /* for DB5500 */
#define PRCM_IRRCCLK_MGT_OFF 0x04C /* for DB5500 */
#define PRCM_LCDCLK_MGT_OFF 0x044
#define PRCM_BMLCLK_MGT_OFF 0x04C
#define PRCM_HSITXCLK_MGT_OFF 0x050
#define PRCM_HSIRXCLK_MGT_OFF 0x054
#define PRCM_HDMICLK_MGT_OFF 0x058
#define PRCM_APEATCLK_MGT_OFF 0x05C
#define PRCM_APETRACECLK_MGT_OFF 0x060
#define PRCM_MCDECLK_MGT_OFF 0x064
#define PRCM_IPI2CCLK_MGT_OFF 0x068
#define PRCM_DSIALTCLK_MGT_OFF 0x06C
#define PRCM_DMACLK_MGT_OFF 0x074
#define PRCM_B2R2CLK_MGT_OFF 0x078
#define PRCM_TVCLK_MGT_OFF 0x07C
#define PRCM_UNIPROCLK_MGT_OFF 0x278
#define PRCM_SSPCLK_MGT_OFF 0x280
#define PRCM_RNGCLK_MGT_OFF 0x284
#define PRCM_UICCCLK_MGT_OFF 0x27C
#define PRCM_MSP1CLK_MGT_OFF 0x288
#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+ _offset)
#define PRCM_ACLK_MGT PRCM_CLK_MGT(0x004)
#define PRCM_SVACLK_MGT PRCM_CLK_MGT(0x008)
#define PRCM_SIACLK_MGT PRCM_CLK_MGT(0x00C)
#define PRCM_SGACLK_MGT PRCM_CLK_MGT(0x014)
#define PRCM_UARTCLK_MGT PRCM_CLK_MGT(0x018)
#define PRCM_MSP02CLK_MGT PRCM_CLK_MGT(0x01C)
#define PRCM_I2CCLK_MGT PRCM_CLK_MGT(0x020)
#define PRCM_SDMMCCLK_MGT PRCM_CLK_MGT(0x024)
#define PRCM_SLIMCLK_MGT PRCM_CLK_MGT(0x028)
#define PRCM_PER1CLK_MGT PRCM_CLK_MGT(0x02C)
#define PRCM_PER2CLK_MGT PRCM_CLK_MGT(0x030)
#define PRCM_PER3CLK_MGT PRCM_CLK_MGT(0x034)
#define PRCM_PER5CLK_MGT PRCM_CLK_MGT(0x038)
#define PRCM_PER6CLK_MGT PRCM_CLK_MGT(0x03C)
#define PRCM_PER7CLK_MGT PRCM_CLK_MGT(0x040)
#define PRCM_LCDCLK_MGT PRCM_CLK_MGT(0x044)
#define PRCM_BMLCLK_MGT PRCM_CLK_MGT(0x04C)
#define PRCM_HSITXCLK_MGT PRCM_CLK_MGT(0x050)
#define PRCM_HSIRXCLK_MGT PRCM_CLK_MGT(0x054)
#define PRCM_HDMICLK_MGT PRCM_CLK_MGT(0x058)
#define PRCM_APEATCLK_MGT PRCM_CLK_MGT(0x05C)
#define PRCM_APETRACECLK_MGT PRCM_CLK_MGT(0x060)
#define PRCM_MCDECLK_MGT PRCM_CLK_MGT(0x064)
#define PRCM_IPI2CCLK_MGT PRCM_CLK_MGT(0x068)
#define PRCM_DSIALTCLK_MGT PRCM_CLK_MGT(0x06C)
#define PRCM_DMACLK_MGT PRCM_CLK_MGT(0x074)
#define PRCM_B2R2CLK_MGT PRCM_CLK_MGT(0x078)
#define PRCM_TVCLK_MGT PRCM_CLK_MGT(0x07C)
#define PRCM_UNIPROCLK_MGT PRCM_CLK_MGT(0x278)
#define PRCM_SSPCLK_MGT PRCM_CLK_MGT(0x280)
#define PRCM_RNGCLK_MGT PRCM_CLK_MGT(0x284)
#define PRCM_UICCCLK_MGT PRCM_CLK_MGT(0x27C)
#define PRCM_MSP1CLK_MGT PRCM_CLK_MGT(0x288)
#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE 0x3f
......@@ -79,6 +79,8 @@
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
#define PRCM_ARM_WFI_STANDBY_WFI0 0x08
#define PRCM_ARM_WFI_STANDBY_WFI1 0x10
#define PRCM_IOCR (_PRCMU_BASE + 0x310)
#define PRCM_IOCR_IOFORCE 0x1
......@@ -131,20 +133,58 @@
#define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420)
#define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424)
#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP BIT(11)
#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI BIT(22)
/* PRCMU clock/PLL/reset registers */
#define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080)
#define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084)
#define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C)
#define PRCM_PLL_FREQ_D_SHIFT 0
#define PRCM_PLL_FREQ_D_MASK BITS(0, 7)
#define PRCM_PLL_FREQ_N_SHIFT 8
#define PRCM_PLL_FREQ_N_MASK BITS(8, 13)
#define PRCM_PLL_FREQ_R_SHIFT 16
#define PRCM_PLL_FREQ_R_MASK BITS(16, 18)
#define PRCM_PLL_FREQ_SELDIV2 BIT(24)
#define PRCM_PLL_FREQ_DIV2EN BIT(25)
#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_LCDCLK_MGT (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
#define PRCM_MCDECLK_MGT (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
#define PRCM_HDMICLK_MGT (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
#define PRCM_TVCLK_MGT (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 BIT(0)
#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3 BIT(1)
#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT 0
#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK BITS(0, 2)
#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT 8
#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK BITS(8, 10)
#define PRCM_DSI_PLLOUT_SEL_OFF 0
#define PRCM_DSI_PLLOUT_SEL_PHI 1
#define PRCM_DSI_PLLOUT_SEL_PHI_2 2
#define PRCM_DSI_PLLOUT_SEL_PHI_4 3
#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT 0
#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK BITS(0, 7)
#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT 8
#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK BITS(8, 15)
#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT 16
#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK BITS(16, 23)
#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN BIT(24)
#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN BIT(25)
#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN BIT(26)
#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
#define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC)
#define PRCM_CLKOCR_CLKOUT0_REF_CLK (1 << 0)
#define PRCM_CLKOCR_CLKOUT0_MASK BITS(0, 13)
......@@ -183,9 +223,15 @@
#define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24)
#define PRCM_CLKOCR_CLK1TYPE BIT(28)
#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
#define PRCM_CLK_MGT_CLKEN BIT(8)
#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
#define PRCM_CLK_MGT_CLKPLLSW_SOC0 BIT(5)
#define PRCM_CLK_MGT_CLKPLLSW_SOC1 BIT(6)
#define PRCM_CLK_MGT_CLKPLLSW_DDR BIT(7)
#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
#define PRCM_CLK_MGT_CLKEN BIT(8)
#define PRCM_CLK_MGT_CLK38 BIT(9)
#define PRCM_CLK_MGT_CLK38DIV BIT(11)
#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN BIT(12)
/* GPIOCR register */
#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
......
......@@ -560,6 +560,8 @@ EXPORT_SYMBOL(mc13xxx_get_flags);
#define MC13XXX_ADC1_CHAN0_SHIFT 5
#define MC13XXX_ADC1_CHAN1_SHIFT 8
#define MC13783_ADC1_ATO_SHIFT 11
#define MC13783_ADC1_ATOX (1 << 19)
struct mc13xxx_adcdone_data {
struct mc13xxx *mc13xxx;
......@@ -580,7 +582,8 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
#define MC13XXX_ADC_WORKING (1 << 0)
int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
unsigned int channel, unsigned int *sample)
unsigned int channel, u8 ato, bool atox,
unsigned int *sample)
{
u32 adc0, adc1, old_adc0;
int i, ret;
......@@ -631,6 +634,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
return -EINVAL;
}
adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
if (atox)
adc1 |= MC13783_ADC1_ATOX;
dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
mc13xxx_handler_adcdone, __func__, &adcdone_data);
......@@ -813,7 +819,8 @@ static int mc13xxx_probe(struct spi_device *spi)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
&pdata->touch, sizeof(pdata->touch));
if (pdata) {
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
......
......@@ -162,7 +162,7 @@ int mfd_add_devices(struct device *parent, int id,
atomic_t *cnts;
/* initialize reference counting for all cells */
cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
if (!cnts)
return -ENOMEM;
......
......@@ -170,7 +170,7 @@ struct usbhs_hcd_omap {
/*-------------------------------------------------------------------------*/
const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
static u64 usbhs_dmamask = ~(u32)0;
static u64 usbhs_dmamask = DMA_BIT_MASK(32);
/*-------------------------------------------------------------------------*/
......@@ -223,7 +223,7 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
}
child->dev.dma_mask = &usbhs_dmamask;
child->dev.coherent_dma_mask = 0xffffffff;
dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
child->dev.parent = dev;
ret = platform_device_add(child);
......@@ -799,14 +799,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, omap);
omap_usbhs_init(dev);
ret = omap_usbhs_alloc_children(pdev);
if (ret) {
dev_err(dev, "omap_usbhs_alloc_children failed\n");
goto err_alloc;
}
omap_usbhs_init(dev);
goto end_probe;
err_alloc:
......
......@@ -46,13 +46,7 @@ EXPORT_SYMBOL_GPL(pcf50633_read_block);
int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
int nr_regs, u8 *data)
{
int ret;
ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
if (ret != 0)
return ret;
return nr_regs;
return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
}
EXPORT_SYMBOL_GPL(pcf50633_write_block);
......
......@@ -19,32 +19,7 @@
#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/gpio.h>
enum pcf50633_regulator_id {
PCF50633_REGULATOR_AUTO,
PCF50633_REGULATOR_DOWN1,
PCF50633_REGULATOR_DOWN2,
PCF50633_REGULATOR_LDO1,
PCF50633_REGULATOR_LDO2,
PCF50633_REGULATOR_LDO3,
PCF50633_REGULATOR_LDO4,
PCF50633_REGULATOR_LDO5,
PCF50633_REGULATOR_LDO6,
PCF50633_REGULATOR_HCLDO,
PCF50633_REGULATOR_MEMLDO,
};
#define PCF50633_REG_AUTOOUT 0x1a
#define PCF50633_REG_DOWN1OUT 0x1e
#define PCF50633_REG_DOWN2OUT 0x22
#define PCF50633_REG_MEMLDOOUT 0x26
#define PCF50633_REG_LDO1OUT 0x2d
#define PCF50633_REG_LDO2OUT 0x2f
#define PCF50633_REG_LDO3OUT 0x31
#define PCF50633_REG_LDO4OUT 0x33
#define PCF50633_REG_LDO5OUT 0x35
#define PCF50633_REG_LDO6OUT 0x37
#define PCF50633_REG_HCLDOOUT 0x39
#include <linux/mfd/pcf50633/pmic.h>
static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
[PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
......
......@@ -19,12 +19,7 @@
#include <linux/slab.h>
#include <linux/mfd/pcf50633/core.h>
/* Two MBCS registers used during cold start */
#define PCF50633_REG_MBCS1 0x4b
#define PCF50633_REG_MBCS2 0x4c
#define PCF50633_MBCS1_USBPRES 0x01
#define PCF50633_MBCS1_ADAPTPRES 0x01
#include <linux/mfd/pcf50633/mbc.h>
int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
void (*handler) (int, void *), void *data)
......
/*
* Interrupt driver for RICOH583 power management chip.
*
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
* Author: Laxman dewangan <ldewangan@nvidia.com>
*
* based on code
* Copyright (C) 2011 RICOH COMPANY,LTD
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mfd/rc5t583.h>
enum int_type {
SYS_INT = 0x1,
DCDC_INT = 0x2,
RTC_INT = 0x4,
ADC_INT = 0x8,
GPIO_INT = 0x10,
};
static int gpedge_add[] = {
RC5T583_GPIO_GPEDGE2,
RC5T583_GPIO_GPEDGE2
};
static int irq_en_add[] = {
RC5T583_INT_EN_SYS1,
RC5T583_INT_EN_SYS2,
RC5T583_INT_EN_DCDC,
RC5T583_INT_EN_RTC,
RC5T583_INT_EN_ADC1,
RC5T583_INT_EN_ADC2,
RC5T583_INT_EN_ADC3,
RC5T583_GPIO_EN_INT
};
static int irq_mon_add[] = {
RC5T583_INT_MON_SYS1,
RC5T583_INT_MON_SYS2,
RC5T583_INT_MON_DCDC,
RC5T583_INT_MON_RTC,
RC5T583_INT_IR_ADCL,
RC5T583_INT_IR_ADCH,
RC5T583_INT_IR_ADCEND,
RC5T583_INT_IR_GPIOF,
RC5T583_INT_IR_GPIOR
};
static int irq_clr_add[] = {
RC5T583_INT_IR_SYS1,
RC5T583_INT_IR_SYS2,
RC5T583_INT_IR_DCDC,
RC5T583_INT_IR_RTC,
RC5T583_INT_IR_ADCL,
RC5T583_INT_IR_ADCH,
RC5T583_INT_IR_ADCEND,
RC5T583_INT_IR_GPIOF,
RC5T583_INT_IR_GPIOR
};
static int main_int_type[] = {
SYS_INT,
SYS_INT,
DCDC_INT,
RTC_INT,
ADC_INT,
ADC_INT,
ADC_INT,
GPIO_INT,
GPIO_INT,
};
struct rc5t583_irq_data {
u8 int_type;
u8 master_bit;
u8 int_en_bit;
u8 mask_reg_index;
int grp_index;
};
#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
_int_bit, _mask_ind) \
{ \
.int_type = _int_type, \
.master_bit = _master_bit, \
.grp_index = _grp_index, \
.int_en_bit = _int_bit, \
.mask_reg_index = _mask_ind, \
}
static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
[RC5T583_IRQ_ONKEY] = RC5T583_IRQ(SYS_INT, 0, 0, 0, 0),
[RC5T583_IRQ_ACOK] = RC5T583_IRQ(SYS_INT, 0, 1, 1, 0),
[RC5T583_IRQ_LIDOPEN] = RC5T583_IRQ(SYS_INT, 0, 2, 2, 0),
[RC5T583_IRQ_PREOT] = RC5T583_IRQ(SYS_INT, 0, 3, 3, 0),
[RC5T583_IRQ_CLKSTP] = RC5T583_IRQ(SYS_INT, 0, 4, 4, 0),
[RC5T583_IRQ_ONKEY_OFF] = RC5T583_IRQ(SYS_INT, 0, 5, 5, 0),
[RC5T583_IRQ_WD] = RC5T583_IRQ(SYS_INT, 0, 7, 7, 0),
[RC5T583_IRQ_EN_PWRREQ1] = RC5T583_IRQ(SYS_INT, 0, 8, 0, 1),
[RC5T583_IRQ_EN_PWRREQ2] = RC5T583_IRQ(SYS_INT, 0, 9, 1, 1),
[RC5T583_IRQ_PRE_VINDET] = RC5T583_IRQ(SYS_INT, 0, 10, 2, 1),
[RC5T583_IRQ_DC0LIM] = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
[RC5T583_IRQ_DC1LIM] = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
[RC5T583_IRQ_DC2LIM] = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
[RC5T583_IRQ_DC3LIM] = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
[RC5T583_IRQ_CTC] = RC5T583_IRQ(RTC_INT, 2, 0, 0, 3),
[RC5T583_IRQ_YALE] = RC5T583_IRQ(RTC_INT, 2, 5, 5, 3),
[RC5T583_IRQ_DALE] = RC5T583_IRQ(RTC_INT, 2, 6, 6, 3),
[RC5T583_IRQ_WALE] = RC5T583_IRQ(RTC_INT, 2, 7, 7, 3),
[RC5T583_IRQ_AIN1L] = RC5T583_IRQ(ADC_INT, 3, 0, 0, 4),
[RC5T583_IRQ_AIN2L] = RC5T583_IRQ(ADC_INT, 3, 1, 1, 4),
[RC5T583_IRQ_AIN3L] = RC5T583_IRQ(ADC_INT, 3, 2, 2, 4),
[RC5T583_IRQ_VBATL] = RC5T583_IRQ(ADC_INT, 3, 3, 3, 4),
[RC5T583_IRQ_VIN3L] = RC5T583_IRQ(ADC_INT, 3, 4, 4, 4),
[RC5T583_IRQ_VIN8L] = RC5T583_IRQ(ADC_INT, 3, 5, 5, 4),
[RC5T583_IRQ_AIN1H] = RC5T583_IRQ(ADC_INT, 3, 6, 0, 5),
[RC5T583_IRQ_AIN2H] = RC5T583_IRQ(ADC_INT, 3, 7, 1, 5),
[RC5T583_IRQ_AIN3H] = RC5T583_IRQ(ADC_INT, 3, 8, 2, 5),
[RC5T583_IRQ_VBATH] = RC5T583_IRQ(ADC_INT, 3, 9, 3, 5),
[RC5T583_IRQ_VIN3H] = RC5T583_IRQ(ADC_INT, 3, 10, 4, 5),
[RC5T583_IRQ_VIN8H] = RC5T583_IRQ(ADC_INT, 3, 11, 5, 5),
[RC5T583_IRQ_ADCEND] = RC5T583_IRQ(ADC_INT, 3, 12, 0, 6),
[RC5T583_IRQ_GPIO0] = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
[RC5T583_IRQ_GPIO1] = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
[RC5T583_IRQ_GPIO2] = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
[RC5T583_IRQ_GPIO3] = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
[RC5T583_IRQ_GPIO4] = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
[RC5T583_IRQ_GPIO5] = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
[RC5T583_IRQ_GPIO6] = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
[RC5T583_IRQ_GPIO7] = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
};
static void rc5t583_irq_lock(struct irq_data *irq_data)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
mutex_lock(&rc5t583->irq_lock);
}
static void rc5t583_irq_unmask(struct irq_data *irq_data)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
rc5t583->intc_inten_reg |= 1 << data->master_bit;
rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
}
static void rc5t583_irq_mask(struct irq_data *irq_data)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
if (!rc5t583->group_irq_en[data->grp_index])
rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
}
static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
int val = 0;
int gpedge_index;
int gpedge_bit_pos;
/* Supporting only trigger level inetrrupt */
if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
gpedge_index = data->int_en_bit / 4;
gpedge_bit_pos = data->int_en_bit % 4;
if (type & IRQ_TYPE_EDGE_FALLING)
val |= 0x2;
if (type & IRQ_TYPE_EDGE_RISING)
val |= 0x1;
rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
rc5t583_irq_unmask(irq_data);
return 0;
}
return -EINVAL;
}
static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
rc5t583->gpedge_reg[i]);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
gpedge_add[i], ret);
}
for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
rc5t583->irq_en_reg[i]);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
irq_en_add[i], ret);
}
ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
rc5t583->intc_inten_reg);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
RC5T583_INTC_INTEN, ret);
mutex_unlock(&rc5t583->irq_lock);
}
#ifdef CONFIG_PM_SLEEP
static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
{
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
return irq_set_irq_wake(rc5t583->chip_irq, on);
}
#else
#define rc5t583_irq_set_wake NULL
#endif
static irqreturn_t rc5t583_irq(int irq, void *data)
{
struct rc5t583 *rc5t583 = data;
uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
uint8_t master_int;
int i;
int ret;
unsigned int rtc_int_sts = 0;
/* Clear the status */
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
int_sts[i] = 0;
ret = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
if (ret < 0) {
dev_err(rc5t583->dev,
"Error in reading reg 0x%02x error: %d\n",
RC5T583_INTC_INTMON, ret);
return IRQ_HANDLED;
}
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
if (!(master_int & main_int_type[i]))
continue;
ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
if (ret < 0) {
dev_warn(rc5t583->dev,
"Error in reading reg 0x%02x error: %d\n",
irq_mon_add[i], ret);
int_sts[i] = 0;
continue;
}
if (main_int_type[i] & RTC_INT) {
rtc_int_sts = 0;
if (int_sts[i] & 0x1)
rtc_int_sts |= BIT(6);
if (int_sts[i] & 0x2)
rtc_int_sts |= BIT(7);
if (int_sts[i] & 0x4)
rtc_int_sts |= BIT(0);
if (int_sts[i] & 0x8)
rtc_int_sts |= BIT(5);
}
ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
~int_sts[i]);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in reading reg 0x%02x error: %d\n",
irq_clr_add[i], ret);
if (main_int_type[i] & RTC_INT)
int_sts[i] = rtc_int_sts;
}
/* Merge gpio interrupts for rising and falling case*/
int_sts[7] |= int_sts[8];
/* Call interrupt handler if enabled */
for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
(rc5t583->group_irq_en[data->master_bit] &
(1 << data->grp_index)))
handle_nested_irq(rc5t583->irq_base + i);
}
return IRQ_HANDLED;
}
static struct irq_chip rc5t583_irq_chip = {
.name = "rc5t583-irq",
.irq_mask = rc5t583_irq_mask,
.irq_unmask = rc5t583_irq_unmask,
.irq_bus_lock = rc5t583_irq_lock,
.irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
.irq_set_type = rc5t583_irq_set_type,
.irq_set_wake = rc5t583_irq_set_wake,
};
int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
{
int i, ret;
if (!irq_base) {
dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
return -EINVAL;
}
mutex_init(&rc5t583->irq_lock);
/* Initailize all int register to 0 */
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
rc5t583->irq_en_reg[i]);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
irq_en_add[i], ret);
}
for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++) {
ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
rc5t583->gpedge_reg[i]);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
gpedge_add[i], ret);
}
ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
RC5T583_INTC_INTEN, ret);
/* Clear all interrupts in case they woke up active. */
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
irq_clr_add[i], ret);
}
rc5t583->irq_base = irq_base;
rc5t583->chip_irq = irq;
for (i = 0; i < RC5T583_MAX_IRQS; i++) {
int __irq = i + rc5t583->irq_base;
irq_set_chip_data(__irq, rc5t583);
irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
handle_simple_irq);
irq_set_nested_thread(__irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(__irq, IRQF_VALID);
#endif
}
ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
"rc5t583", rc5t583);
if (ret < 0)
dev_err(rc5t583->dev,
"Error in registering interrupt error: %d\n", ret);
return ret;
}
int rc5t583_irq_exit(struct rc5t583 *rc5t583)
{
if (rc5t583->chip_irq)
free_irq(rc5t583->chip_irq, rc5t583);
return 0;
}
/*
* Core driver access RC5T583 power management chip.
*
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
* Author: Laxman dewangan <ldewangan@nvidia.com>
*
* Based on code
* Copyright (C) 2011 RICOH COMPANY,LTD
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rc5t583.h>
#include <linux/regmap.h>
#define RICOH_ONOFFSEL_REG 0x10
#define RICOH_SWCTL_REG 0x5E
struct deepsleep_control_data {
u8 reg_add;
u8 ds_pos_bit;
};
#define DEEPSLEEP_INIT(_id, _reg, _pos) \
{ \
.reg_add = RC5T583_##_reg, \
.ds_pos_bit = _pos, \
}
static struct deepsleep_control_data deepsleep_data[] = {
DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
};
#define EXT_PWR_REQ \
(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
static struct mfd_cell rc5t583_subdevs[] = {
{.name = "rc5t583-regulator",},
{.name = "rc5t583-rtc", },
{.name = "rc5t583-key", }
};
int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
return regmap_write(rc5t583->regmap, reg, val);
}
int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
unsigned int ival;
int ret;
ret = regmap_read(rc5t583->regmap, reg, &ival);
if (!ret)
*val = (uint8_t)ival;
return ret;
}
int rc5t583_set_bits(struct device *dev, unsigned int reg,
unsigned int bit_mask)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
}
int rc5t583_clear_bits(struct device *dev, unsigned int reg,
unsigned int bit_mask)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
}
int rc5t583_update(struct device *dev, unsigned int reg,
unsigned int val, unsigned int mask)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
return regmap_update_bits(rc5t583->regmap, reg, mask, val);
}
static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
int id, int ext_pwr, int slots)
{
int ret;
uint8_t sleepseq_val;
unsigned int en_bit;
unsigned int slot_bit;
if (id == RC5T583_DS_DC0) {
dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
return -EINVAL;
}
en_bit = deepsleep_data[id].ds_pos_bit;
slot_bit = en_bit + 1;
ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
if (ret < 0) {
dev_err(dev, "Error in reading reg 0x%x\n",
deepsleep_data[id].reg_add);
return ret;
}
sleepseq_val &= ~(0xF << en_bit);
sleepseq_val |= BIT(en_bit);
sleepseq_val |= ((slots & 0x7) << slot_bit);
ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
if (ret < 0) {
dev_err(dev, "Error in updating the 0x%02x register\n",
RICOH_ONOFFSEL_REG);
return ret;
}
ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
if (ret < 0) {
dev_err(dev, "Error in writing reg 0x%x\n",
deepsleep_data[id].reg_add);
return ret;
}
if (id == RC5T583_DS_LDO4) {
ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
if (ret < 0)
dev_err(dev, "Error in writing reg 0x%x\n",
RICOH_SWCTL_REG);
}
return ret;
}
static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
int id, int ext_pwr)
{
int ret;
if (id != RC5T583_DS_DC0) {
dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
return -EINVAL;
}
ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
if (ret < 0)
dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
return ret;
}
int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
int ext_pwr_req, int deepsleep_slot_nr)
{
if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
return -EINVAL;
if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
ext_pwr_req, deepsleep_slot_nr);
if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
return __rc5t583_set_ext_pwrreq2_control(dev,
ds_id, ext_pwr_req);
return 0;
}
static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
struct rc5t583_platform_data *pdata)
{
int ret;
int i;
uint8_t on_off_val = 0;
/* Clear ONOFFSEL register */
if (pdata->enable_shutdown)
on_off_val = 0x1;
ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
if (ret < 0)
dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
RICOH_ONOFFSEL_REG, ret);
ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
if (ret < 0)
dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
RICOH_SWCTL_REG, ret);
/* Clear sleep sequence register */
for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
ret = rc5t583_write(rc5t583->dev, i, 0x0);
if (ret < 0)
dev_warn(rc5t583->dev,
"Error in writing reg 0x%02x error: %d\n",
i, ret);
}
return 0;
}
static bool volatile_reg(struct device *dev, unsigned int reg)
{
/* Enable caching in interrupt registers */
switch (reg) {
case RC5T583_INT_EN_SYS1:
case RC5T583_INT_EN_SYS2:
case RC5T583_INT_EN_DCDC:
case RC5T583_INT_EN_RTC:
case RC5T583_INT_EN_ADC1:
case RC5T583_INT_EN_ADC2:
case RC5T583_INT_EN_ADC3:
case RC5T583_GPIO_GPEDGE1:
case RC5T583_GPIO_GPEDGE2:
case RC5T583_GPIO_EN_INT:
return false;
case RC5T583_GPIO_MON_IOIN:
/* This is gpio input register */
return true;
default:
/* Enable caching in gpio registers */
if ((reg >= RC5T583_GPIO_IOSEL) &&
(reg <= RC5T583_GPIO_GPOFUNC))
return false;
/* Enable caching in sleep seq registers */
if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
return false;
/* Enable caching of regulator registers */
if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
return false;
if ((reg >= RC5T583_REG_LDOEN1) &&
(reg <= RC5T583_REG_LDO9DAC_DS))
return false;
break;
}
return true;
}
static const struct regmap_config rc5t583_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = volatile_reg,
.max_register = RC5T583_MAX_REGS,
.num_reg_defaults_raw = RC5T583_MAX_REGS,
.cache_type = REGCACHE_RBTREE,
};
static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rc5t583 *rc5t583;
struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
int ret;
bool irq_init_success = false;
if (!pdata) {
dev_err(&i2c->dev, "Err: Platform data not found\n");
return -EINVAL;
}
rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
if (!rc5t583) {
dev_err(&i2c->dev, "Memory allocation failed\n");
return -ENOMEM;
}
rc5t583->dev = &i2c->dev;
i2c_set_clientdata(i2c, rc5t583);
rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
if (IS_ERR(rc5t583->regmap)) {
ret = PTR_ERR(rc5t583->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
return ret;
}
ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
if (ret < 0)
goto err_irq_init;
if (i2c->irq) {
ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
/* Still continue with waring if irq init fails */
if (ret)
dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
else
irq_init_success = true;
}
ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
if (ret) {
dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
goto err_add_devs;
}
return 0;
err_add_devs:
if (irq_init_success)
rc5t583_irq_exit(rc5t583);
err_irq_init:
regmap_exit(rc5t583->regmap);
return ret;
}
static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
{
struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
mfd_remove_devices(rc5t583->dev);
rc5t583_irq_exit(rc5t583);
regmap_exit(rc5t583->regmap);
return 0;
}
static const struct i2c_device_id rc5t583_i2c_id[] = {
{.name = "rc5t583", .driver_data = 0},
{}
};
MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
static struct i2c_driver rc5t583_i2c_driver = {
.driver = {
.name = "rc5t583",
.owner = THIS_MODULE,
},
.probe = rc5t583_i2c_probe,
.remove = __devexit_p(rc5t583_i2c_remove),
.id_table = rc5t583_i2c_id,
};
static int __init rc5t583_i2c_init(void)
{
return i2c_add_driver(&rc5t583_i2c_driver);
}
subsys_initcall(rc5t583_i2c_init);
static void __exit rc5t583_i2c_exit(void)
{
i2c_del_driver(&rc5t583_i2c_driver);
}
module_exit(rc5t583_i2c_exit);
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
MODULE_LICENSE("GPL v2");
......@@ -26,7 +26,27 @@
#include <linux/mfd/s5m87xx/s5m-rtc.h>
#include <linux/regmap.h>
static struct mfd_cell s5m87xx_devs[] = {
static struct mfd_cell s5m8751_devs[] = {
{
.name = "s5m8751-pmic",
}, {
.name = "s5m-charger",
}, {
.name = "s5m8751-codec",
},
};
static struct mfd_cell s5m8763_devs[] = {
{
.name = "s5m8763-pmic",
}, {
.name = "s5m-rtc",
}, {
.name = "s5m-charger",
},
};
static struct mfd_cell s5m8767_devs[] = {
{
.name = "s5m8767-pmic",
}, {
......@@ -42,7 +62,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_read);
int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
}
EXPORT_SYMBOL_GPL(s5m_bulk_read);
......@@ -54,7 +74,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_write);
int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
}
EXPORT_SYMBOL_GPL(s5m_bulk_write);
......@@ -74,10 +94,10 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
{
struct s5m_platform_data *pdata = i2c->dev.platform_data;
struct s5m87xx_dev *s5m87xx;
int ret = 0;
int error;
int ret;
s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
GFP_KERNEL);
if (s5m87xx == NULL)
return -ENOMEM;
......@@ -96,9 +116,9 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
if (IS_ERR(s5m87xx->regmap)) {
error = PTR_ERR(s5m87xx->regmap);
ret = PTR_ERR(s5m87xx->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
error);
ret);
goto err;
}
......@@ -112,9 +132,23 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(s5m87xx->dev);
ret = mfd_add_devices(s5m87xx->dev, -1,
s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
NULL, 0);
switch (s5m87xx->device_type) {
case S5M8751X:
ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
ARRAY_SIZE(s5m8751_devs), NULL, 0);
break;
case S5M8763X:
ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
ARRAY_SIZE(s5m8763_devs), NULL, 0);
break;
case S5M8767X:
ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
ARRAY_SIZE(s5m8767_devs), NULL, 0);
break;
default:
/* If this happens the probe function is problem */
BUG();
}
if (ret < 0)
goto err;
......@@ -126,7 +160,6 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
kfree(s5m87xx);
return ret;
}
......@@ -138,7 +171,6 @@ static int s5m87xx_i2c_remove(struct i2c_client *i2c)
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
kfree(s5m87xx);
return 0;
}
......
......@@ -342,7 +342,10 @@ int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
break;
default:
break;
dev_err(s5m87xx->dev,
"Unknown device type %d\n",
s5m87xx->device_type);
return -EINVAL;
}
}
......@@ -444,7 +447,9 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
}
break;
default:
break;
dev_err(s5m87xx->dev,
"Unknown device type %d\n", s5m87xx->device_type);
return -EINVAL;
}
if (!s5m87xx->ono)
......@@ -467,12 +472,15 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
break;
default:
ret = -EINVAL;
break;
}
if (ret)
if (ret) {
dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
s5m87xx->ono, ret);
return ret;
}
return 0;
}
......
......@@ -387,14 +387,6 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
EXPORT_SYMBOL_GPL(sm501_unit_power);
/* Perform a rounded division. */
static long sm501fb_round_div(long num, long denom)
{
/* n / d + 1 / 2 = (2n + d) / 2d */
return (2 * num + denom) / (2 * denom);
}
/* clock value structure. */
struct sm501_clock {
unsigned long mclk;
......@@ -428,7 +420,7 @@ static int sm501_calc_clock(unsigned long freq,
/* try all 8 shift values.*/
for (shift = 0; shift < 8; shift++) {
/* Calculate difference to requested clock */
diff = sm501fb_round_div(mclk, divider << shift) - freq;
diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
if (diff < 0)
diff = -diff;
......
......@@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
.num_resources = ARRAY_SIZE(stmpe_gpio_resources),
};
static struct mfd_cell stmpe_gpio_cell_noirq = {
.name = "stmpe-gpio",
/* gpio cell resources consist of an irq only so no resources here */
};
/*
* Keypad (1601, 2401, 2403)
*/
......@@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
},
};
static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
{
.cell = &stmpe_gpio_cell_noirq,
.block = STMPE_BLOCK_GPIO,
},
};
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
......@@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
.enable = stmpe801_enable,
};
static struct stmpe_variant_info stmpe801_noirq = {
.name = "stmpe801",
.id_val = STMPE801_ID,
.id_mask = 0xffff,
.num_gpios = 8,
.regs = stmpe801_regs,
.blocks = stmpe801_blocks_noirq,
.num_blocks = ARRAY_SIZE(stmpe801_blocks_noirq),
.enable = stmpe801_enable,
};
/*
* Touchscreen (STMPE811 or STMPE610)
*/
......@@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
.enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
};
static struct stmpe_variant_info *stmpe_variant_info[] = {
static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
[STMPE610] = &stmpe610,
[STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
......@@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
[STMPE2403] = &stmpe2403,
};
/*
* These devices can be connected in a 'no-irq' configuration - the irq pin
* is not used and the device cannot interrupt the CPU. Here we only list
* devices which support this configuration - the driver will fail probing
* for any devices not listed here which are configured in this way.
*/
static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
[STMPE801] = &stmpe801_noirq,
};
static irqreturn_t stmpe_irq(int irq, void *data)
{
struct stmpe *stmpe = data;
......@@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
struct stmpe_variant_info *variant = stmpe->variant;
u8 icr;
u8 icr = 0;
unsigned int id;
u8 data[2];
int ret;
......@@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
if (id == STMPE801_ID)
icr = STMPE801_REG_SYS_CTRL_INT_EN;
else
icr = STMPE_ICR_LSB_GIM;
/* STMPE801 doesn't support Edge interrupts */
if (id != STMPE801_ID) {
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
}
if (irq_trigger == IRQF_TRIGGER_RISING ||
irq_trigger == IRQF_TRIGGER_HIGH) {
if (stmpe->irq >= 0) {
if (id == STMPE801_ID)
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
icr = STMPE801_REG_SYS_CTRL_INT_EN;
else
icr |= STMPE_ICR_LSB_HIGH;
}
icr = STMPE_ICR_LSB_GIM;
if (stmpe->pdata->irq_invert_polarity) {
if (id == STMPE801_ID)
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
else
icr ^= STMPE_ICR_LSB_HIGH;
/* STMPE801 doesn't support Edge interrupts */
if (id != STMPE801_ID) {
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
}
if (irq_trigger == IRQF_TRIGGER_RISING ||
irq_trigger == IRQF_TRIGGER_HIGH) {
if (id == STMPE801_ID)
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
else
icr |= STMPE_ICR_LSB_HIGH;
}
if (stmpe->pdata->irq_invert_polarity) {
if (id == STMPE801_ID)
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
else
icr ^= STMPE_ICR_LSB_HIGH;
}
}
if (stmpe->pdata->autosleep) {
......@@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
stmpe->irq = ci->irq;
}
if (stmpe->irq < 0) {
/* use alternate variant info for no-irq mode, if supported */
dev_info(stmpe->dev,
"%s configured in no-irq mode by platform data\n",
stmpe->variant->name);
if (!stmpe_noirq_variant_info[stmpe->partnum]) {
dev_err(stmpe->dev,
"%s does not support no-irq mode!\n",
stmpe->variant->name);
ret = -ENODEV;
goto free_gpio;
}
stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
}
ret = stmpe_chip_init(stmpe);
if (ret)
goto free_gpio;
ret = stmpe_irq_init(stmpe);
if (ret)
goto free_gpio;
if (stmpe->irq >= 0) {
ret = stmpe_irq_init(stmpe);
if (ret)
goto free_gpio;
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
pdata->irq_trigger | IRQF_ONESHOT,
"stmpe", stmpe);
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n",
ret);
goto out_removeirq;
}
}
ret = stmpe_devices_init(stmpe);
......@@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
out_removedevs:
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->irq, stmpe);
if (stmpe->irq >= 0)
free_irq(stmpe->irq, stmpe);
out_removeirq:
stmpe_irq_remove(stmpe);
if (stmpe->irq >= 0)
stmpe_irq_remove(stmpe);
free_gpio:
if (pdata->irq_over_gpio)
gpio_free(pdata->irq_gpio);
......@@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
{
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
if (stmpe->irq >= 0) {
free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
}
if (stmpe->pdata->irq_over_gpio)
gpio_free(stmpe->pdata->irq_gpio);
......@@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
if (stmpe->irq >= 0 && device_may_wakeup(dev))
enable_irq_wake(stmpe->irq);
return 0;
......@@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
if (stmpe->irq >= 0 && device_may_wakeup(dev))
disable_irq_wake(stmpe->irq);
return 0;
......
/*
* Core driver for TI TPS65090 PMIC family
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65090.h>
#include <linux/regmap.h>
#include <linux/err.h>
#define NUM_INT_REG 2
#define TOTAL_NUM_REG 0x18
/* interrupt status registers */
#define TPS65090_INT_STS 0x0
#define TPS65090_INT_STS2 0x1
/* interrupt mask registers */
#define TPS65090_INT_MSK 0x2
#define TPS65090_INT_MSK2 0x3
struct tps65090_irq_data {
u8 mask_reg;
u8 mask_pos;
};
#define TPS65090_IRQ(_reg, _mask_pos) \
{ \
.mask_reg = (_reg), \
.mask_pos = (_mask_pos), \
}
static const struct tps65090_irq_data tps65090_irqs[] = {
[0] = TPS65090_IRQ(0, 0),
[1] = TPS65090_IRQ(0, 1),
[2] = TPS65090_IRQ(0, 2),
[3] = TPS65090_IRQ(0, 3),
[4] = TPS65090_IRQ(0, 4),
[5] = TPS65090_IRQ(0, 5),
[6] = TPS65090_IRQ(0, 6),
[7] = TPS65090_IRQ(0, 7),
[8] = TPS65090_IRQ(1, 0),
[9] = TPS65090_IRQ(1, 1),
[10] = TPS65090_IRQ(1, 2),
[11] = TPS65090_IRQ(1, 3),
[12] = TPS65090_IRQ(1, 4),
[13] = TPS65090_IRQ(1, 5),
[14] = TPS65090_IRQ(1, 6),
[15] = TPS65090_IRQ(1, 7),
};
static struct mfd_cell tps65090s[] = {
{
.name = "tps65910-pmic",
},
{
.name = "tps65910-regulator",
},
};
struct tps65090 {
struct mutex lock;
struct device *dev;
struct i2c_client *client;
struct regmap *rmap;
struct irq_chip irq_chip;
struct mutex irq_lock;
int irq_base;
unsigned int id;
};
int tps65090_write(struct device *dev, int reg, uint8_t val)
{
struct tps65090 *tps = dev_get_drvdata(dev);
return regmap_write(tps->rmap, reg, val);
}
EXPORT_SYMBOL_GPL(tps65090_write);
int tps65090_read(struct device *dev, int reg, uint8_t *val)
{
struct tps65090 *tps = dev_get_drvdata(dev);
unsigned int temp_val;
int ret;
ret = regmap_read(tps->rmap, reg, &temp_val);
if (!ret)
*val = temp_val;
return ret;
}
EXPORT_SYMBOL_GPL(tps65090_read);
int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
{
struct tps65090 *tps = dev_get_drvdata(dev);
return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
}
EXPORT_SYMBOL_GPL(tps65090_set_bits);
int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
{
struct tps65090 *tps = dev_get_drvdata(dev);
return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
}
EXPORT_SYMBOL_GPL(tps65090_clr_bits);
static void tps65090_irq_lock(struct irq_data *data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
mutex_lock(&tps65090->irq_lock);
}
static void tps65090_irq_mask(struct irq_data *irq_data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->hwirq;
const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
data->mask_pos);
}
static void tps65090_irq_unmask(struct irq_data *irq_data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - tps65090->irq_base;
const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
data->mask_pos);
}
static void tps65090_irq_sync_unlock(struct irq_data *data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
mutex_unlock(&tps65090->irq_lock);
}
static irqreturn_t tps65090_irq(int irq, void *data)
{
struct tps65090 *tps65090 = data;
int ret = 0;
u8 status, mask;
unsigned long int acks = 0;
int i;
for (i = 0; i < NUM_INT_REG; i++) {
ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
if (ret < 0) {
dev_err(tps65090->dev,
"failed to read mask reg [addr:%d]\n",
TPS65090_INT_MSK + i);
return IRQ_NONE;
}
ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
&status);
if (ret < 0) {
dev_err(tps65090->dev,
"failed to read status reg [addr:%d]\n",
TPS65090_INT_STS + i);
return IRQ_NONE;
}
if (status) {
/* Ack only those interrupts which are not masked */
status &= (~mask);
ret = tps65090_write(tps65090->dev,
TPS65090_INT_STS + i, status);
if (ret < 0) {
dev_err(tps65090->dev,
"failed to write interrupt status\n");
return IRQ_NONE;
}
acks |= (status << (i * 8));
}
}
for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
handle_nested_irq(tps65090->irq_base + i);
return acks ? IRQ_HANDLED : IRQ_NONE;
}
static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
int irq_base)
{
int i, ret;
if (!irq_base) {
dev_err(tps65090->dev, "IRQ base not set\n");
return -EINVAL;
}
mutex_init(&tps65090->irq_lock);
for (i = 0; i < NUM_INT_REG; i++)
tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
for (i = 0; i < NUM_INT_REG; i++)
tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
tps65090->irq_base = irq_base;
tps65090->irq_chip.name = "tps65090";
tps65090->irq_chip.irq_mask = tps65090_irq_mask;
tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
int __irq = i + tps65090->irq_base;
irq_set_chip_data(__irq, tps65090);
irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
handle_simple_irq);
irq_set_nested_thread(__irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(__irq, IRQF_VALID);
#endif
}
ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
"tps65090", tps65090);
if (!ret) {
device_init_wakeup(tps65090->dev, 1);
enable_irq_wake(irq);
}
return ret;
}
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
return true;
else
return false;
}
static const struct regmap_config tps65090_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TOTAL_NUM_REG,
.num_reg_defaults_raw = TOTAL_NUM_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = is_volatile_reg,
};
static int __devinit tps65090_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tps65090_platform_data *pdata = client->dev.platform_data;
struct tps65090 *tps65090;
int ret;
if (!pdata) {
dev_err(&client->dev, "tps65090 requires platform data\n");
return -EINVAL;
}
tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
GFP_KERNEL);
if (tps65090 == NULL)
return -ENOMEM;
tps65090->client = client;
tps65090->dev = &client->dev;
i2c_set_clientdata(client, tps65090);
mutex_init(&tps65090->lock);
if (client->irq) {
ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
if (ret) {
dev_err(&client->dev, "IRQ init failed with err: %d\n",
ret);
goto err_exit;
}
}
tps65090->rmap = regmap_init_i2c(tps65090->client,
&tps65090_regmap_config);
if (IS_ERR(tps65090->rmap)) {
dev_err(&client->dev, "regmap_init failed with err: %ld\n",
PTR_ERR(tps65090->rmap));
goto err_irq_exit;
};
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
ARRAY_SIZE(tps65090s), NULL, 0);
if (ret) {
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
ret);
goto err_regmap_exit;
}
return 0;
err_regmap_exit:
regmap_exit(tps65090->rmap);
err_irq_exit:
if (client->irq)
free_irq(client->irq, tps65090);
err_exit:
return ret;
}
static int __devexit tps65090_i2c_remove(struct i2c_client *client)
{
struct tps65090 *tps65090 = i2c_get_clientdata(client);
mfd_remove_devices(tps65090->dev);
regmap_exit(tps65090->rmap);
if (client->irq)
free_irq(client->irq, tps65090);
return 0;
}
#ifdef CONFIG_PM
static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
{
if (client->irq)
disable_irq(client->irq);
return 0;
}
static int tps65090_i2c_resume(struct i2c_client *client)
{
if (client->irq)
enable_irq(client->irq);
return 0;
}
#endif
static const struct i2c_device_id tps65090_id_table[] = {
{ "tps65090", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
static struct i2c_driver tps65090_driver = {
.driver = {
.name = "tps65090",
.owner = THIS_MODULE,
},
.probe = tps65090_i2c_probe,
.remove = __devexit_p(tps65090_i2c_remove),
#ifdef CONFIG_PM
.suspend = tps65090_i2c_suspend,
.resume = tps65090_i2c_resume,
#endif
.id_table = tps65090_id_table,
};
static int __init tps65090_init(void)
{
return i2c_add_driver(&tps65090_driver);
}
subsys_initcall(tps65090_init);
static void __exit tps65090_exit(void)
{
i2c_del_driver(&tps65090_driver);
}
module_exit(tps65090_exit);
MODULE_DESCRIPTION("TPS65090 core driver");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
MODULE_LICENSE("GPL v2");
/*
* tps65217.c
*
* TPS65217 chip family multi-function driver
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65217.h>
/**
* tps65217_reg_read: Read a single tps65217 register.
*
* @tps: Device to read from.
* @reg: Register to read.
* @val: Contians the value
*/
int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
unsigned int *val)
{
return regmap_read(tps->regmap, reg, val);
}
EXPORT_SYMBOL_GPL(tps65217_reg_read);
/**
* tps65217_reg_write: Write a single tps65217 register.
*
* @tps65217: Device to write to.
* @reg: Register to write to.
* @val: Value to write.
* @level: Password protected level
*/
int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
unsigned int val, unsigned int level)
{
int ret;
unsigned int xor_reg_val;
switch (level) {
case TPS65217_PROTECT_NONE:
return regmap_write(tps->regmap, reg, val);
case TPS65217_PROTECT_L1:
xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
xor_reg_val);
if (ret < 0)
return ret;
return regmap_write(tps->regmap, reg, val);
case TPS65217_PROTECT_L2:
xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
xor_reg_val);
if (ret < 0)
return ret;
ret = regmap_write(tps->regmap, reg, val);
if (ret < 0)
return ret;
ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
xor_reg_val);
if (ret < 0)
return ret;
return regmap_write(tps->regmap, reg, val);
default:
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(tps65217_reg_write);
/**
* tps65217_update_bits: Modify bits w.r.t mask, val and level.
*
* @tps65217: Device to write to.
* @reg: Register to read-write to.
* @mask: Mask.
* @val: Value to write.
* @level: Password protected level
*/
int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
unsigned int mask, unsigned int val, unsigned int level)
{
int ret;
unsigned int data;
ret = tps65217_reg_read(tps, reg, &data);
if (ret) {
dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
return ret;
}
data &= ~mask;
data |= val & mask;
ret = tps65217_reg_write(tps, reg, data, level);
if (ret)
dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
return ret;
}
int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
unsigned int mask, unsigned int val, unsigned int level)
{
return tps65217_update_bits(tps, reg, mask, val, level);
}
EXPORT_SYMBOL_GPL(tps65217_set_bits);
int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
unsigned int mask, unsigned int level)
{
return tps65217_update_bits(tps, reg, mask, 0, level);
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
static struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int __devinit tps65217_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
{
struct tps65217 *tps;
struct tps65217_board *pdata = client->dev.platform_data;
int i, ret;
unsigned int version;
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
tps->pdata = pdata;
tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
dev_err(tps->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
i2c_set_clientdata(client, tps);
tps->dev = &client->dev;
ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
if (ret < 0) {
dev_err(tps->dev, "Failed to read revision"
" register: %d\n", ret);
goto err_regmap;
}
dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
version & TPS65217_CHIPID_REV_MASK);
for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
struct platform_device *pdev;
pdev = platform_device_alloc("tps65217-pmic", i);
if (!pdev) {
dev_err(tps->dev, "Cannot create regulator %d\n", i);
continue;
}
pdev->dev.parent = tps->dev;
platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
sizeof(pdata->tps65217_init_data[i]));
tps->regulator_pdev[i] = pdev;
platform_device_add(pdev);
}
return 0;
err_regmap:
regmap_exit(tps->regmap);
return ret;
}
static int __devexit tps65217_remove(struct i2c_client *client)
{
struct tps65217 *tps = i2c_get_clientdata(client);
int i;
for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
platform_device_unregister(tps->regulator_pdev[i]);
regmap_exit(tps->regmap);
return 0;
}
static const struct i2c_device_id tps65217_id_table[] = {
{"tps65217", 0xF0},
{/* end of list */}
};
MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
static struct i2c_driver tps65217_driver = {
.driver = {
.name = "tps65217",
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
.remove = __devexit_p(tps65217_remove),
};
static int __init tps65217_init(void)
{
return i2c_add_driver(&tps65217_driver);
}
subsys_initcall(tps65217_init);
static void __exit tps65217_exit(void)
{
i2c_del_driver(&tps65217_driver);
}
module_exit(tps65217_exit);
MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
MODULE_LICENSE("GPL v2");
......@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
}
#ifdef CONFIG_PM_SLEEP
static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
return irq_set_irq_wake(tps65910->chip_irq, enable);
}
#else
#define tps65910_irq_set_wake NULL
#endif
static struct irq_chip tps65910_irq_chip = {
.name = "tps65910",
.irq_bus_lock = tps65910_irq_lock,
.irq_bus_sync_unlock = tps65910_irq_sync_unlock,
.irq_disable = tps65910_irq_disable,
.irq_enable = tps65910_irq_enable,
.irq_set_wake = tps65910_irq_set_wake,
};
int tps65910_irq_init(struct tps65910 *tps65910, int irq,
......
......@@ -16,10 +16,12 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/mfd/core.h>
#include <linux/regmap.h>
#include <linux/mfd/tps65910.h>
static struct mfd_cell tps65910s[] = {
......@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
int bytes, void *dest)
{
struct i2c_client *i2c = tps65910->i2c_client;
struct i2c_msg xfer[2];
int ret;
/* Write register */
xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = bytes;
xfer[1].buf = dest;
ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret == 2)
ret = 0;
else if (ret >= 0)
ret = -EIO;
return ret;
return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
}
static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
int bytes, void *src)
int bytes, void *src)
{
struct i2c_client *i2c = tps65910->i2c_client;
/* we add 1 byte for device register */
u8 msg[TPS65910_MAX_REGISTER + 1];
int ret;
if (bytes > TPS65910_MAX_REGISTER)
return -EINVAL;
msg[0] = reg;
memcpy(&msg[1], src, bytes);
ret = i2c_master_send(i2c, msg, bytes + 1);
if (ret < 0)
return ret;
if (ret != bytes + 1)
return -EIO;
return 0;
return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
}
int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
{
u8 data;
int err;
mutex_lock(&tps65910->io_mutex);
err = tps65910_i2c_read(tps65910, reg, 1, &data);
if (err) {
dev_err(tps65910->dev, "read from reg %x failed\n", reg);
goto out;
}
data |= mask;
err = tps65910_i2c_write(tps65910, reg, 1, &data);
if (err)
dev_err(tps65910->dev, "write to reg %x failed\n", reg);
out:
mutex_unlock(&tps65910->io_mutex);
return err;
return regmap_update_bits(tps65910->regmap, reg, mask, mask);
}
EXPORT_SYMBOL_GPL(tps65910_set_bits);
int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
{
u8 data;
int err;
mutex_lock(&tps65910->io_mutex);
err = tps65910_i2c_read(tps65910, reg, 1, &data);
if (err) {
dev_err(tps65910->dev, "read from reg %x failed\n", reg);
goto out;
}
data &= ~mask;
err = tps65910_i2c_write(tps65910, reg, 1, &data);
if (err)
dev_err(tps65910->dev, "write to reg %x failed\n", reg);
out:
mutex_unlock(&tps65910->io_mutex);
return err;
return regmap_update_bits(tps65910->regmap, reg, mask, 0);
}
EXPORT_SYMBOL_GPL(tps65910_clear_bits);
static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
struct tps65910 *tps65910 = dev_get_drvdata(dev);
/*
* Caching all regulator registers.
* All regualator register address range is same for
* TPS65910 and TPS65911
*/
if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
/* Check for non-existing register */
if (tps65910_chip_id(tps65910) == TPS65910)
if ((reg == TPS65911_VDDCTRL_OP) ||
(reg == TPS65911_VDDCTRL_SR))
return true;
return false;
}
return true;
}
static const struct regmap_config tps65910_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
.max_register = TPS65910_MAX_REGISTER,
.num_reg_defaults_raw = TPS65910_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
static int tps65910_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
......@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
tps65910->write = tps65910_i2c_write;
mutex_init(&tps65910->io_mutex);
tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
if (IS_ERR(tps65910->regmap)) {
ret = PTR_ERR(tps65910->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
goto regmap_err;
}
ret = mfd_add_devices(tps65910->dev, -1,
tps65910s, ARRAY_SIZE(tps65910s),
NULL, 0);
......@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
return ret;
err:
regmap_exit(tps65910->regmap);
regmap_err:
kfree(tps65910);
kfree(init_data);
return ret;
......@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
tps65910_irq_exit(tps65910);
mfd_remove_devices(tps65910->dev);
regmap_exit(tps65910->regmap);
kfree(tps65910);
return 0;
......
......@@ -46,9 +46,7 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
#include <plat/cpu.h>
#endif
#include "twl-core.h"
/*
* The TWL4030 "Triton 2" is one of a family of a multi-function "Power
......@@ -116,8 +114,8 @@
#define twl_has_watchdog() false
#endif
#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
#define twl_has_codec() true
#else
#define twl_has_codec() false
......@@ -147,12 +145,10 @@
#define SUB_CHIP_ID1 1
#define SUB_CHIP_ID2 2
#define SUB_CHIP_ID3 3
#define SUB_CHIP_ID_INVAL 0xff
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
#define TWL4030_NR_IRQS 34 /* core:8, power:8, gpio: 18 */
#define TWL6030_NR_IRQS 20
/* Base Address defns for twl4030_map[] */
/* subchip/slave 0 - USB ID */
......@@ -314,7 +310,7 @@ static struct twl_mapping twl6030_map[] = {
* so they continue to match the order in this table.
*/
{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
{ SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
{ SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
......@@ -376,6 +372,11 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
return -EPERM;
}
sid = twl_map[mod_no].sid;
if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
pr_err("%s: module %d is not part of the pmic\n",
DRIVER_NAME, mod_no);
return -EINVAL;
}
twl = &twl_modules[sid];
mutex_lock(&twl->xfer_lock);
......@@ -433,6 +434,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
return -EPERM;
}
sid = twl_map[mod_no].sid;
if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
pr_err("%s: module %d is not part of the pmic\n",
DRIVER_NAME, mod_no);
return -EINVAL;
}
twl = &twl_modules[sid];
mutex_lock(&twl->xfer_lock);
......@@ -663,7 +669,8 @@ add_regulator(int num, struct regulator_init_data *pdata,
*/
static int
add_children(struct twl4030_platform_data *pdata, unsigned long features)
add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
unsigned long features)
{
struct device *child;
unsigned sub_chip_id;
......@@ -671,7 +678,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_gpio() && pdata->gpio) {
child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
pdata->gpio, sizeof(*pdata->gpio),
false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
false, irq_base + GPIO_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -679,7 +686,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_keypad() && pdata->keypad) {
child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
pdata->keypad, sizeof(*pdata->keypad),
true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
true, irq_base + KEYPAD_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -687,7 +694,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_madc() && pdata->madc) {
child = add_child(2, "twl4030_madc",
pdata->madc, sizeof(*pdata->madc),
true, pdata->irq_base + MADC_INTR_OFFSET, 0);
true, irq_base + MADC_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -703,7 +710,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
child = add_child(sub_chip_id, "twl_rtc",
NULL, 0,
true, pdata->irq_base + RTC_INTR_OFFSET, 0);
true, irq_base + RTC_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -756,8 +763,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
pdata->usb, sizeof(*pdata->usb),
true,
/* irq0 = USB_PRES, irq1 = USB */
pdata->irq_base + USB_PRES_INTR_OFFSET,
pdata->irq_base + USB_INTR_OFFSET);
irq_base + USB_PRES_INTR_OFFSET,
irq_base + USB_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
......@@ -805,8 +812,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
pdata->usb, sizeof(*pdata->usb),
true,
/* irq1 = VBUS_PRES, irq0 = USB ID */
pdata->irq_base + USBOTG_INTR_OFFSET,
pdata->irq_base + USB_PRES_INTR_OFFSET);
irq_base + USBOTG_INTR_OFFSET,
irq_base + USB_PRES_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
......@@ -833,7 +840,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_pwrbutton() && twl_class_is_4030()) {
child = add_child(1, "twl4030_pwrbutton",
NULL, 0, true, pdata->irq_base + 8 + 0, 0);
NULL, 0, true, irq_base + 8 + 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -847,15 +854,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
child = add_child(sub_chip_id, "twl6040",
pdata->audio, sizeof(*pdata->audio),
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
/* twl4030 regulators */
if (twl_has_regulator() && twl_class_is_4030()) {
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
......@@ -1092,8 +1090,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
child = add_child(3, "twl4030_bci",
pdata->bci, sizeof(*pdata->bci), false,
/* irq0 = CHG_PRES, irq1 = BCI */
pdata->irq_base + BCI_PRES_INTR_OFFSET,
pdata->irq_base + BCI_INTR_OFFSET);
irq_base + BCI_PRES_INTR_OFFSET,
irq_base + BCI_INTR_OFFSET);
if (IS_ERR(child))
return PTR_ERR(child);
}
......@@ -1193,26 +1191,24 @@ static void clocks_init(struct device *dev,
/*----------------------------------------------------------------------*/
int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
int twl4030_exit_irq(void);
int twl4030_init_chip_irq(const char *chip);
int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
int twl6030_exit_irq(void);
static int twl_remove(struct i2c_client *client)
{
unsigned i;
unsigned i, num_slaves;
int status;
if (twl_class_is_4030())
if (twl_class_is_4030()) {
status = twl4030_exit_irq();
else
num_slaves = TWL_NUM_SLAVES;
} else {
status = twl6030_exit_irq();
num_slaves = TWL_NUM_SLAVES - 1;
}
if (status < 0)
return status;
for (i = 0; i < TWL_NUM_SLAVES; i++) {
for (i = 0; i < num_slaves; i++) {
struct twl_client *twl = &twl_modules[i];
if (twl->client && twl->client != client)
......@@ -1223,20 +1219,15 @@ static int twl_remove(struct i2c_client *client)
return 0;
}
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
struct device_node *node = client->dev.of_node;
u8 temp;
int ret = 0;
int nr_irqs = TWL4030_NR_IRQS;
if ((id->driver_data) & TWL6030_CLASS)
nr_irqs = TWL6030_NR_IRQS;
int irq_base = 0;
int status;
unsigned i, num_slaves;
if (node && !pdata) {
/*
......@@ -1255,17 +1246,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EINVAL;
}
status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
if (IS_ERR_VALUE(status)) {
dev_err(&client->dev, "Fail to allocate IRQ descs\n");
return status;
}
pdata->irq_base = status;
pdata->irq_end = pdata->irq_base + nr_irqs;
irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
&irq_domain_simple_ops, NULL);
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
return -EIO;
......@@ -1276,13 +1256,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -EBUSY;
}
for (i = 0; i < TWL_NUM_SLAVES; i++) {
struct twl_client *twl = &twl_modules[i];
if ((id->driver_data) & TWL6030_CLASS) {
twl_id = TWL6030_CLASS_ID;
twl_map = &twl6030_map[0];
num_slaves = TWL_NUM_SLAVES - 1;
} else {
twl_id = TWL4030_CLASS_ID;
twl_map = &twl4030_map[0];
num_slaves = TWL_NUM_SLAVES;
}
for (i = 0; i < num_slaves; i++) {
struct twl_client *twl = &twl_modules[i];
twl->address = client->addr + i;
if (i == 0)
if (i == 0) {
twl->client = client;
else {
} else {
twl->client = i2c_new_dummy(client->adapter,
twl->address);
if (!twl->client) {
......@@ -1294,22 +1284,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
mutex_init(&twl->xfer_lock);
}
inuse = true;
if ((id->driver_data) & TWL6030_CLASS) {
twl_id = TWL6030_CLASS_ID;
twl_map = &twl6030_map[0];
} else {
twl_id = TWL4030_CLASS_ID;
twl_map = &twl4030_map[0];
}
/* setup clock framework */
clocks_init(&client->dev, pdata->clock);
/* read TWL IDCODE Register */
if (twl_id == TWL4030_CLASS_ID) {
ret = twl_read_idcode_register();
WARN(ret < 0, "Error: reading twl_idcode register value\n");
status = twl_read_idcode_register();
WARN(status < 0, "Error: reading twl_idcode register value\n");
}
/* load power event scripts */
......@@ -1317,31 +1301,31 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl4030_power_init(pdata->power);
/* Maybe init the T2 Interrupt subsystem */
if (client->irq
&& pdata->irq_base
&& pdata->irq_end > pdata->irq_base) {
if (client->irq) {
if (twl_class_is_4030()) {
twl4030_init_chip_irq(id->name);
status = twl4030_init_irq(client->irq, pdata->irq_base,
pdata->irq_end);
irq_base = twl4030_init_irq(&client->dev, client->irq);
} else {
status = twl6030_init_irq(client->irq, pdata->irq_base,
pdata->irq_end);
irq_base = twl6030_init_irq(&client->dev, client->irq);
}
if (status < 0)
if (irq_base < 0) {
status = irq_base;
goto fail;
}
}
/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
/*
* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
* Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
*/
if (twl_class_is_4030()) {
u8 temp;
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
......@@ -1349,11 +1333,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
if (status)
status = add_children(pdata, id->driver_data);
status = add_children(pdata, irq_base, id->driver_data);
fail:
if (status < 0)
twl_remove(client);
return status;
}
......
#ifndef __TWL_CORE_H__
#define __TWL_CORE_H__
extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
extern int twl6030_init_irq(struct device *dev, int irq_num);
extern int twl6030_exit_irq(void);
extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
extern int twl4030_init_irq(struct device *dev, int irq_num);
extern int twl4030_exit_irq(void);
extern int twl4030_init_chip_irq(const char *chip);
......
......@@ -28,10 +28,12 @@
*/
#include <linux/init.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/i2c/twl.h>
#include "twl-core.h"
......@@ -53,13 +55,14 @@
* base + 8 .. base + 15 SIH for PWR_INT
* base + 16 .. base + 33 SIH for GPIO
*/
#define TWL4030_CORE_NR_IRQS 8
#define TWL4030_PWR_NR_IRQS 8
/* PIH register offsets */
#define REG_PIH_ISR_P1 0x01
#define REG_PIH_ISR_P2 0x02
#define REG_PIH_SIR 0x03 /* for testing */
/* Linux could (eventually) use either IRQ line */
static int irq_line;
......@@ -111,7 +114,8 @@ static int nr_sih_modules;
#define TWL4030_MODULE_INT_PWR TWL4030_MODULE_INT
/* Order in this table matches order in PIH_ISR. That is,
/*
* Order in this table matches order in PIH_ISR. That is,
* BIT(n) in PIH_ISR is sih_modules[n].
*/
/* sih_modules_twl4030 is used both in twl4030 and twl5030 */
......@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
*/
static irqreturn_t handle_twl4030_pih(int irq, void *devid)
{
int module_irq;
irqreturn_t ret;
u8 pih_isr;
......@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
return IRQ_NONE;
}
/* these handlers deal with the relevant SIH irq status */
for (module_irq = twl4030_irq_base;
pih_isr;
pih_isr >>= 1, module_irq++) {
if (pih_isr & 0x1)
handle_nested_irq(module_irq);
while (pih_isr) {
unsigned long pending = __ffs(pih_isr);
unsigned int irq;
pih_isr &= ~BIT(pending);
irq = pending + twl4030_irq_base;
handle_nested_irq(irq);
}
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------*/
/*
......@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
memset(buf, 0xff, sizeof buf);
sih = sih_modules;
for (i = 0; i < nr_sih_modules; i++, sih++) {
/* skip USB -- it's funky */
if (!sih->bytes_ixr)
continue;
......@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
pr_err("twl4030: err %d initializing %s %s\n",
status, sih->name, "IMR");
/* Maybe disable "exclusive" mode; buffer second pending irq;
/*
* Maybe disable "exclusive" mode; buffer second pending irq;
* set Clear-On-Read (COR) bit.
*
* NOTE that sometimes COR polarity is documented as being
......@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
if (sih->irq_lines <= line)
continue;
/* Clear pending interrupt status. Either the read was
/*
* Clear pending interrupt status. Either the read was
* enough, or we need to write those bits. Repeat, in
* case an IRQ is pending (PENDDIS=0) ... that's not
* uncommon with PWR_INT.PWRON.
......@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
status = twl_i2c_write(sih->module, buf,
sih->mask[line].isr_offset,
sih->bytes_ixr);
/* else COR=1 means read sufficed.
/*
* else COR=1 means read sufficed.
* (for most SIH modules...)
*/
}
......@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
static inline void activate_irq(int irq)
{
#ifdef CONFIG_ARM
/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
/*
* ARM requires an extra step to clear IRQ_NOREQUEST, which it
* sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
*/
set_irq_flags(irq, IRQF_VALID);
......@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
return IRQ_HANDLED;
}
static unsigned twl4030_irq_next;
/* returns the first IRQ used by this SIH bank,
* or negative errno
*/
int twl4030_sih_setup(int module)
/* returns the first IRQ used by this SIH bank, or negative errno */
int twl4030_sih_setup(struct device *dev, int module, int irq_base)
{
int sih_mod;
const struct sih *sih = NULL;
struct sih_agent *agent;
int i, irq;
int status = -EINVAL;
unsigned irq_base = twl4030_irq_next;
/* only support modules with standard clear-on-read for now */
for (sih_mod = 0, sih = sih_modules;
sih_mod < nr_sih_modules;
for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
sih_mod++, sih++) {
if (sih->module == module && sih->set_cor) {
if (!WARN((irq_base + sih->bits) > NR_IRQS,
"irq %d for %s too big\n",
irq_base + sih->bits,
sih->name))
status = 0;
status = 0;
break;
}
}
if (status < 0)
return status;
......@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
if (!agent)
return -ENOMEM;
status = 0;
agent->irq_base = irq_base;
agent->sih = sih;
agent->imr = ~0;
......@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
activate_irq(irq);
}
twl4030_irq_next += i;
/* replace generic PIH handler (handle_simple_irq) */
irq = sih_mod + twl4030_irq_base;
irq_set_handler_data(irq, agent);
......@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
agent->irq_name ?: sih->name, NULL);
pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
irq, irq_base, twl4030_irq_next - 1);
dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
irq, irq_base, irq_base + i - 1);
return status < 0 ? status : irq_base;
}
/* FIXME need a call to reverse twl4030_sih_setup() ... */
/*----------------------------------------------------------------------*/
/* FIXME pass in which interrupt line we'll use ... */
#define twl_irq_line 0
int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
int twl4030_init_irq(struct device *dev, int irq_num)
{
static struct irq_chip twl4030_irq_chip;
int status, i;
int irq_base, irq_end, nr_irqs;
struct device_node *node = dev->of_node;
int status;
int i;
/*
* TWL core and pwr interrupts must be contiguous because
* the hwirqs numbers are defined contiguously from 1 to 15.
* Create only one domain for both.
*/
nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
if (IS_ERR_VALUE(irq_base)) {
dev_err(dev, "Fail to allocate IRQ descs\n");
return irq_base;
}
irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
&irq_domain_simple_ops, NULL);
irq_end = irq_base + TWL4030_CORE_NR_IRQS;
/*
* Mask and clear all TWL4030 interrupts since initially we do
......@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
twl4030_irq_base = irq_base;
/* install an irq handler for each of the SIH modules;
/*
* Install an irq handler for each of the SIH modules;
* clone dummy irq_chip since PIH can't *do* anything
*/
twl4030_irq_chip = dummy_irq_chip;
......@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
irq_set_nested_thread(i, 1);
activate_irq(i);
}
twl4030_irq_next = i;
pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
irq_num, irq_base, twl4030_irq_next - 1);
dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
irq_num, irq_base, irq_end);
/* ... and the PWR_INT module ... */
status = twl4030_sih_setup(TWL4030_MODULE_INT);
status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
if (status < 0) {
pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
dev_err(dev, "sih_setup PWR INT --> %d\n", status);
goto fail;
}
......@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
IRQF_ONESHOT,
"TWL4030-PIH", NULL);
if (status < 0) {
pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
goto fail_rqirq;
}
return status;
return irq_base;
fail_rqirq:
/* clean up twl4030_sih_setup */
fail:
......
......@@ -39,6 +39,8 @@
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include "twl-core.h"
......@@ -51,8 +53,8 @@
*
* We set up IRQs starting at a platform-specified base. An interrupt map table,
* specifies mapping between interrupt number and the associated module.
*
*/
#define TWL6030_NR_IRQS 20
static int twl6030_interrupt_mapping[24] = {
PWR_INTR_OFFSET, /* Bit 0 PWRON */
......@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
}
local_irq_enable();
}
ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
REG_INT_STS_A, 3); /* clear INT_STS_A */
/*
* NOTE:
* Simulation confirms that documentation is wrong w.r.t the
* interrupt status clear operation. A single *byte* write to
* any one of STS_A to STS_C register results in all three
* STS registers being reset. Since it does not matter which
* value is written, all three registers are cleared on a
* single byte write, so we just use 0x0 to clear.
*/
ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
if (ret)
pr_warning("twl6030: I2C error in clearing PIH ISR\n");
......@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
#endif
}
int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
{
if (on)
atomic_inc(&twl6030_wakeirqs);
......@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
/*----------------------------------------------------------------------*/
static unsigned twl6030_irq_next;
/*----------------------------------------------------------------------*/
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
{
int ret;
......@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
ret);
return ret;
}
return 0;
return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
}
EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
......@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
}
EXPORT_SYMBOL(twl6030_mmc_card_detect);
int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
int twl6030_init_irq(struct device *dev, int irq_num)
{
int status = 0;
int i;
struct device_node *node = dev->of_node;
int nr_irqs, irq_base, irq_end;
struct task_struct *task;
int ret;
u8 mask[4];
static struct irq_chip twl6030_irq_chip;
int status = 0;
int i;
u8 mask[4];
nr_irqs = TWL6030_NR_IRQS;
irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
if (IS_ERR_VALUE(irq_base)) {
dev_err(dev, "Fail to allocate IRQ descs\n");
return irq_base;
}
irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
&irq_domain_simple_ops, NULL);
irq_end = irq_base + nr_irqs;
static struct irq_chip twl6030_irq_chip;
mask[1] = 0xFF;
mask[2] = 0xFF;
mask[3] = 0xFF;
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
/* mask all int lines */
twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
/* mask all int sts */
twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
/* clear INT_STS_A,B,C */
twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
twl6030_irq_base = irq_base;
/* install an irq handler for each of the modules;
/*
* install an irq handler for each of the modules;
* clone dummy irq_chip since PIH can't *do* anything
*/
twl6030_irq_chip = dummy_irq_chip;
......@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
activate_irq(i);
}
twl6030_irq_next = i;
pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
irq_num, irq_base, twl6030_irq_next - 1);
dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
irq_num, irq_base, irq_end);
/* install an irq handler to demultiplex the TWL6030 interrupt */
init_completion(&irq_event);
status = request_irq(irq_num, handle_twl6030_pih, 0,
"TWL6030-PIH", &irq_event);
status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
&irq_event);
if (status < 0) {
pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
goto fail_irq;
}
task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
if (IS_ERR(task)) {
pr_err("twl6030: could not create irq %d thread!\n", irq_num);
dev_err(dev, "could not create irq %d thread!\n", irq_num);
status = PTR_ERR(task);
goto fail_kthread;
}
twl_irq = irq_num;
register_pm_notifier(&twl6030_irq_pm_notifier_block);
return status;
return irq_base;
fail_kthread:
free_irq(irq_num, &irq_event);
......@@ -408,6 +429,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
fail_irq:
for (i = irq_base; i < irq_end; i++)
irq_set_chip_and_handler(i, NULL, NULL);
return status;
}
......
......@@ -89,7 +89,7 @@ static const struct spi_device_id wm831x_spi_ids[] = {
{ "wm8326", WM8326 },
{ },
};
MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
static struct spi_driver wm831x_spi_driver = {
.driver = {
......
......@@ -271,8 +271,7 @@ static int wm8400_init(struct wm8400 *wm8400,
return -EIO;
}
if (i != reg_data[WM8400_RESET_ID].default_val) {
dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
reg);
dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
return -ENODEV;
}
......
......@@ -639,7 +639,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
}
pm_runtime_enable(wm8994->dev);
pm_runtime_resume(wm8994->dev);
pm_runtime_idle(wm8994->dev);
return 0;
......
......@@ -20,7 +20,6 @@
#include "wm8994.h"
static struct reg_default wm1811_defaults[] = {
{ 0x0000, 0x1811 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
......@@ -61,7 +60,7 @@ static struct reg_default wm1811_defaults[] = {
{ 0x0036, 0x0000 }, /* R54 - Speaker Mixer */
{ 0x0037, 0x0000 }, /* R55 - Additional Control */
{ 0x0038, 0x0000 }, /* R56 - AntiPOP (1) */
{ 0x0039, 0x0180 }, /* R57 - AntiPOP (2) */
{ 0x0039, 0x0000 }, /* R57 - AntiPOP (2) */
{ 0x003B, 0x000D }, /* R59 - LDO 1 */
{ 0x003C, 0x0003 }, /* R60 - LDO 2 */
{ 0x003D, 0x0039 }, /* R61 - MICBIAS1 */
......@@ -69,16 +68,12 @@ static struct reg_default wm1811_defaults[] = {
{ 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
{ 0x004D, 0xAB19 }, /* R77 - Charge Pump (2) */
{ 0x0051, 0x0004 }, /* R81 - Class W (1) */
{ 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
{ 0x0055, 0x054A }, /* R85 - DC Servo (2) */
{ 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
{ 0x0059, 0x0000 }, /* R89 - DC Servo (4) */
{ 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
{ 0x00C5, 0x0000 }, /* R197 - Class D Test (5) */
{ 0x00D0, 0x7600 }, /* R208 - Mic Detect 1 */
{ 0x00D1, 0x007F }, /* R209 - Mic Detect 2 */
{ 0x00D2, 0x0000 }, /* R210 - Mic Detect 3 */
{ 0x0100, 0x0100 }, /* R256 - Chip Revision */
{ 0x0101, 0x8004 }, /* R257 - Control Interface */
{ 0x0200, 0x0000 }, /* R512 - AIF1 Clocking (1) */
{ 0x0201, 0x0000 }, /* R513 - AIF1 Clocking (2) */
......@@ -88,7 +83,6 @@ static struct reg_default wm1811_defaults[] = {
{ 0x0209, 0x0000 }, /* R521 - Clocking (2) */
{ 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
{ 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
{ 0x0212, 0x0000 }, /* R530 - Rate Status */
{ 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
{ 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
{ 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
......@@ -218,8 +212,6 @@ static struct reg_default wm1811_defaults[] = {
{ 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
{ 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
{ 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
{ 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
{ 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
{ 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
{ 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
{ 0x0739, 0xDFEF }, /* R1849 - Interrupt Status 2 Mask */
......@@ -228,7 +220,6 @@ static struct reg_default wm1811_defaults[] = {
};
static struct reg_default wm8994_defaults[] = {
{ 0x0000, 0x8994 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
......@@ -275,12 +266,9 @@ static struct reg_default wm8994_defaults[] = {
{ 0x003C, 0x0003 }, /* R60 - LDO 2 */
{ 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
{ 0x0051, 0x0004 }, /* R81 - Class W (1) */
{ 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
{ 0x0055, 0x054A }, /* R85 - DC Servo (2) */
{ 0x0057, 0x0000 }, /* R87 - DC Servo (4) */
{ 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
{ 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
{ 0x0100, 0x0003 }, /* R256 - Chip Revision */
{ 0x0101, 0x8004 }, /* R257 - Control Interface */
{ 0x0110, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
{ 0x0111, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
......@@ -292,7 +280,6 @@ static struct reg_default wm8994_defaults[] = {
{ 0x0209, 0x0000 }, /* R521 - Clocking (2) */
{ 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
{ 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
{ 0x0212, 0x0000 }, /* R530 - Rate Status */
{ 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
{ 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
{ 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
......@@ -445,9 +432,6 @@ static struct reg_default wm8994_defaults[] = {
{ 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
{ 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
{ 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
{ 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
{ 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
{ 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
{ 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
{ 0x0739, 0xFFFF }, /* R1849 - Interrupt Status 2 Mask */
{ 0x0740, 0x0000 }, /* R1856 - Interrupt Control */
......@@ -455,7 +439,6 @@ static struct reg_default wm8994_defaults[] = {
};
static struct reg_default wm8958_defaults[] = {
{ 0x0000, 0x8958 }, /* R0 - Software Reset */
{ 0x0001, 0x0000 }, /* R1 - Power Management (1) */
{ 0x0002, 0x6000 }, /* R2 - Power Management (2) */
{ 0x0003, 0x0000 }, /* R3 - Power Management (3) */
......@@ -970,6 +953,7 @@ static bool wm8994_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8994_DC_SERVO_READBACK:
case WM8994_MICBIAS:
case WM8994_WRITE_SEQUENCER_CTRL_1:
case WM8994_WRITE_SEQUENCER_CTRL_2:
case WM8994_AIF1_ADC2_LEFT_VOLUME:
......
......@@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
#endif /* VRTC_CALIBRATION */
device_init_wakeup(&pdev->dev, 1);
return 0;
out_rtc:
free_irq(info->irq, info);
......@@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pm860x_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
return 0;
}
static int pm860x_rtc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
static struct platform_driver pm860x_rtc_driver = {
.driver = {
.name = "88pm860x-rtc",
.owner = THIS_MODULE,
.pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
.remove = __devexit_p(pm860x_rtc_remove),
......
......@@ -67,6 +67,28 @@ static inline int wled_idc(int port)
return ret;
}
static int backlight_power_set(struct pm860x_chip *chip, int port,
int on)
{
int ret = -EINVAL;
switch (port) {
case PM8606_BACKLIGHT1:
ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
pm8606_osc_disable(chip, WLED1_DUTY);
break;
case PM8606_BACKLIGHT2:
ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
pm8606_osc_disable(chip, WLED2_DUTY);
break;
case PM8606_BACKLIGHT3:
ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
pm8606_osc_disable(chip, WLED3_DUTY);
break;
}
return ret;
}
static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
{
struct pm860x_backlight_data *data = bl_get_data(bl);
......@@ -79,6 +101,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
else
value = brightness;
if (brightness)
backlight_power_set(chip, data->port, 1);
ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
if (ret < 0)
goto out;
......@@ -115,6 +140,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
if (ret < 0)
goto out;
if (brightness == 0)
backlight_power_set(chip, data->port, 0);
dev_dbg(chip->dev, "set brightness %d\n", value);
data->current_brightness = value;
return 0;
......@@ -170,7 +198,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
struct backlight_device *bl;
struct resource *res;
struct backlight_properties props;
unsigned char value;
char name[MFD_NAME_SIZE];
int ret;
......@@ -217,26 +244,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bl);
/* Enable reference VSYS */
ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
if (ret < 0)
goto out;
if ((ret & PM8606_VSYS_EN) == 0) {
value = ret | PM8606_VSYS_EN;
ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
if (ret < 0)
goto out;
}
/* Enable reference OSC */
ret = pm860x_reg_read(data->i2c, PM8606_MISC);
if (ret < 0)
goto out;
if ((ret & PM8606_MISC_OSC_EN) == 0) {
value = ret | PM8606_MISC_OSC_EN;
ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
if (ret < 0)
goto out;
}
/* read current backlight */
ret = pm860x_backlight_get_brightness(bl);
if (ret < 0)
......
......@@ -761,7 +761,7 @@ struct twl_regulator_driver_data {
/*----------------------------------------------------------------------*/
int twl4030_sih_setup(int module);
int twl4030_sih_setup(struct device *dev, int module, int irq_base);
/* Offsets to Power Registers */
#define TWL4030_VDAC_DEV_GRP 0x3B
......
......@@ -263,6 +263,22 @@ enum {
#define PM8607_PD_PREBIAS_MASK (0x1F << 0)
#define PM8607_PD_PRECHG_MASK (7 << 5)
#define PM8606_REF_GP_OSC_OFF 0
#define PM8606_REF_GP_OSC_ON 1
#define PM8606_REF_GP_OSC_UNKNOWN 2
/* Clients of reference group and 8MHz oscillator in 88PM8606 */
enum pm8606_ref_gp_and_osc_clients {
REF_GP_NO_CLIENTS = 0,
WLED1_DUTY = (1<<0), /*PF 0x02.7:0*/
WLED2_DUTY = (1<<1), /*PF 0x04.7:0*/
WLED3_DUTY = (1<<2), /*PF 0x06.7:0*/
RGB1_ENABLE = (1<<3), /*PF 0x07.1*/
RGB2_ENABLE = (1<<4), /*PF 0x07.2*/
LDO_VBR_EN = (1<<5), /*PF 0x12.0*/
REF_GP_MAX_CLIENT = 0xFFFF
};
/* Interrupt Number in 88PM8607 */
enum {
PM8607_IRQ_ONKEY,
......@@ -298,6 +314,7 @@ enum {
struct pm860x_chip {
struct device *dev;
struct mutex irq_lock;
struct mutex osc_lock;
struct i2c_client *client;
struct i2c_client *companion; /* companion chip client */
struct regmap *regmap;
......@@ -305,12 +322,15 @@ struct pm860x_chip {
int buck3_double; /* DVC ramp slope double */
unsigned short companion_addr;
unsigned short osc_vote;
int id;
int irq_mode;
int irq_base;
int core_irq;
unsigned char chip_version;
unsigned char osc_status;
unsigned int wakeup_flag;
};
enum {
......@@ -369,6 +389,9 @@ struct pm860x_platform_data {
int num_regulators;
};
extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
extern int pm860x_reg_read(struct i2c_client *, int);
extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
......
......@@ -34,13 +34,6 @@ struct device;
#define AB5500_1_1 0x21
#define AB5500_2_0 0x24
/* AB8500 CIDs*/
#define AB8500_CUT1P0 0x10
#define AB8500_CUT1P1 0x11
#define AB8500_CUT2P0 0x20
#define AB8500_CUT3P0 0x30
#define AB8500_CUT3P3 0x33
/*
* AB3100, EVENTA1, A2 and A3 event register flags
* these are catenated into a single 32-bit flag in the code
......
......@@ -10,12 +10,14 @@
/*
* Platform data to register a block: only the initial gpio/irq number.
* Array sizes are large enough to contain all AB8500 and AB9540 GPIO
* registers.
*/
struct ab8500_gpio_platform_data {
int gpio_base;
u32 irq_base;
u8 config_reg[7];
u8 config_reg[8];
};
#endif /* _AB8500_GPIO_H */
......@@ -71,6 +71,13 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
#define AB8500_SWATCTRL 0x230
#define AB8500_HIQCLKCTRL 0x232
#define AB8500_VSIMSYSCLKCTRL 0x233
#define AB9540_SYSCLK12BUFCTRL 0x234
#define AB9540_SYSCLK12CONFCTRL 0x235
#define AB9540_SYSCLK12BUFCTRL2 0x236
#define AB9540_SYSCLK12BUF1VALID 0x237
#define AB9540_SYSCLK12BUF2VALID 0x238
#define AB9540_SYSCLK12BUF3VALID 0x239
#define AB9540_SYSCLK12BUF4VALID 0x23A
/* Bits */
#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
......@@ -251,4 +258,40 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1ENA BIT(0)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2ENA BIT(1)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3ENA BIT(2)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4ENA BIT(3)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFENA_MASK 0x0F
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1STRE BIT(4)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2STRE BIT(5)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3STRE BIT(6)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4STRE BIT(7)
#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFSTRE_MASK 0xF0
#define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)
#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF1PDENA BIT(0)
#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF2PDENA BIT(1)
#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF3PDENA BIT(2)
#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF4PDENA BIT(3)
#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_MASK 0xFF
#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_SHIFT 0
#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_MASK 0xFF
#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_SHIFT 0
#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_MASK 0xFF
#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_SHIFT 0
#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
#endif /* __AB8500_SYSCTRL_H */
......@@ -11,6 +11,29 @@
struct device;
/*
* AB IC versions
*
* AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
* non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
* print of version string.
*/
enum ab8500_version {
AB8500_VERSION_AB8500 = 0x0,
AB8500_VERSION_AB8505 = 0x1,
AB8500_VERSION_AB9540 = 0x2,
AB8500_VERSION_AB8540 = 0x3,
AB8500_VERSION_UNDEFINED,
};
/* AB8500 CIDs*/
#define AB8500_CUTEARLY 0x00
#define AB8500_CUT1P0 0x10
#define AB8500_CUT1P1 0x11
#define AB8500_CUT2P0 0x20
#define AB8500_CUT3P0 0x30
#define AB8500_CUT3P3 0x33
/*
* AB8500 bank addresses
*/
......@@ -37,30 +60,34 @@ struct device;
/*
* Interrupts
* Values used to index into array ab8500_irq_regoffset[] defined in
* drivers/mdf/ab8500-core.c
*/
#define AB8500_INT_MAIN_EXT_CH_NOT_OK 0
#define AB8500_INT_UN_PLUG_TV_DET 1
#define AB8500_INT_PLUG_TV_DET 2
/* Definitions for AB8500 and AB9540 */
/* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
#define AB8500_INT_MAIN_EXT_CH_NOT_OK 0 /* not 8505/9540 */
#define AB8500_INT_UN_PLUG_TV_DET 1 /* not 8505/9540 */
#define AB8500_INT_PLUG_TV_DET 2 /* not 8505/9540 */
#define AB8500_INT_TEMP_WARM 3
#define AB8500_INT_PON_KEY2DB_F 4
#define AB8500_INT_PON_KEY2DB_R 5
#define AB8500_INT_PON_KEY1DB_F 6
#define AB8500_INT_PON_KEY1DB_R 7
/* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
#define AB8500_INT_BATT_OVV 8
#define AB8500_INT_MAIN_CH_UNPLUG_DET 10
#define AB8500_INT_MAIN_CH_PLUG_DET 11
#define AB8500_INT_USB_ID_DET_F 12
#define AB8500_INT_USB_ID_DET_R 13
#define AB8500_INT_MAIN_CH_UNPLUG_DET 10 /* not 8505 */
#define AB8500_INT_MAIN_CH_PLUG_DET 11 /* not 8505 */
#define AB8500_INT_VBUS_DET_F 14
#define AB8500_INT_VBUS_DET_R 15
/* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
#define AB8500_INT_VBUS_CH_DROP_END 16
#define AB8500_INT_RTC_60S 17
#define AB8500_INT_RTC_ALARM 18
#define AB8500_INT_BAT_CTRL_INDB 20
#define AB8500_INT_CH_WD_EXP 21
#define AB8500_INT_VBUS_OVV 22
#define AB8500_INT_MAIN_CH_DROP_END 23
#define AB8500_INT_MAIN_CH_DROP_END 23 /* not 8505/9540 */
/* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
#define AB8500_INT_CCN_CONV_ACC 24
#define AB8500_INT_INT_AUD 25
#define AB8500_INT_CCEOC 26
......@@ -69,7 +96,8 @@ struct device;
#define AB8500_INT_LOW_BAT_R 29
#define AB8500_INT_BUP_CHG_NOT_OK 30
#define AB8500_INT_BUP_CHG_OK 31
#define AB8500_INT_GP_HW_ADC_CONV_END 32
/* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
#define AB8500_INT_GP_HW_ADC_CONV_END 32 /* not 8505 */
#define AB8500_INT_ACC_DETECT_1DB_F 33
#define AB8500_INT_ACC_DETECT_1DB_R 34
#define AB8500_INT_ACC_DETECT_22DB_F 35
......@@ -77,38 +105,43 @@ struct device;
#define AB8500_INT_ACC_DETECT_21DB_F 37
#define AB8500_INT_ACC_DETECT_21DB_R 38
#define AB8500_INT_GP_SW_ADC_CONV_END 39
#define AB8500_INT_GPIO6R 40
#define AB8500_INT_GPIO7R 41
#define AB8500_INT_GPIO8R 42
#define AB8500_INT_GPIO9R 43
/* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
#define AB8500_INT_GPIO6R 40 /* not 8505/9540 */
#define AB8500_INT_GPIO7R 41 /* not 8505/9540 */
#define AB8500_INT_GPIO8R 42 /* not 8505/9540 */
#define AB8500_INT_GPIO9R 43 /* not 8505/9540 */
#define AB8500_INT_GPIO10R 44
#define AB8500_INT_GPIO11R 45
#define AB8500_INT_GPIO12R 46
#define AB8500_INT_GPIO12R 46 /* not 8505 */
#define AB8500_INT_GPIO13R 47
#define AB8500_INT_GPIO24R 48
#define AB8500_INT_GPIO25R 49
#define AB8500_INT_GPIO36R 50
#define AB8500_INT_GPIO37R 51
#define AB8500_INT_GPIO38R 52
#define AB8500_INT_GPIO39R 53
/* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
#define AB8500_INT_GPIO24R 48 /* not 8505 */
#define AB8500_INT_GPIO25R 49 /* not 8505 */
#define AB8500_INT_GPIO36R 50 /* not 8505/9540 */
#define AB8500_INT_GPIO37R 51 /* not 8505/9540 */
#define AB8500_INT_GPIO38R 52 /* not 8505/9540 */
#define AB8500_INT_GPIO39R 53 /* not 8505/9540 */
#define AB8500_INT_GPIO40R 54
#define AB8500_INT_GPIO41R 55
#define AB8500_INT_GPIO6F 56
#define AB8500_INT_GPIO7F 57
#define AB8500_INT_GPIO8F 58
#define AB8500_INT_GPIO9F 59
/* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
#define AB8500_INT_GPIO6F 56 /* not 8505/9540 */
#define AB8500_INT_GPIO7F 57 /* not 8505/9540 */
#define AB8500_INT_GPIO8F 58 /* not 8505/9540 */
#define AB8500_INT_GPIO9F 59 /* not 8505/9540 */
#define AB8500_INT_GPIO10F 60
#define AB8500_INT_GPIO11F 61
#define AB8500_INT_GPIO12F 62
#define AB8500_INT_GPIO12F 62 /* not 8505 */
#define AB8500_INT_GPIO13F 63
#define AB8500_INT_GPIO24F 64
#define AB8500_INT_GPIO25F 65
#define AB8500_INT_GPIO36F 66
#define AB8500_INT_GPIO37F 67
#define AB8500_INT_GPIO38F 68
#define AB8500_INT_GPIO39F 69
/* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
#define AB8500_INT_GPIO24F 64 /* not 8505 */
#define AB8500_INT_GPIO25F 65 /* not 8505 */
#define AB8500_INT_GPIO36F 66 /* not 8505/9540 */
#define AB8500_INT_GPIO37F 67 /* not 8505/9540 */
#define AB8500_INT_GPIO38F 68 /* not 8505/9540 */
#define AB8500_INT_GPIO39F 69 /* not 8505/9540 */
#define AB8500_INT_GPIO40F 70
#define AB8500_INT_GPIO41F 71
/* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
#define AB8500_INT_ADP_SOURCE_ERROR 72
#define AB8500_INT_ADP_SINK_ERROR 73
#define AB8500_INT_ADP_PROBE_PLUG 74
......@@ -116,30 +149,67 @@ struct device;
#define AB8500_INT_ADP_SENSE_OFF 76
#define AB8500_INT_USB_PHY_POWER_ERR 78
#define AB8500_INT_USB_LINK_STATUS 79
/* ab8500_irq_regoffset[10] -> IT[Source|Latch|Mask]19 */
#define AB8500_INT_BTEMP_LOW 80
#define AB8500_INT_BTEMP_LOW_MEDIUM 81
#define AB8500_INT_BTEMP_MEDIUM_HIGH 82
#define AB8500_INT_BTEMP_HIGH 83
#define AB8500_INT_USB_CHARGER_NOT_OK 89
/* ab8500_irq_regoffset[11] -> IT[Source|Latch|Mask]20 */
#define AB8500_INT_SRP_DETECT 88
#define AB8500_INT_USB_CHARGER_NOT_OKR 89
#define AB8500_INT_ID_WAKEUP_R 90
#define AB8500_INT_ID_DET_R1R 92
#define AB8500_INT_ID_DET_R2R 93
#define AB8500_INT_ID_DET_R3R 94
#define AB8500_INT_ID_DET_R4R 95
/* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
#define AB8500_INT_ID_WAKEUP_F 96
#define AB8500_INT_ID_DET_R1F 98
#define AB8500_INT_ID_DET_R2F 99
#define AB8500_INT_ID_DET_R3F 100
#define AB8500_INT_ID_DET_R4F 101
#define AB8500_INT_USB_CHG_DET_DONE 102
#define AB8500_INT_CHAUTORESTARTAFTSEC 102
#define AB8500_INT_CHSTOPBYSEC 103
/* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
#define AB8500_INT_USB_CH_TH_PROT_F 104
#define AB8500_INT_USB_CH_TH_PROT_R 105
#define AB8500_INT_MAIN_CH_TH_PROT_F 106
#define AB8500_INT_MAIN_CH_TH_PROT_R 107
#define AB8500_INT_USB_CHARGER_NOT_OKF 111
#define AB8500_INT_MAIN_CH_TH_PROT_F 106 /* not 8505/9540 */
#define AB8500_INT_MAIN_CH_TH_PROT_R 107 /* not 8505/9540 */
#define AB8500_INT_CHCURLIMNOHSCHIRP 109
#define AB8500_INT_CHCURLIMHSCHIRP 110
#define AB8500_INT_XTAL32K_KO 111
/* Definitions for AB9540 */
/* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
#define AB9540_INT_GPIO50R 113
#define AB9540_INT_GPIO51R 114 /* not 8505 */
#define AB9540_INT_GPIO52R 115
#define AB9540_INT_GPIO53R 116
#define AB9540_INT_GPIO54R 117 /* not 8505 */
#define AB9540_INT_IEXT_CH_RF_BFN_R 118
#define AB9540_INT_IEXT_CH_RF_BFN_F 119
/* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
#define AB9540_INT_GPIO50F 121
#define AB9540_INT_GPIO51F 122 /* not 8505 */
#define AB9540_INT_GPIO52F 123
#define AB9540_INT_GPIO53F 124
#define AB9540_INT_GPIO54F 125 /* not 8505 */
/*
* AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
* entire platform. This is a "compile time" constant so this must be set to
* the largest possible value that may be encountered with different AB SOCs.
* Of the currently supported AB devices, AB8500 and AB9540, it is the AB9540
* which is larger.
*/
#define AB8500_NR_IRQS 112
#define AB8505_NR_IRQS 128
#define AB9540_NR_IRQS 128
/* This is set to the roof of any AB8500 chip variant IRQ counts */
#define AB8500_MAX_NR_IRQS AB9540_NR_IRQS
#define AB8500_NUM_IRQ_REGS 14
#define AB9540_NUM_IRQ_REGS 17
/**
* struct ab8500 - ab8500 internal structure
......@@ -147,13 +217,18 @@ struct device;
* @lock: read/write operations lock
* @irq_lock: genirq bus lock
* @irq: irq line
* @version: chip version id (e.g. ab8500 or ab9540)
* @chip_id: chip revision id
* @write: register write
* @write_masked: masked register write
* @read: register read
* @rx_buf: rx buf for SPI
* @tx_buf: tx buf for SPI
* @mask: cache of IRQ regs for bus lock
* @oldmask: cache of previous IRQ regs for bus lock
* @mask_size: Actual number of valid entries in mask[], oldmask[] and
* irq_reg_offset
* @irq_reg_offset: Array of offsets into IRQ registers
*/
struct ab8500 {
struct device *dev;
......@@ -162,16 +237,20 @@ struct ab8500 {
int irq_base;
int irq;
enum ab8500_version version;
u8 chip_id;
int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
int (*read) (struct ab8500 *a8500, u16 addr);
int (*write)(struct ab8500 *ab8500, u16 addr, u8 data);
int (*write_masked)(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data);
int (*read)(struct ab8500 *ab8500, u16 addr);
unsigned long tx_buf[4];
unsigned long rx_buf[4];
u8 mask[AB8500_NUM_IRQ_REGS];
u8 oldmask[AB8500_NUM_IRQ_REGS];
u8 *mask;
u8 *oldmask;
int mask_size;
const int *irq_reg_offset;
};
struct regulator_reg_init;
......@@ -197,7 +276,52 @@ struct ab8500_platform_data {
struct ab8500_gpio_platform_data *gpio;
};
extern int __devinit ab8500_init(struct ab8500 *ab8500);
extern int __devinit ab8500_init(struct ab8500 *ab8500,
enum ab8500_version version);
extern int __devexit ab8500_exit(struct ab8500 *ab8500);
static inline int is_ab8500(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB8500;
}
static inline int is_ab8505(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB8505;
}
static inline int is_ab9540(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB9540;
}
static inline int is_ab8540(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB8540;
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_2p0(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
}
#endif /* MFD_AB8500_H */
/*
* anatop.h - Anatop MFD driver
*
* Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
* Copyright (C) 2012 Linaro
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_MFD_ANATOP_H
#define __LINUX_MFD_ANATOP_H
#include <linux/spinlock.h>
/**
* anatop - MFD data
* @ioreg: ioremap register
* @reglock: spinlock for register read/write
*/
struct anatop {
void *ioreg;
spinlock_t reglock;
};
extern u32 anatop_get_bits(struct anatop *, u32, int, int);
extern void anatop_set_bits(struct anatop *, u32, int, int, u32);
#endif /* __LINUX_MFD_ANATOP_H */
......@@ -76,8 +76,6 @@ enum da9052_chip_id {
struct da9052_pdata;
struct da9052 {
struct mutex io_lock;
struct device *dev;
struct regmap *regmap;
......
......@@ -11,6 +11,24 @@
#define __MFD_DB8500_PRCMU_H
#include <linux/interrupt.h>
#include <linux/bitops.h>
/*
* Registers
*/
#define DB8500_PRCM_GPIOCR 0x138
#define DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0 BIT(0)
#define DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD BIT(9)
#define DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 BIT(11)
#define DB8500_PRCM_GPIOCR_SPI2_SELECT BIT(23)
#define DB8500_PRCM_LINE_VALUE 0x170
#define DB8500_PRCM_LINE_VALUE_HSI_CAWAKE0 BIT(3)
#define DB8500_PRCM_DSI_SW_RESET 0x324
#define DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN BIT(0)
#define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
#define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
/* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
......@@ -421,40 +439,22 @@ enum auto_enable {
/* End of file previously known as prcmu-fw-defs_v1.h */
/**
* enum hw_acc_dev - enum for hw accelerators
* @HW_ACC_SVAMMDSP: for SVAMMDSP
* @HW_ACC_SVAPIPE: for SVAPIPE
* @HW_ACC_SIAMMDSP: for SIAMMDSP
* @HW_ACC_SIAPIPE: for SIAPIPE
* @HW_ACC_SGA: for SGA
* @HW_ACC_B2R2: for B2R2
* @HW_ACC_MCDE: for MCDE
* @HW_ACC_ESRAM1: for ESRAM1
* @HW_ACC_ESRAM2: for ESRAM2
* @HW_ACC_ESRAM3: for ESRAM3
* @HW_ACC_ESRAM4: for ESRAM4
* @NUM_HW_ACC: number of hardware accelerators
*
* Different hw accelerators which can be turned ON/
* OFF or put into retention (MMDSPs and ESRAMs).
* Used with EPOD API.
* enum prcmu_power_status - results from set_power_state
* @PRCMU_SLEEP_OK: Sleep went ok
* @PRCMU_DEEP_SLEEP_OK: DeepSleep went ok
* @PRCMU_IDLE_OK: Idle went ok
* @PRCMU_DEEPIDLE_OK: DeepIdle went ok
* @PRCMU_PRCMU2ARMPENDINGIT_ER: Pending interrupt detected
* @PRCMU_ARMPENDINGIT_ER: Pending interrupt detected
*
* NOTE! Deprecated, to be removed when all users switched over to use the
* regulator API.
*/
enum hw_acc_dev {
HW_ACC_SVAMMDSP,
HW_ACC_SVAPIPE,
HW_ACC_SIAMMDSP,
HW_ACC_SIAPIPE,
HW_ACC_SGA,
HW_ACC_B2R2,
HW_ACC_MCDE,
HW_ACC_ESRAM1,
HW_ACC_ESRAM2,
HW_ACC_ESRAM3,
HW_ACC_ESRAM4,
NUM_HW_ACC
enum prcmu_power_status {
PRCMU_SLEEP_OK = 0xf3,
PRCMU_DEEP_SLEEP_OK = 0xf6,
PRCMU_IDLE_OK = 0xf0,
PRCMU_DEEPIDLE_OK = 0xe3,
PRCMU_PRCMU2ARMPENDINGIT_ER = 0x91,
PRCMU_ARMPENDINGIT_ER = 0x93,
};
/*
......@@ -493,6 +493,20 @@ struct prcmu_auto_pm_config {
u8 sva_policy;
};
#define PRCMU_FW_PROJECT_U8500 2
#define PRCMU_FW_PROJECT_U9500 4
#define PRCMU_FW_PROJECT_U8500_C2 7
#define PRCMU_FW_PROJECT_U9500_C2 11
#define PRCMU_FW_PROJECT_U8520 13
#define PRCMU_FW_PROJECT_U8420 14
struct prcmu_fw_version {
u8 project;
u8 api_version;
u8 func_version;
u8 errata;
};
#ifdef CONFIG_MFD_DB8500_PRCMU
void db8500_prcmu_early_init(void);
......@@ -500,42 +514,41 @@ int prcmu_set_rc_a2p(enum romcode_write);
enum romcode_read prcmu_get_rc_p2a(void);
enum ap_pwrst prcmu_get_xp70_current_state(void);
bool prcmu_has_arm_maxopp(void);
bool prcmu_is_u8400(void);
int prcmu_set_ape_opp(u8 opp);
int prcmu_get_ape_opp(void);
struct prcmu_fw_version *prcmu_get_fw_version(void);
int prcmu_request_ape_opp_100_voltage(bool enable);
int prcmu_release_usb_wakeup_state(void);
int prcmu_set_ddr_opp(u8 opp);
int prcmu_get_ddr_opp(void);
/* NOTE! Use regulator framework instead */
int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle);
bool prcmu_is_auto_pm_enabled(void);
int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
int prcmu_set_clock_divider(u8 clock, u8 divider);
int prcmu_config_hotdog(u8 threshold);
int prcmu_config_hotmon(u8 low, u8 high);
int prcmu_start_temp_sense(u16 cycles32k);
int prcmu_stop_temp_sense(void);
int db8500_prcmu_config_hotdog(u8 threshold);
int db8500_prcmu_config_hotmon(u8 low, u8 high);
int db8500_prcmu_start_temp_sense(u16 cycles32k);
int db8500_prcmu_stop_temp_sense(void);
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
void prcmu_ac_wake_req(void);
void prcmu_ac_sleep_req(void);
void prcmu_modem_reset(void);
void prcmu_enable_spi2(void);
void prcmu_disable_spi2(void);
void db8500_prcmu_modem_reset(void);
int prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
int prcmu_enable_a9wdog(u8 id);
int prcmu_disable_a9wdog(u8 id);
int prcmu_kick_a9wdog(u8 id);
int prcmu_load_a9wdog(u8 id, u32 val);
int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
int db8500_prcmu_enable_a9wdog(u8 id);
int db8500_prcmu_disable_a9wdog(u8 id);
int db8500_prcmu_kick_a9wdog(u8 id);
int db8500_prcmu_load_a9wdog(u8 id, u32 val);
void db8500_prcmu_system_reset(u16 reset_code);
int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
u8 db8500_prcmu_get_power_state_result(void);
int db8500_prcmu_gic_decouple(void);
int db8500_prcmu_gic_recouple(void);
int db8500_prcmu_copy_gic_settings(void);
bool db8500_prcmu_gic_pending_irq(void);
bool db8500_prcmu_pending_irq(void);
bool db8500_prcmu_is_cpu_in_wfi(int cpu);
void db8500_prcmu_enable_wakeups(u32 wakeups);
int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
int db8500_prcmu_request_clock(u8 clock, bool enable);
......@@ -549,6 +562,14 @@ u16 db8500_prcmu_get_reset_code(void);
bool db8500_prcmu_is_ac_wake_requested(void);
int db8500_prcmu_set_arm_opp(u8 opp);
int db8500_prcmu_get_arm_opp(void);
int db8500_prcmu_set_ape_opp(u8 opp);
int db8500_prcmu_get_ape_opp(void);
int db8500_prcmu_set_ddr_opp(u8 opp);
int db8500_prcmu_get_ddr_opp(void);
u32 db8500_prcmu_read(unsigned int reg);
void db8500_prcmu_write(unsigned int reg, u32 value);
void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value);
#else /* !CONFIG_MFD_DB8500_PRCMU */
......@@ -574,17 +595,17 @@ static inline bool prcmu_has_arm_maxopp(void)
return false;
}
static inline bool prcmu_is_u8400(void)
static inline struct prcmu_fw_version *prcmu_get_fw_version(void)
{
return false;
return NULL;
}
static inline int prcmu_set_ape_opp(u8 opp)
static inline int db8500_prcmu_set_ape_opp(u8 opp)
{
return 0;
}
static inline int prcmu_get_ape_opp(void)
static inline int db8500_prcmu_get_ape_opp(void)
{
return APE_100_OPP;
}
......@@ -599,21 +620,16 @@ static inline int prcmu_release_usb_wakeup_state(void)
return 0;
}
static inline int prcmu_set_ddr_opp(u8 opp)
static inline int db8500_prcmu_set_ddr_opp(u8 opp)
{
return 0;
}
static inline int prcmu_get_ddr_opp(void)
static inline int db8500_prcmu_get_ddr_opp(void)
{
return DDR_100_OPP;
}
static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
{
return 0;
}
static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle)
{
......@@ -634,22 +650,22 @@ static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
return 0;
}
static inline int prcmu_config_hotdog(u8 threshold)
static inline int db8500_prcmu_config_hotdog(u8 threshold)
{
return 0;
}
static inline int prcmu_config_hotmon(u8 low, u8 high)
static inline int db8500_prcmu_config_hotmon(u8 low, u8 high)
{
return 0;
}
static inline int prcmu_start_temp_sense(u16 cycles32k)
static inline int db8500_prcmu_start_temp_sense(u16 cycles32k)
{
return 0;
}
static inline int prcmu_stop_temp_sense(void)
static inline int db8500_prcmu_stop_temp_sense(void)
{
return 0;
}
......@@ -668,22 +684,17 @@ static inline void prcmu_ac_wake_req(void) {}
static inline void prcmu_ac_sleep_req(void) {}
static inline void prcmu_modem_reset(void) {}
static inline void db8500_prcmu_modem_reset(void) {}
static inline int prcmu_enable_spi2(void)
{
return 0;
}
static inline void db8500_prcmu_system_reset(u16 reset_code) {}
static inline int prcmu_disable_spi2(void)
static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
{
return 0;
}
static inline void db8500_prcmu_system_reset(u16 reset_code) {}
static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
static inline u8 db8500_prcmu_get_power_state_result(void)
{
return 0;
}
......@@ -729,27 +740,27 @@ static inline u16 db8500_prcmu_get_reset_code(void)
return 0;
}
static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
static inline int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
return 0;
}
static inline int prcmu_enable_a9wdog(u8 id)
static inline int db8500_prcmu_enable_a9wdog(u8 id)
{
return 0;
}
static inline int prcmu_disable_a9wdog(u8 id)
static inline int db8500_prcmu_disable_a9wdog(u8 id)
{
return 0;
}
static inline int prcmu_kick_a9wdog(u8 id)
static inline int db8500_prcmu_kick_a9wdog(u8 id)
{
return 0;
}
static inline int prcmu_load_a9wdog(u8 id, u32 val)
static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val)
{
return 0;
}
......@@ -769,6 +780,16 @@ static inline int db8500_prcmu_get_arm_opp(void)
return 0;
}
static inline u32 db8500_prcmu_read(unsigned int reg)
{
return 0;
}
static inline void db8500_prcmu_write(unsigned int reg, u32 value) {}
static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
u32 value) {}
#endif /* !CONFIG_MFD_DB8500_PRCMU */
#endif /* __MFD_DB8500_PRCMU_H */
......@@ -10,7 +10,7 @@
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <asm/mach-types.h>
#include <linux/err.h>
/* PRCMU Wakeup defines */
enum prcmu_wakeup_index {
......@@ -80,6 +80,29 @@ enum prcmu_wakeup_index {
#define EPOD_STATE_ON_CLK_OFF 0x03
#define EPOD_STATE_ON 0x04
/* DB5500 CLKOUT IDs */
enum {
DB5500_CLKOUT0 = 0,
DB5500_CLKOUT1,
};
/* DB5500 CLKOUTx sources */
enum {
DB5500_CLKOUT_REF_CLK_SEL0,
DB5500_CLKOUT_RTC_CLK0_SEL0,
DB5500_CLKOUT_ULP_CLK_SEL0,
DB5500_CLKOUT_STATIC0,
DB5500_CLKOUT_REFCLK,
DB5500_CLKOUT_ULPCLK,
DB5500_CLKOUT_ARMCLK,
DB5500_CLKOUT_SYSACC0CLK,
DB5500_CLKOUT_SOC0PLLCLK,
DB5500_CLKOUT_SOC1PLLCLK,
DB5500_CLKOUT_DDRPLLCLK,
DB5500_CLKOUT_TVCLK,
DB5500_CLKOUT_IRDACLK,
};
/*
* CLKOUT sources
*/
......@@ -111,6 +134,7 @@ enum prcmu_clock {
PRCMU_MSP1CLK,
PRCMU_I2CCLK,
PRCMU_SDMMCCLK,
PRCMU_SPARE1CLK,
PRCMU_SLIMCLK,
PRCMU_PER1CLK,
PRCMU_PER2CLK,
......@@ -139,12 +163,20 @@ enum prcmu_clock {
PRCMU_IRRCCLK,
PRCMU_SIACLK,
PRCMU_SVACLK,
PRCMU_ACLK,
PRCMU_NUM_REG_CLOCKS,
PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
PRCMU_CDCLK,
PRCMU_TIMCLK,
PRCMU_PLLSOC0,
PRCMU_PLLSOC1,
PRCMU_PLLDDR,
PRCMU_PLLDSI,
PRCMU_DSI0CLK,
PRCMU_DSI1CLK,
PRCMU_DSI0ESCCLK,
PRCMU_DSI1ESCCLK,
PRCMU_DSI2ESCCLK,
};
/**
......@@ -153,12 +185,14 @@ enum prcmu_clock {
* @APE_NO_CHANGE: The APE operating point is unchanged
* @APE_100_OPP: The new APE operating point is ape100opp
* @APE_50_OPP: 50%
* @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
*/
enum ape_opp {
APE_OPP_INIT = 0x00,
APE_NO_CHANGE = 0x01,
APE_100_OPP = 0x02,
APE_50_OPP = 0x03
APE_50_OPP = 0x03,
APE_50_PARTLY_25_OPP = 0xFF,
};
/**
......@@ -218,9 +252,11 @@ enum ddr_pwrst {
#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
#include <mach/id.h>
static inline void __init prcmu_early_init(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_early_init();
else
return db8500_prcmu_early_init();
......@@ -229,7 +265,7 @@ static inline void __init prcmu_early_init(void)
static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_set_power_state(state, keep_ulp_clk,
keep_ap_pll);
else
......@@ -237,9 +273,65 @@ static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
keep_ap_pll);
}
static inline u8 prcmu_get_power_state_result(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_get_power_state_result();
}
static inline int prcmu_gic_decouple(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_gic_decouple();
}
static inline int prcmu_gic_recouple(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_gic_recouple();
}
static inline bool prcmu_gic_pending_irq(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_gic_pending_irq();
}
static inline bool prcmu_is_cpu_in_wfi(int cpu)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_is_cpu_in_wfi(cpu);
}
static inline int prcmu_copy_gic_settings(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_copy_gic_settings();
}
static inline bool prcmu_pending_irq(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_pending_irq();
}
static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_set_epod(epod_id, epod_state);
......@@ -247,7 +339,7 @@ static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
static inline void prcmu_enable_wakeups(u32 wakeups)
{
if (machine_is_u5500())
if (cpu_is_u5500())
db5500_prcmu_enable_wakeups(wakeups);
else
db8500_prcmu_enable_wakeups(wakeups);
......@@ -260,7 +352,7 @@ static inline void prcmu_disable_wakeups(void)
static inline void prcmu_config_abb_event_readout(u32 abb_events)
{
if (machine_is_u5500())
if (cpu_is_u5500())
db5500_prcmu_config_abb_event_readout(abb_events);
else
db8500_prcmu_config_abb_event_readout(abb_events);
......@@ -268,7 +360,7 @@ static inline void prcmu_config_abb_event_readout(u32 abb_events)
static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
{
if (machine_is_u5500())
if (cpu_is_u5500())
db5500_prcmu_get_abb_event_buffer(buf);
else
db8500_prcmu_get_abb_event_buffer(buf);
......@@ -276,25 +368,40 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
static inline int prcmu_request_clock(u8 clock, bool enable)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_request_clock(clock, enable);
else
return db8500_prcmu_request_clock(clock, enable);
}
int prcmu_set_ape_opp(u8 opp);
int prcmu_get_ape_opp(void);
int prcmu_set_ddr_opp(u8 opp);
int prcmu_get_ddr_opp(void);
unsigned long prcmu_clock_rate(u8 clock);
long prcmu_round_clock_rate(u8 clock, unsigned long rate);
int prcmu_set_clock_rate(u8 clock, unsigned long rate);
static inline int prcmu_set_ddr_opp(u8 opp)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_set_ddr_opp(opp);
}
static inline int prcmu_get_ddr_opp(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_get_ddr_opp();
}
static inline int prcmu_set_arm_opp(u8 opp)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_set_arm_opp(opp);
......@@ -302,15 +409,31 @@ static inline int prcmu_set_arm_opp(u8 opp)
static inline int prcmu_get_arm_opp(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_get_arm_opp();
}
static inline int prcmu_set_ape_opp(u8 opp)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_set_ape_opp(opp);
}
static inline int prcmu_get_ape_opp(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_get_ape_opp();
}
static inline void prcmu_system_reset(u16 reset_code)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_system_reset(reset_code);
else
return db8500_prcmu_system_reset(reset_code);
......@@ -318,7 +441,7 @@ static inline void prcmu_system_reset(u16 reset_code)
static inline u16 prcmu_get_reset_code(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_get_reset_code();
else
return db8500_prcmu_get_reset_code();
......@@ -326,10 +449,17 @@ static inline u16 prcmu_get_reset_code(void)
void prcmu_ac_wake_req(void);
void prcmu_ac_sleep_req(void);
void prcmu_modem_reset(void);
static inline void prcmu_modem_reset(void)
{
if (cpu_is_u5500())
return;
else
return db8500_prcmu_modem_reset();
}
static inline bool prcmu_is_ac_wake_requested(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_is_ac_wake_requested();
else
return db8500_prcmu_is_ac_wake_requested();
......@@ -337,7 +467,7 @@ static inline bool prcmu_is_ac_wake_requested(void)
static inline int prcmu_set_display_clocks(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_set_display_clocks();
else
return db8500_prcmu_set_display_clocks();
......@@ -345,7 +475,7 @@ static inline int prcmu_set_display_clocks(void)
static inline int prcmu_disable_dsipll(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_disable_dsipll();
else
return db8500_prcmu_disable_dsipll();
......@@ -353,7 +483,7 @@ static inline int prcmu_disable_dsipll(void)
static inline int prcmu_enable_dsipll(void)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return db5500_prcmu_enable_dsipll();
else
return db8500_prcmu_enable_dsipll();
......@@ -361,11 +491,107 @@ static inline int prcmu_enable_dsipll(void)
static inline int prcmu_config_esram0_deep_sleep(u8 state)
{
if (machine_is_u5500())
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_config_esram0_deep_sleep(state);
}
static inline int prcmu_config_hotdog(u8 threshold)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_config_hotdog(threshold);
}
static inline int prcmu_config_hotmon(u8 low, u8 high)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_config_hotmon(low, high);
}
static inline int prcmu_start_temp_sense(u16 cycles32k)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_start_temp_sense(cycles32k);
}
static inline int prcmu_stop_temp_sense(void)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_stop_temp_sense();
}
static inline u32 prcmu_read(unsigned int reg)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_read(reg);
}
static inline void prcmu_write(unsigned int reg, u32 value)
{
if (cpu_is_u5500())
return;
else
db8500_prcmu_write(reg, value);
}
static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
{
if (cpu_is_u5500())
return;
else
db8500_prcmu_write_masked(reg, mask, value);
}
static inline int prcmu_enable_a9wdog(u8 id)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_enable_a9wdog(id);
}
static inline int prcmu_disable_a9wdog(u8 id)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_disable_a9wdog(id);
}
static inline int prcmu_kick_a9wdog(u8 id)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_kick_a9wdog(id);
}
static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_load_a9wdog(id, timeout);
}
static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
if (cpu_is_u5500())
return -EINVAL;
else
return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
}
#else
static inline void __init prcmu_early_init(void) {}
......@@ -395,6 +621,12 @@ static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
return -ENOSYS;
}
static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
u8 size)
{
return -ENOSYS;
}
static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
{
return 0;
......@@ -405,6 +637,21 @@ static inline int prcmu_request_clock(u8 clock, bool enable)
return 0;
}
static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
{
return 0;
}
static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
{
return 0;
}
static inline unsigned long prcmu_clock_rate(u8 clock)
{
return 0;
}
static inline int prcmu_set_ape_opp(u8 opp)
{
return 0;
......@@ -480,14 +727,133 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
*buf = NULL;
}
static inline int prcmu_config_hotdog(u8 threshold)
{
return 0;
}
static inline int prcmu_config_hotmon(u8 low, u8 high)
{
return 0;
}
static inline int prcmu_start_temp_sense(u16 cycles32k)
{
return 0;
}
static inline int prcmu_stop_temp_sense(void)
{
return 0;
}
static inline u32 prcmu_read(unsigned int reg)
{
return 0;
}
static inline void prcmu_write(unsigned int reg, u32 value) {}
static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
#endif
static inline void prcmu_set(unsigned int reg, u32 bits)
{
prcmu_write_masked(reg, bits, bits);
}
static inline void prcmu_clear(unsigned int reg, u32 bits)
{
prcmu_write_masked(reg, bits, 0);
}
#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
/**
* prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
*/
static inline void prcmu_enable_spi2(void)
{
if (cpu_is_u8500())
prcmu_set(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
}
/**
* prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
*/
static inline void prcmu_disable_spi2(void)
{
if (cpu_is_u8500())
prcmu_clear(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
}
/**
* prcmu_enable_stm_mod_uart - Enables pin muxing for STMMOD
* and UARTMOD on OtherAlternateC3.
*/
static inline void prcmu_enable_stm_mod_uart(void)
{
if (cpu_is_u8500()) {
prcmu_set(DB8500_PRCM_GPIOCR,
(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
}
}
/**
* prcmu_disable_stm_mod_uart - Disables pin muxing for STMMOD
* and UARTMOD on OtherAlternateC3.
*/
static inline void prcmu_disable_stm_mod_uart(void)
{
if (cpu_is_u8500()) {
prcmu_clear(DB8500_PRCM_GPIOCR,
(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
}
}
/**
* prcmu_enable_stm_ape - Enables pin muxing for STM APE on OtherAlternateC1.
*/
static inline void prcmu_enable_stm_ape(void)
{
if (cpu_is_u8500()) {
prcmu_set(DB8500_PRCM_GPIOCR,
DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
}
}
/**
* prcmu_disable_stm_ape - Disables pin muxing for STM APE on OtherAlternateC1.
*/
static inline void prcmu_disable_stm_ape(void)
{
if (cpu_is_u8500()) {
prcmu_clear(DB8500_PRCM_GPIOCR,
DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
}
}
#else
static inline void prcmu_enable_spi2(void) {}
static inline void prcmu_disable_spi2(void) {}
static inline void prcmu_enable_stm_mod_uart(void) {}
static inline void prcmu_disable_stm_mod_uart(void) {}
static inline void prcmu_enable_stm_ape(void) {}
static inline void prcmu_disable_stm_ape(void) {}
#endif
/* PRCMU QoS APE OPP class */
#define PRCMU_QOS_APE_OPP 1
#define PRCMU_QOS_DDR_OPP 2
#define PRCMU_QOS_ARM_OPP 3
#define PRCMU_QOS_DEFAULT_VALUE -1
#ifdef CONFIG_UX500_PRCMU_QOS_POWER
#ifdef CONFIG_DBX500_PRCMU_QOS_POWER
unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
......
......@@ -38,7 +38,8 @@ int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq);
int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
unsigned int mode, unsigned int channel, unsigned int *sample);
unsigned int mode, unsigned int channel,
u8 ato, bool atox, unsigned int *sample);
#define MC13XXX_IRQ_ADCDONE 0
#define MC13XXX_IRQ_ADCBISDONE 1
......@@ -157,6 +158,18 @@ struct mc13xxx_buttons_platform_data {
unsigned short b3on_key;
};
struct mc13xxx_ts_platform_data {
/* Delay between Touchscreen polarization and ADC Conversion.
* Given in clock ticks of a 32 kHz clock which gives a granularity of
* about 30.5ms */
u8 ato;
#define MC13783_TS_ATO_FIRST false
#define MC13783_TS_ATO_EACH true
/* Use the ATO delay only for the first conversion or for each one */
bool atox;
};
struct mc13xxx_platform_data {
#define MC13XXX_USE_TOUCHSCREEN (1 << 0)
#define MC13XXX_USE_CODEC (1 << 1)
......@@ -167,6 +180,7 @@ struct mc13xxx_platform_data {
struct mc13xxx_regulator_platform_data regulators;
struct mc13xxx_leds_platform_data *leds;
struct mc13xxx_buttons_platform_data *buttons;
struct mc13xxx_ts_platform_data touch;
};
#define MC13XXX_ADC_MODE_TS 1
......
/*
* Core driver interface to access RICOH_RC5T583 power management chip.
*
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
* Author: Laxman dewangan <ldewangan@nvidia.com>
*
* Based on code
* Copyright (C) 2011 RICOH COMPANY,LTD
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __LINUX_MFD_RC5T583_H
#define __LINUX_MFD_RC5T583_H
#include <linux/mutex.h>
#include <linux/types.h>
#define RC5T583_MAX_REGS 0xF8
/* Maximum number of main interrupts */
#define MAX_MAIN_INTERRUPT 5
#define RC5T583_MAX_GPEDGE_REG 2
#define RC5T583_MAX_INTERRUPT_MASK_REGS 9
/* Interrupt enable register */
#define RC5T583_INT_EN_SYS1 0x19
#define RC5T583_INT_EN_SYS2 0x1D
#define RC5T583_INT_EN_DCDC 0x41
#define RC5T583_INT_EN_RTC 0xED
#define RC5T583_INT_EN_ADC1 0x90
#define RC5T583_INT_EN_ADC2 0x91
#define RC5T583_INT_EN_ADC3 0x92
/* Interrupt status registers (monitor regs in Ricoh)*/
#define RC5T583_INTC_INTPOL 0xAD
#define RC5T583_INTC_INTEN 0xAE
#define RC5T583_INTC_INTMON 0xAF
#define RC5T583_INT_MON_GRP 0xAF
#define RC5T583_INT_MON_SYS1 0x1B
#define RC5T583_INT_MON_SYS2 0x1F
#define RC5T583_INT_MON_DCDC 0x43
#define RC5T583_INT_MON_RTC 0xEE
/* Interrupt clearing registers */
#define RC5T583_INT_IR_SYS1 0x1A
#define RC5T583_INT_IR_SYS2 0x1E
#define RC5T583_INT_IR_DCDC 0x42
#define RC5T583_INT_IR_RTC 0xEE
#define RC5T583_INT_IR_ADCL 0x94
#define RC5T583_INT_IR_ADCH 0x95
#define RC5T583_INT_IR_ADCEND 0x96
#define RC5T583_INT_IR_GPIOR 0xA9
#define RC5T583_INT_IR_GPIOF 0xAA
/* Sleep sequence registers */
#define RC5T583_SLPSEQ1 0x21
#define RC5T583_SLPSEQ2 0x22
#define RC5T583_SLPSEQ3 0x23
#define RC5T583_SLPSEQ4 0x24
#define RC5T583_SLPSEQ5 0x25
#define RC5T583_SLPSEQ6 0x26
#define RC5T583_SLPSEQ7 0x27
#define RC5T583_SLPSEQ8 0x28
#define RC5T583_SLPSEQ9 0x29
#define RC5T583_SLPSEQ10 0x2A
#define RC5T583_SLPSEQ11 0x2B
/* Regulator registers */
#define RC5T583_REG_DC0CTL 0x30
#define RC5T583_REG_DC0DAC 0x31
#define RC5T583_REG_DC0LATCTL 0x32
#define RC5T583_REG_SR0CTL 0x33
#define RC5T583_REG_DC1CTL 0x34
#define RC5T583_REG_DC1DAC 0x35
#define RC5T583_REG_DC1LATCTL 0x36
#define RC5T583_REG_SR1CTL 0x37
#define RC5T583_REG_DC2CTL 0x38
#define RC5T583_REG_DC2DAC 0x39
#define RC5T583_REG_DC2LATCTL 0x3A
#define RC5T583_REG_SR2CTL 0x3B
#define RC5T583_REG_DC3CTL 0x3C
#define RC5T583_REG_DC3DAC 0x3D
#define RC5T583_REG_DC3LATCTL 0x3E
#define RC5T583_REG_SR3CTL 0x3F
#define RC5T583_REG_LDOEN1 0x50
#define RC5T583_REG_LDOEN2 0x51
#define RC5T583_REG_LDODIS1 0x52
#define RC5T583_REG_LDODIS2 0x53
#define RC5T583_REG_LDO0DAC 0x54
#define RC5T583_REG_LDO1DAC 0x55
#define RC5T583_REG_LDO2DAC 0x56
#define RC5T583_REG_LDO3DAC 0x57
#define RC5T583_REG_LDO4DAC 0x58
#define RC5T583_REG_LDO5DAC 0x59
#define RC5T583_REG_LDO6DAC 0x5A
#define RC5T583_REG_LDO7DAC 0x5B
#define RC5T583_REG_LDO8DAC 0x5C
#define RC5T583_REG_LDO9DAC 0x5D
#define RC5T583_REG_DC0DAC_DS 0x60
#define RC5T583_REG_DC1DAC_DS 0x61
#define RC5T583_REG_DC2DAC_DS 0x62
#define RC5T583_REG_DC3DAC_DS 0x63
#define RC5T583_REG_LDO0DAC_DS 0x64
#define RC5T583_REG_LDO1DAC_DS 0x65
#define RC5T583_REG_LDO2DAC_DS 0x66
#define RC5T583_REG_LDO3DAC_DS 0x67
#define RC5T583_REG_LDO4DAC_DS 0x68
#define RC5T583_REG_LDO5DAC_DS 0x69
#define RC5T583_REG_LDO6DAC_DS 0x6A
#define RC5T583_REG_LDO7DAC_DS 0x6B
#define RC5T583_REG_LDO8DAC_DS 0x6C
#define RC5T583_REG_LDO9DAC_DS 0x6D
/* GPIO register base address */
#define RC5T583_GPIO_IOSEL 0xA0
#define RC5T583_GPIO_PDEN 0xA1
#define RC5T583_GPIO_IOOUT 0xA2
#define RC5T583_GPIO_PGSEL 0xA3
#define RC5T583_GPIO_GPINV 0xA4
#define RC5T583_GPIO_GPDEB 0xA5
#define RC5T583_GPIO_GPEDGE1 0xA6
#define RC5T583_GPIO_GPEDGE2 0xA7
#define RC5T583_GPIO_EN_INT 0xA8
#define RC5T583_GPIO_MON_IOIN 0xAB
#define RC5T583_GPIO_GPOFUNC 0xAC
/* RICOH_RC5T583 IRQ definitions */
enum {
RC5T583_IRQ_ONKEY,
RC5T583_IRQ_ACOK,
RC5T583_IRQ_LIDOPEN,
RC5T583_IRQ_PREOT,
RC5T583_IRQ_CLKSTP,
RC5T583_IRQ_ONKEY_OFF,
RC5T583_IRQ_WD,
RC5T583_IRQ_EN_PWRREQ1,
RC5T583_IRQ_EN_PWRREQ2,
RC5T583_IRQ_PRE_VINDET,
RC5T583_IRQ_DC0LIM,
RC5T583_IRQ_DC1LIM,
RC5T583_IRQ_DC2LIM,
RC5T583_IRQ_DC3LIM,
RC5T583_IRQ_CTC,
RC5T583_IRQ_YALE,
RC5T583_IRQ_DALE,
RC5T583_IRQ_WALE,
RC5T583_IRQ_AIN1L,
RC5T583_IRQ_AIN2L,
RC5T583_IRQ_AIN3L,
RC5T583_IRQ_VBATL,
RC5T583_IRQ_VIN3L,
RC5T583_IRQ_VIN8L,
RC5T583_IRQ_AIN1H,
RC5T583_IRQ_AIN2H,
RC5T583_IRQ_AIN3H,
RC5T583_IRQ_VBATH,
RC5T583_IRQ_VIN3H,
RC5T583_IRQ_VIN8H,
RC5T583_IRQ_ADCEND,
RC5T583_IRQ_GPIO0,
RC5T583_IRQ_GPIO1,
RC5T583_IRQ_GPIO2,
RC5T583_IRQ_GPIO3,
RC5T583_IRQ_GPIO4,
RC5T583_IRQ_GPIO5,
RC5T583_IRQ_GPIO6,
RC5T583_IRQ_GPIO7,
/* Should be last entry */
RC5T583_MAX_IRQS,
};
/* Ricoh583 gpio definitions */
enum {
RC5T583_GPIO0,
RC5T583_GPIO1,
RC5T583_GPIO2,
RC5T583_GPIO3,
RC5T583_GPIO4,
RC5T583_GPIO5,
RC5T583_GPIO6,
RC5T583_GPIO7,
/* Should be last entry */
RC5T583_MAX_GPIO,
};
enum {
RC5T583_DS_NONE,
RC5T583_DS_DC0,
RC5T583_DS_DC1,
RC5T583_DS_DC2,
RC5T583_DS_DC3,
RC5T583_DS_LDO0,
RC5T583_DS_LDO1,
RC5T583_DS_LDO2,
RC5T583_DS_LDO3,
RC5T583_DS_LDO4,
RC5T583_DS_LDO5,
RC5T583_DS_LDO6,
RC5T583_DS_LDO7,
RC5T583_DS_LDO8,
RC5T583_DS_LDO9,
RC5T583_DS_PSO0,
RC5T583_DS_PSO1,
RC5T583_DS_PSO2,
RC5T583_DS_PSO3,
RC5T583_DS_PSO4,
RC5T583_DS_PSO5,
RC5T583_DS_PSO6,
RC5T583_DS_PSO7,
/* Should be last entry */
RC5T583_DS_MAX,
};
/*
* Ricoh pmic RC5T583 supports sleep through two external controls.
* The output of gpios and regulator can be enable/disable through
* this external signals.
*/
enum {
RC5T583_EXT_PWRREQ1_CONTROL = 0x1,
RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
};
struct rc5t583 {
struct device *dev;
struct regmap *regmap;
int chip_irq;
int irq_base;
struct mutex irq_lock;
unsigned long group_irq_en[MAX_MAIN_INTERRUPT];
/* For main interrupt bits in INTC */
uint8_t intc_inten_reg;
/* For group interrupt bits and address */
uint8_t irq_en_reg[RC5T583_MAX_INTERRUPT_MASK_REGS];
/* For gpio edge */
uint8_t gpedge_reg[RC5T583_MAX_GPEDGE_REG];
};
/*
* rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
* The board specific data is provided through this structure.
* @irq_base: Irq base number on which this device registers their interrupts.
* @enable_shutdown: Enable shutdown through the input pin "shutdown".
*/
struct rc5t583_platform_data {
int irq_base;
bool enable_shutdown;
};
int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
int rc5t583_set_bits(struct device *dev, unsigned int reg,
unsigned int bit_mask);
int rc5t583_clear_bits(struct device *dev, unsigned int reg,
unsigned int bit_mask);
int rc5t583_update(struct device *dev, unsigned int reg,
unsigned int val, unsigned int mask);
int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
int ext_pwr_req, int deepsleep_slot_nr);
int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
int rc5t583_irq_exit(struct rc5t583 *rc5t583);
#endif
......@@ -28,6 +28,7 @@ enum stmpe_partnum {
STMPE1601,
STMPE2401,
STMPE2403,
STMPE_NBR_PARTS
};
/*
......
/*
* Core driver interface for TI TPS65090 PMIC family
*
* Copyright (C) 2012 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef __LINUX_MFD_TPS65090_H
#define __LINUX_MFD_TPS65090_H
struct tps65090_subdev_info {
int id;
const char *name;
void *platform_data;
};
struct tps65090_platform_data {
int irq_base;
int num_subdevs;
struct tps65090_subdev_info *subdevs;
};
/*
* NOTE: the functions below are not intended for use outside
* of the TPS65090 sub-device drivers
*/
extern int tps65090_write(struct device *dev, int reg, uint8_t val);
extern int tps65090_read(struct device *dev, int reg, uint8_t *val);
extern int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num);
extern int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num);
#endif /*__LINUX_MFD_TPS65090_H */
/*
* linux/mfd/tps65217.h
*
* Functions to access TPS65217 power management chip.
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LINUX_MFD_TPS65217_H
#define __LINUX_MFD_TPS65217_H
#include <linux/i2c.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
/* I2C ID for TPS65217 part */
#define TPS65217_I2C_ID 0x24
/* All register addresses */
#define TPS65217_REG_CHIPID 0X00
#define TPS65217_REG_PPATH 0X01
#define TPS65217_REG_INT 0X02
#define TPS65217_REG_CHGCONFIG0 0X03
#define TPS65217_REG_CHGCONFIG1 0X04
#define TPS65217_REG_CHGCONFIG2 0X05
#define TPS65217_REG_CHGCONFIG3 0X06
#define TPS65217_REG_WLEDCTRL1 0X07
#define TPS65217_REG_WLEDCTRL2 0X08
#define TPS65217_REG_MUXCTRL 0X09
#define TPS65217_REG_STATUS 0X0A
#define TPS65217_REG_PASSWORD 0X0B
#define TPS65217_REG_PGOOD 0X0C
#define TPS65217_REG_DEFPG 0X0D
#define TPS65217_REG_DEFDCDC1 0X0E
#define TPS65217_REG_DEFDCDC2 0X0F
#define TPS65217_REG_DEFDCDC3 0X10
#define TPS65217_REG_DEFSLEW 0X11
#define TPS65217_REG_DEFLDO1 0X12
#define TPS65217_REG_DEFLDO2 0X13
#define TPS65217_REG_DEFLS1 0X14
#define TPS65217_REG_DEFLS2 0X15
#define TPS65217_REG_ENABLE 0X16
#define TPS65217_REG_DEFUVLO 0X18
#define TPS65217_REG_SEQ1 0X19
#define TPS65217_REG_SEQ2 0X1A
#define TPS65217_REG_SEQ3 0X1B
#define TPS65217_REG_SEQ4 0X1C
#define TPS65217_REG_SEQ5 0X1D
#define TPS65217_REG_SEQ6 0X1E
/* Register field definitions */
#define TPS65217_CHIPID_CHIP_MASK 0xF0
#define TPS65217_CHIPID_REV_MASK 0x0F
#define TPS65217_PPATH_ACSINK_ENABLE BIT(7)
#define TPS65217_PPATH_USBSINK_ENABLE BIT(6)
#define TPS65217_PPATH_AC_PW_ENABLE BIT(5)
#define TPS65217_PPATH_USB_PW_ENABLE BIT(4)
#define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
#define TPS65217_PPATH_USB_CURRENT_MASK 0x03
#define TPS65217_INT_PBM BIT(6)
#define TPS65217_INT_ACM BIT(5)
#define TPS65217_INT_USBM BIT(4)
#define TPS65217_INT_PBI BIT(2)
#define TPS65217_INT_ACI BIT(1)
#define TPS65217_INT_USBI BIT(0)
#define TPS65217_CHGCONFIG0_TREG BIT(7)
#define TPS65217_CHGCONFIG0_DPPM BIT(6)
#define TPS65217_CHGCONFIG0_TSUSP BIT(5)
#define TPS65217_CHGCONFIG0_TERMI BIT(4)
#define TPS65217_CHGCONFIG0_ACTIVE BIT(3)
#define TPS65217_CHGCONFIG0_CHGTOUT BIT(2)
#define TPS65217_CHGCONFIG0_PCHGTOUT BIT(1)
#define TPS65217_CHGCONFIG0_BATTEMP BIT(0)
#define TPS65217_CHGCONFIG1_TMR_MASK 0xC0
#define TPS65217_CHGCONFIG1_TMR_ENABLE BIT(5)
#define TPS65217_CHGCONFIG1_NTC_TYPE BIT(4)
#define TPS65217_CHGCONFIG1_RESET BIT(3)
#define TPS65217_CHGCONFIG1_TERM BIT(2)
#define TPS65217_CHGCONFIG1_SUSP BIT(1)
#define TPS65217_CHGCONFIG1_CHG_EN BIT(0)
#define TPS65217_CHGCONFIG2_DYNTMR BIT(7)
#define TPS65217_CHGCONFIG2_VPREGHG BIT(6)
#define TPS65217_CHGCONFIG2_VOREG_MASK 0x30
#define TPS65217_CHGCONFIG3_ICHRG_MASK 0xC0
#define TPS65217_CHGCONFIG3_DPPMTH_MASK 0x30
#define TPS65217_CHGCONFIG2_PCHRGT BIT(3)
#define TPS65217_CHGCONFIG2_TERMIF 0x06
#define TPS65217_CHGCONFIG2_TRANGE BIT(0)
#define TPS65217_WLEDCTRL1_ISINK_ENABLE BIT(3)
#define TPS65217_WLEDCTRL1_ISEL BIT(2)
#define TPS65217_WLEDCTRL1_FDIM_MASK 0x03
#define TPS65217_WLEDCTRL2_DUTY_MASK 0x7F
#define TPS65217_MUXCTRL_MUX_MASK 0x07
#define TPS65217_STATUS_OFF BIT(7)
#define TPS65217_STATUS_ACPWR BIT(3)
#define TPS65217_STATUS_USBPWR BIT(2)
#define TPS65217_STATUS_PB BIT(0)
#define TPS65217_PASSWORD_REGS_UNLOCK 0x7D
#define TPS65217_PGOOD_LDO3_PG BIT(6)
#define TPS65217_PGOOD_LDO4_PG BIT(5)
#define TPS65217_PGOOD_DC1_PG BIT(4)
#define TPS65217_PGOOD_DC2_PG BIT(3)
#define TPS65217_PGOOD_DC3_PG BIT(2)
#define TPS65217_PGOOD_LDO1_PG BIT(1)
#define TPS65217_PGOOD_LDO2_PG BIT(0)
#define TPS65217_DEFPG_LDO1PGM BIT(3)
#define TPS65217_DEFPG_LDO2PGM BIT(2)
#define TPS65217_DEFPG_PGDLY_MASK 0x03
#define TPS65217_DEFDCDCX_XADJX BIT(7)
#define TPS65217_DEFDCDCX_DCDC_MASK 0x3F
#define TPS65217_DEFSLEW_GO BIT(7)
#define TPS65217_DEFSLEW_GODSBL BIT(6)
#define TPS65217_DEFSLEW_PFM_EN1 BIT(5)
#define TPS65217_DEFSLEW_PFM_EN2 BIT(4)
#define TPS65217_DEFSLEW_PFM_EN3 BIT(3)
#define TPS65217_DEFSLEW_SLEW_MASK 0x07
#define TPS65217_DEFLDO1_LDO1_MASK 0x0F
#define TPS65217_DEFLDO2_TRACK BIT(6)
#define TPS65217_DEFLDO2_LDO2_MASK 0x3F
#define TPS65217_DEFLDO3_LDO3_EN BIT(5)
#define TPS65217_DEFLDO3_LDO3_MASK 0x1F
#define TPS65217_DEFLDO4_LDO4_EN BIT(5)
#define TPS65217_DEFLDO4_LDO4_MASK 0x1F
#define TPS65217_ENABLE_LS1_EN BIT(6)
#define TPS65217_ENABLE_LS2_EN BIT(5)
#define TPS65217_ENABLE_DC1_EN BIT(4)
#define TPS65217_ENABLE_DC2_EN BIT(3)
#define TPS65217_ENABLE_DC3_EN BIT(2)
#define TPS65217_ENABLE_LDO1_EN BIT(1)
#define TPS65217_ENABLE_LDO2_EN BIT(0)
#define TPS65217_DEFUVLO_UVLOHYS BIT(2)
#define TPS65217_DEFUVLO_UVLO_MASK 0x03
#define TPS65217_SEQ1_DC1_SEQ_MASK 0xF0
#define TPS65217_SEQ1_DC2_SEQ_MASK 0x0F
#define TPS65217_SEQ2_DC3_SEQ_MASK 0xF0
#define TPS65217_SEQ2_LDO1_SEQ_MASK 0x0F
#define TPS65217_SEQ3_LDO2_SEQ_MASK 0xF0
#define TPS65217_SEQ3_LDO3_SEQ_MASK 0x0F
#define TPS65217_SEQ4_LDO4_SEQ_MASK 0xF0
#define TPS65217_SEQ5_DLY1_MASK 0xC0
#define TPS65217_SEQ5_DLY2_MASK 0x30
#define TPS65217_SEQ5_DLY3_MASK 0x0C
#define TPS65217_SEQ5_DLY4_MASK 0x03
#define TPS65217_SEQ6_DLY5_MASK 0xC0
#define TPS65217_SEQ6_DLY6_MASK 0x30
#define TPS65217_SEQ6_SEQUP BIT(2)
#define TPS65217_SEQ6_SEQDWN BIT(1)
#define TPS65217_SEQ6_INSTDWN BIT(0)
#define TPS65217_MAX_REGISTER 0x1E
#define TPS65217_PROTECT_NONE 0
#define TPS65217_PROTECT_L1 1
#define TPS65217_PROTECT_L2 2
enum tps65217_regulator_id {
/* DCDC's */
TPS65217_DCDC_1,
TPS65217_DCDC_2,
TPS65217_DCDC_3,
/* LDOs */
TPS65217_LDO_1,
TPS65217_LDO_2,
TPS65217_LDO_3,
TPS65217_LDO_4,
};
#define TPS65217_MAX_REG_ID TPS65217_LDO_4
/* Number of step-down converters available */
#define TPS65217_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS65217_NUM_LDO 4
/* Number of total regulators available */
#define TPS65217_NUM_REGULATOR (TPS65217_NUM_DCDC + TPS65217_NUM_LDO)
/**
* struct tps65217_board - packages regulator init data
* @tps65217_regulator_data: regulator initialization values
*
* Board data may be used to initialize regulator.
*/
struct tps65217_board {
struct regulator_init_data *tps65217_init_data;
};
/**
* struct tps_info - packages regulator constraints
* @name: Voltage regulator name
* @min_uV: minimum micro volts
* @max_uV: minimum micro volts
* @vsel_to_uv: Function pointer to get voltage from selector
* @uv_to_vsel: Function pointer to get selector from voltage
* @table: Table for non-uniform voltage step-size
* @table_len: Length of the voltage table
* @enable_mask: Regulator enable mask bits
* @set_vout_reg: Regulator output voltage set register
* @set_vout_mask: Regulator output voltage set mask
*
* This data is used to check the regualtor voltage limits while setting.
*/
struct tps_info {
const char *name;
int min_uV;
int max_uV;
int (*vsel_to_uv)(unsigned int vsel);
int (*uv_to_vsel)(int uV, unsigned int *vsel);
const int *table;
unsigned int table_len;
unsigned int enable_mask;
unsigned int set_vout_reg;
unsigned int set_vout_mask;
};
/**
* struct tps65217 - tps65217 sub-driver chip access routines
*
* Device data may be used to access the TPS65217 chip
*/
struct tps65217 {
struct device *dev;
struct tps65217_board *pdata;
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
struct tps_info *info[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
/* Client devices */
struct platform_device *regulator_pdev[TPS65217_NUM_REGULATOR];
};
static inline struct tps65217 *dev_to_tps65217(struct device *dev)
{
return dev_get_drvdata(dev);
}
int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
unsigned int *val);
int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
unsigned int val, unsigned int level);
int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
unsigned int mask, unsigned int val, unsigned int level);
int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
unsigned int mask, unsigned int level);
#endif /* __LINUX_MFD_TPS65217_H */
......@@ -17,6 +17,8 @@
#ifndef __LINUX_MFD_TPS65910_H
#define __LINUX_MFD_TPS65910_H
#include <linux/gpio.h>
/* TPS chip id list */
#define TPS65910 0
#define TPS65911 1
......@@ -796,6 +798,7 @@ struct tps65910_board {
struct tps65910 {
struct device *dev;
struct i2c_client *i2c_client;
struct regmap *regmap;
struct mutex io_mutex;
unsigned int id;
int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
......
......@@ -22,7 +22,6 @@ struct wm8994_ldo_pdata {
/** GPIOs to enable regulator, 0 or less if not available */
int enable;
const char *supply;
const struct regulator_init_data *init_data;
};
......
......@@ -26,7 +26,26 @@ enum ab8500_regulator_id {
AB8500_NUM_REGULATORS,
};
/* AB8500 register initialization */
/* AB9450 regulators */
enum ab9540_regulator_id {
AB9540_LDO_AUX1,
AB9540_LDO_AUX2,
AB9540_LDO_AUX3,
AB9540_LDO_AUX4,
AB9540_LDO_INTCORE,
AB9540_LDO_TVOUT,
AB9540_LDO_USB,
AB9540_LDO_AUDIO,
AB9540_LDO_ANAMIC1,
AB9540_LDO_ANAMIC2,
AB9540_LDO_DMIC,
AB9540_LDO_ANA,
AB9540_SYSCLKREQ_2,
AB9540_SYSCLKREQ_4,
AB9540_NUM_REGULATORS,
};
/* AB8500 and AB9540 register initialization */
struct ab8500_regulator_reg_init {
int id;
u8 value;
......@@ -71,4 +90,53 @@ enum ab8500_regulator_reg {
AB8500_NUM_REGULATOR_REGISTERS,
};
/* AB9540 registers */
enum ab9540_regulator_reg {
AB9540_REGUREQUESTCTRL1,
AB9540_REGUREQUESTCTRL2,
AB9540_REGUREQUESTCTRL3,
AB9540_REGUREQUESTCTRL4,
AB9540_REGUSYSCLKREQ1HPVALID1,
AB9540_REGUSYSCLKREQ1HPVALID2,
AB9540_REGUHWHPREQ1VALID1,
AB9540_REGUHWHPREQ1VALID2,
AB9540_REGUHWHPREQ2VALID1,
AB9540_REGUHWHPREQ2VALID2,
AB9540_REGUSWHPREQVALID1,
AB9540_REGUSWHPREQVALID2,
AB9540_REGUSYSCLKREQVALID1,
AB9540_REGUSYSCLKREQVALID2,
AB9540_REGUVAUX4REQVALID,
AB9540_REGUMISC1,
AB9540_VAUDIOSUPPLY,
AB9540_REGUCTRL1VAMIC,
AB9540_VSMPS1REGU,
AB9540_VSMPS2REGU,
AB9540_VSMPS3REGU, /* NOTE! PRCMU register */
AB9540_VPLLVANAREGU,
AB9540_EXTSUPPLYREGU,
AB9540_VAUX12REGU,
AB9540_VRF1VAUX3REGU,
AB9540_VSMPS1SEL1,
AB9540_VSMPS1SEL2,
AB9540_VSMPS1SEL3,
AB9540_VSMPS2SEL1,
AB9540_VSMPS2SEL2,
AB9540_VSMPS2SEL3,
AB9540_VSMPS3SEL1, /* NOTE! PRCMU register */
AB9540_VSMPS3SEL2, /* NOTE! PRCMU register */
AB9540_VAUX1SEL,
AB9540_VAUX2SEL,
AB9540_VRF1VAUX3SEL,
AB9540_REGUCTRL2SPARE,
AB9540_VAUX4REQCTRL,
AB9540_VAUX4REGU,
AB9540_VAUX4SEL,
AB9540_REGUCTRLDISCH,
AB9540_REGUCTRLDISCH2,
AB9540_REGUCTRLDISCH3,
AB9540_NUM_REGULATOR_REGISTERS,
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment