mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
MFD changes for 3.4
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPcXgCAAoJEIqAPN1PVmxKh2oP/2Ns+dr4oOF8z+uqYG1oisJd CxBTC1Bi9gYBtpiMztPiHZWiQtVXoDgLbLkx6ooWH5dpwCdvU6TVBZUJp4wpELtx mMk5vJy4/INHgI0nk5wUOr76rNlQfIcK04f+LHBSG1iljUkoVR3FefVKgoyIP+Wv oiCeuCyQcYIUmG1pVt1x43OoS+2xgjWQA67AalLLRj1DOA5OkvUL7NGsrZ1iZTUh YHQJsK6ER3MgbFFEImtn10NNFwAEG04o6vi42DFW1O0awm6kmVoLjo46wS+UiKoh Vx8t5ZGvlYOZ1ZM9N5ETgQnihBt7cOhA3ivZar8h+WiYVTRJs1ZSkpmnlpmM4YY9 RCZ5DRw3N39R0ezkNVGSr1Xn1vkysIiZI82frrJiPUYLKihsrBzj2Jq3O25iILCf Iyv7HBEJxAb3x0zlF6kPhaA8OW4dssaHTLNx5IJSOKwiwVLdm4RPyOHh9QVz++p/ p0hvSQWK1MUruBbBrjF/FN+FidgK2iU0iDW/GoDwI7OKymSxg7sauLtp0cZpo6nT F+Ep6yl/uR5vxih4LSYFJOjoeKuwIo/x92H0qJ3UroaUs9DNJ7UCKchXXiQ1Wtnz tAAsWP1YsMxMzlMxqW5J9w4LJynJ8bqrC0L8+HWzIUwikA8wv8/47Pmc/vPW0Y3N 5L7KMS8/iFCsS8rPmGeP =onDl -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
30304e5a79
23
Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
Normal file
23
Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
Normal file
@ -0,0 +1,23 @@
|
||||
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 @@ out:
|
||||
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);
|
||||
if (ab8500->write_masked == NULL) {
|
||||
u8 data;
|
||||
|
||||
ret = ab8500->read(ab8500, addr);
|
||||
if (ret < 0) {
|
||||
dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
|
||||
addr, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = (u8)ret;
|
||||
data = (~bitmask & data) | (bitmask & bitvalues);
|
||||
|
||||
ret = ab8500->write(ab8500, addr, data);
|
||||
ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
|
||||
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_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;
|
||||
|
||||
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++) {
|
||||
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;
|
||||
|
||||
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)
|
||||
goto out_freeirq;
|
||||
|
||||
ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
|
||||
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");
|
||||
|
||||
return ret;
|
||||
else
|
||||
return ret;
|
||||
|
||||
out_freeirq:
|
||||
if (ab8500->irq_base)
|
||||
@ -961,18 +1147,27 @@ out_freeirq:
|
||||
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)
|
||||
|
137
drivers/mfd/anatop-mfd.c
Normal file
137
drivers/mfd/anatop-mfd.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 @@ err_revision:
|
||||
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)
|
||||
|
408
drivers/mfd/rc5t583-irq.c
Normal file
408
drivers/mfd/rc5t583-irq.c
Normal file
@ -0,0 +1,408 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
386
drivers/mfd/rc5t583.c
Normal file
386
drivers/mfd/rc5t583.c
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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 @@ err:
|
||||
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;
|
||||
|
387
drivers/mfd/tps65090.c
Normal file
387
drivers/mfd/tps65090.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* 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");
|
242
drivers/mfd/tps65217.c
Normal file
242
drivers/mfd/tps65217.c
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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 = ®
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#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 @@ fail_kthread:
|
||||
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 */
|
||||
|
40
include/linux/mfd/anatop.h
Normal file
40
include/linux/mfd/anatop.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* Different hw accelerators which can be turned ON/
|
||||
* OFF or put into retention (MMDSPs and ESRAMs).
|
||||
* Used with EPOD API.
|
||||
*
|
||||
* 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,17 +684,7 @@ 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 int prcmu_enable_spi2(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int prcmu_disable_spi2(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void db8500_prcmu_modem_reset(void) {}
|
||||
|
||||
static inline void db8500_prcmu_system_reset(u16 reset_code) {}
|
||||
|
||||
@ -688,6 +694,11 @@ static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 db8500_prcmu_get_power_state_result(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void db8500_prcmu_enable_wakeups(u32 wakeups) {}
|
||||
|
||||
static inline int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
|
||||
@ -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
|
||||
|
295
include/linux/mfd/rc5t583.h
Normal file
295
include/linux/mfd/rc5t583.h
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
/*
|
||||
|
46
include/linux/mfd/tps65090.h
Normal file
46
include/linux/mfd/tps65090.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 */
|
283
include/linux/mfd/tps65217.h
Normal file
283
include/linux/mfd/tps65217.h
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user