Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 176017
b: refs/heads/master
c: 0c41839
h: refs/heads/master
i:
  176015: d18cc5e
v: v3
  • Loading branch information
Srinidhi Kasagar authored and Samuel Ortiz committed Dec 13, 2009
1 parent 3102459 commit dcfc5b9
Show file tree
Hide file tree
Showing 5 changed files with 481 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4107da2a2853c070fb3effa58a83f94dc067fc44
refs/heads/master: 0c41839e98272a317d4af4dfcb54b599b2c3dcba
10 changes: 10 additions & 0 deletions trunk/drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,16 @@ config MFD_88PM8607
individual components like voltage regulators, RTC and
battery-charger under the corresponding menus.

config AB4500_CORE
tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip"
depends on SPI
default y
help
Select this option to enable access to AB4500 power management
chip. This connects to U8500 on the SSP/SPI bus and exports
read/write functions for the devices to get access to this chip.
This chip embeds various other multimedia funtionalities as well.

endmenu

menu "Multimedia Capabilities Port drivers"
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/mfd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
207 changes: 207 additions & 0 deletions trunk/drivers/mfd/ab4500-core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Copyright (C) 2009 ST-Ericsson
*
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation.
*
* AB4500 is a companion power management chip used with U8500.
* On this platform, this is interfaced with SSP0 controller
* which is a ARM primecell pl022.
*
* At the moment the module just exports read/write features.
* Interrupt management to be added - TODO.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab4500.h>

/* just required if probe fails, we need to
* unregister the device
*/
static struct spi_driver ab4500_driver;

/*
* This funtion writes to any AB4500 registers using
* SPI protocol & before it writes it packs the data
* in the below 24 bit frame format
*
* *|------------------------------------|
* *| 23|22...18|17.......10|9|8|7......0|
* *| r/w bank adr data |
* * ------------------------------------
*
* This function shouldn't be called from interrupt
* context
*/
int ab4500_write(struct ab4500 *ab4500, unsigned char block,
unsigned long addr, unsigned char data)
{
struct spi_transfer xfer;
struct spi_message msg;
int err;
unsigned long spi_data =
block << 18 | addr << 10 | data;

mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;

xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = NULL;
xfer.len = sizeof(unsigned long);

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);

err = spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);

return err;
}
EXPORT_SYMBOL(ab4500_write);

int ab4500_read(struct ab4500 *ab4500, unsigned char block,
unsigned long addr)
{
struct spi_transfer xfer;
struct spi_message msg;
unsigned long spi_data =
1 << 23 | block << 18 | addr << 10;

mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;

xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = ab4500->rx_buf;
xfer.len = sizeof(unsigned long);

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);

spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);

return ab4500->rx_buf[0];
}
EXPORT_SYMBOL(ab4500_read);

/* ref: ab3100 core */
#define AB4500_DEVICE(devname, devid) \
static struct platform_device ab4500_##devname##_device = { \
.name = devid, \
.id = -1, \
}

/* list of childern devices of ab4500 - all are
* not populated here - TODO
*/
AB4500_DEVICE(charger, "ab4500-charger");
AB4500_DEVICE(audio, "ab4500-audio");
AB4500_DEVICE(usb, "ab4500-usb");
AB4500_DEVICE(tvout, "ab4500-tvout");
AB4500_DEVICE(sim, "ab4500-sim");
AB4500_DEVICE(gpadc, "ab4500-gpadc");
AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
AB4500_DEVICE(misc, "ab4500-misc");

static struct platform_device *ab4500_platform_devs[] = {
&ab4500_charger_device,
&ab4500_audio_device,
&ab4500_usb_device,
&ab4500_tvout_device,
&ab4500_sim_device,
&ab4500_gpadc_device,
&ab4500_clkmgt_device,
&ab4500_misc_device,
};

static int __init ab4500_probe(struct spi_device *spi)
{
struct ab4500 *ab4500;
unsigned char revision;
int err = 0;
int i;

ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
if (!ab4500) {
dev_err(&spi->dev, "could not allocate AB4500\n");
err = -ENOMEM;
goto not_detect;
}

ab4500->spi = spi;
spi_set_drvdata(spi, ab4500);

mutex_init(&ab4500->lock);

/* read the revision register */
revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);

/* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
if (revision == 0x0 || revision == 0x10)
dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
ab4500_driver.driver.name, revision);
else {
dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
goto not_detect;
}

for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) {
ab4500_platform_devs[i]->dev.parent =
&spi->dev;
platform_set_drvdata(ab4500_platform_devs[i], ab4500);
}

/* register the ab4500 platform devices */
platform_add_devices(ab4500_platform_devs,
ARRAY_SIZE(ab4500_platform_devs));

return err;

not_detect:
spi_unregister_driver(&ab4500_driver);
kfree(ab4500);
return err;
}

static int __devexit ab4500_remove(struct spi_device *spi)
{
struct ab4500 *ab4500 =
spi_get_drvdata(spi);

kfree(ab4500);

return 0;
}

static struct spi_driver ab4500_driver = {
.driver = {
.name = "ab4500",
.owner = THIS_MODULE,
},
.probe = ab4500_probe,
.remove = __devexit_p(ab4500_remove)
};

static int __devinit ab4500_init(void)
{
return spi_register_driver(&ab4500_driver);
}

static void __exit ab4500_exit(void)
{
spi_unregister_driver(&ab4500_driver);
}

subsys_initcall_sync(ab4500_init);

MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
MODULE_DESCRIPTION("AB4500 core driver");
MODULE_LICENSE("GPL");
Loading

0 comments on commit dcfc5b9

Please sign in to comment.