Skip to content

Commit

Permalink
mfd: Support AB9540 ab8500 variant
Browse files Browse the repository at this point in the history
The AB9540 variant of the AB8500 is basically close enough
to use the same driver. This adds the new registers and
deviations for this new chip variant.

Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Maxime Coquelin <maxime.coquelin@stericsson.com>
Signed-off-by: Alex Macro <alex.macro@stericsson.com>
Signed-off-by: Michel Jaouen <michel.jaouen@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Linus Walleij authored and Samuel Ortiz committed Mar 6, 2012
1 parent 2ced445 commit d625552
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 25 deletions.
2 changes: 1 addition & 1 deletion arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
191 changes: 170 additions & 21 deletions drivers/mfd/ab8500-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -95,6 +97,9 @@

#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). The interupts are
Expand All @@ -108,6 +113,11 @@ 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",
Expand Down Expand Up @@ -354,7 +364,10 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
int irq;
int num_irqs;

num_irqs = AB8500_NR_IRQS;
if (is_ab9540(ab8500))
num_irqs = AB9540_NR_IRQS;
else
num_irqs = AB8500_NR_IRQS;

for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, ab8500);
Expand All @@ -377,7 +390,10 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
int irq;
int num_irqs;

num_irqs = AB8500_NR_IRQS;
if (is_ab9540(ab8500))
num_irqs = AB9540_NR_IRQS;
else
num_irqs = AB8500_NR_IRQS;

for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM
Expand All @@ -388,6 +404,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
}
}

/* AB8500 GPIO Resources */
static struct resource __devinitdata ab8500_gpio_resources[] = {
{
.name = "GPIO_INT6",
Expand All @@ -397,6 +414,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",
Expand Down Expand Up @@ -713,7 +752,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",
Expand All @@ -727,11 +766,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),
Expand Down Expand Up @@ -770,11 +804,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),
Expand Down Expand Up @@ -803,6 +833,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)
{
Expand Down Expand Up @@ -864,9 +920,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,
Expand All @@ -875,10 +986,22 @@ 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,
};

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);
Expand Down Expand Up @@ -915,8 +1038,14 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
ab8500->chip_id >> 4,
ab8500->chip_id & 0x0F);

ab8500->mask_size = AB8500_NUM_IRQ_REGS;
ab8500->irq_reg_offset = ab8500_irq_regoffset;
/* Configure AB8500 or AB9540 IRQ */
if (is_ab9540(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;
Expand Down Expand Up @@ -982,17 +1111,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
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)
Expand All @@ -1010,7 +1156,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)

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);
Expand Down
4 changes: 3 additions & 1 deletion include/linux/mfd/abx500/ab8500-gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading

0 comments on commit d625552

Please sign in to comment.