Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/lrg/voltage-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6: (42 commits)
  regulator: Fix _regulator_get_voltage if get_voltage callback is NULL
  USB: TWL6025 allow different regulator name
  REGULATOR: TWL6025: add support to twl-regulator
  regulator: twl6030: do not write to _GRP for regulator disable
  regulator: twl6030: do not write to _GRP for regulator enable
  TPS65911: Comparator: Add comparator driver
  TPS65911: Add support for added GPIO lines
  GPIO: TPS65910: Move driver to drivers/gpio/
  TPS65911: Add new irq definitions
  regulator: tps65911: Add new chip version
  MFD: TPS65910: Add support for TPS65911 device
  regulator: Fix off-by-one value range checking for mc13xxx_regulator_get_voltage
  regulator: mc13892: Fix voltage unit in test case.
  regulator: Remove MAX8997_REG_BUCK1DVS/MAX8997_REG_BUCK2DVS/MAX8997_REG_BUCK5DVS macros
  mfd: Fix off-by-one value range checking for tps65910_i2c_write
  regulator: Only apply voltage constraints from consumers that set them
  regulator: If we can't configure optimum mode we're always in the best one
  regulator: max8997: remove useless code
  regulator: Fix memory leak in max8998_pmic_probe failure path
  regulator: Fix desc_id for tps65023/6507x/65910
  ...
  • Loading branch information
Linus Torvalds committed May 27, 2011
2 parents ea0ca3a + cb220d1 commit f7fc06e
Show file tree
Hide file tree
Showing 27 changed files with 3,161 additions and 150 deletions.
4 changes: 2 additions & 2 deletions Documentation/power/regulator/machine.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ static struct regulator_init_data regulator1_data = {

Regulator-1 supplies power to Regulator-2. This relationship must be registered
with the core so that Regulator-1 is also enabled when Consumer A enables its
supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
supply (Regulator-2). The supply regulator is set by the supply_regulator
field below:-

static struct regulator_init_data regulator2_data = {
.supply_regulator_dev = &platform_regulator1_device.dev,
.supply_regulator = "regulator_name",
.constraints = {
.min_uV = 1800000,
.max_uV = 2000000,
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -424,4 +424,11 @@ config AB8500_GPIO
depends on AB8500_CORE && BROKEN
help
Select this to enable the AB8500 IC GPIO driver

config GPIO_TPS65910
bool "TPS65910 GPIO"
depends on MFD_TPS65910
help
Select this option to enable GPIO driver for the TPS65910
chip family.
endif
1 change: 1 addition & 0 deletions drivers/gpio/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ obj-$(CONFIG_GPIO_SX150X) += sx150x.o
obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o
obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o
obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o
obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o
100 changes: 100 additions & 0 deletions drivers/gpio/tps65910-gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* tps65910-gpio.c -- TI TPS6591x
*
* Copyright 2010 Texas Instruments Inc.
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
*
* 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.
*
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/tps65910.h>

static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
uint8_t val;

tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);

if (val & GPIO_STS_MASK)
return 1;

return 0;
}

static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);

if (value)
tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
else
tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
}

static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);

/* Set the initial value */
tps65910_gpio_set(gc, 0, value);

return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}

static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);

return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}

void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
{
int ret;

if (!gpio_base)
return;

tps65910->gpio.owner = THIS_MODULE;
tps65910->gpio.label = tps65910->i2c_client->name;
tps65910->gpio.dev = tps65910->dev;
tps65910->gpio.base = gpio_base;

switch(tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->gpio.ngpio = 6;
case TPS65911:
tps65910->gpio.ngpio = 9;
default:
return;
}
tps65910->gpio.can_sleep = 1;

tps65910->gpio.direction_input = tps65910_gpio_input;
tps65910->gpio.direction_output = tps65910_gpio_output;
tps65910->gpio.set = tps65910_gpio_set;
tps65910->gpio.get = tps65910_gpio_get;

ret = gpiochip_add(&tps65910->gpio);

if (ret)
dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
}
9 changes: 9 additions & 0 deletions drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,15 @@ config MFD_PM8XXX_IRQ
This is required to use certain other PM 8xxx features, such as GPIO
and MPP.

config MFD_TPS65910
bool "TPS65910 Power Management chip"
depends on I2C=y
select MFD_CORE
select GPIO_TPS65910
help
if you say yes here you get support for the TPS65910 series of
Power Management chips.

endif # MFD_SUPPORT

menu "Multimedia Capabilities Port drivers"
Expand Down
1 change: 1 addition & 0 deletions drivers/mfd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,4 @@ obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
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_MFD_TPS65910) += tps65910.o tps65910-irq.o
218 changes: 218 additions & 0 deletions drivers/mfd/tps65910-irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* tps65910-irq.c -- TI TPS6591x
*
* Copyright 2010 Texas Instruments Inc.
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
*
* 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.
*
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/mfd/tps65910.h>

static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
int irq)
{
return (irq - tps65910->irq_base);
}

/*
* This is a threaded IRQ handler so can access I2C/SPI. Since all
* interrupts are clear on read the IRQ line will be reasserted and
* the physical IRQ will be handled again if another interrupt is
* asserted while we run - in the normal course of events this is a
* rare occurrence so we save I2C/SPI reads. We're also assuming that
* it's rare to get lots of interrupts firing simultaneously so try to
* minimise I/O.
*/
static irqreturn_t tps65910_irq(int irq, void *irq_data)
{
struct tps65910 *tps65910 = irq_data;
u32 irq_sts;
u32 irq_mask;
u8 reg;
int i;

tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
irq_sts = reg;
tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
irq_sts |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
irq_sts |= reg << 16;
}

tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
irq_mask = reg;
tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
irq_mask |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
irq_mask |= reg << 16;
}

irq_sts &= ~irq_mask;

if (!irq_sts)
return IRQ_NONE;

for (i = 0; i < tps65910->irq_num; i++) {

if (!(irq_sts & (1 << i)))
continue;

handle_nested_irq(tps65910->irq_base + i);
}

/* Write the STS register back to clear IRQs we handled */
reg = irq_sts & 0xFF;
irq_sts >>= 8;
tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
reg = irq_sts & 0xFF;
tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
reg = irq_sts >> 8;
tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
}

return IRQ_HANDLED;
}

static void tps65910_irq_lock(struct irq_data *data)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);

mutex_lock(&tps65910->irq_lock);
}

static void tps65910_irq_sync_unlock(struct irq_data *data)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
u32 reg_mask;
u8 reg;

tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
reg_mask = reg;
tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
reg_mask |= reg << 8;
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
reg_mask |= reg << 16;
}

if (tps65910->irq_mask != reg_mask) {
reg = tps65910->irq_mask & 0xFF;
tps65910->write(tps65910, TPS65910_INT_MSK, 1, &reg);
reg = tps65910->irq_mask >> 8 & 0xFF;
tps65910->write(tps65910, TPS65910_INT_MSK2, 1, &reg);
switch (tps65910_chip_id(tps65910)) {
case TPS65911:
reg = tps65910->irq_mask >> 16;
tps65910->write(tps65910, TPS65910_INT_MSK3, 1, &reg);
}
}
mutex_unlock(&tps65910->irq_lock);
}

static void tps65910_irq_enable(struct irq_data *data)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);

tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq));
}

static void tps65910_irq_disable(struct irq_data *data)
{
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);

tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
}

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,
};

int tps65910_irq_init(struct tps65910 *tps65910, int irq,
struct tps65910_platform_data *pdata)
{
int ret, cur_irq;
int flags = IRQF_ONESHOT;

if (!irq) {
dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
return -EINVAL;
}

if (!pdata || !pdata->irq_base) {
dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
return -EINVAL;
}

tps65910->irq_mask = 0xFFFFFF;

mutex_init(&tps65910->irq_lock);
tps65910->chip_irq = irq;
tps65910->irq_base = pdata->irq_base;

switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->irq_num = TPS65910_NUM_IRQ;
case TPS65911:
tps65910->irq_num = TPS65911_NUM_IRQ;
}

/* Register with genirq */
for (cur_irq = tps65910->irq_base;
cur_irq < tps65910->irq_num + tps65910->irq_base;
cur_irq++) {
irq_set_chip_data(cur_irq, tps65910);
irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip,
handle_edge_irq);
irq_set_nested_thread(cur_irq, 1);

/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
}

ret = request_threaded_irq(irq, NULL, tps65910_irq, flags,
"tps65910", tps65910);

irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);

if (ret != 0)
dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret);

return ret;
}

int tps65910_irq_exit(struct tps65910 *tps65910)
{
free_irq(tps65910->chip_irq, tps65910);
return 0;
}
Loading

0 comments on commit f7fc06e

Please sign in to comment.