Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 186883
b: refs/heads/master
c: 53dbab7
h: refs/heads/master
i:
  186881: 0633625
  186879: a1f85e1
v: v3
  • Loading branch information
Haojian Zhuang authored and Samuel Ortiz committed Mar 7, 2010
1 parent c0b9b43 commit cabce2c
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 115 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bbd51b1ff1bf57b9ed7f062486a415509968d4d9
refs/heads/master: 53dbab7af9ca13fa95605e9a5c31bb803dcba363
61 changes: 41 additions & 20 deletions trunk/drivers/mfd/88pm860x-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm8607.h>
#include <linux/mfd/88pm860x.h>


#define PM8607_REG_RESOURCE(_start, _end) \
Expand Down Expand Up @@ -67,49 +67,45 @@ static struct mfd_cell pm8607_devs[] = {
PM8607_REG_DEVS(ldo14, LDO14),
};

int pm860x_device_init(struct pm8607_chip *chip,
struct pm8607_platform_data *pdata)
static void device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
}

static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int i, count;
int ret;

ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
if (ret < 0) {
dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
goto out;
}
if ((ret & PM8607_ID_MASK) == PM8607_ID)
if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION)
dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
ret);
else {
dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
"Chip ID: %02x\n", ret);
goto out;
}
chip->chip_id = ret;
chip->chip_version = ret;

ret = pm8607_reg_read(chip, PM8607_BUCK3);
ret = pm860x_reg_read(i2c, PM8607_BUCK3);
if (ret < 0) {
dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
goto out;
}
if (ret & PM8607_BUCK3_DOUBLE)
chip->buck3_double = 1;

ret = pm8607_reg_read(chip, PM8607_MISC1);
ret = pm860x_reg_read(i2c, PM8607_MISC1);
if (ret < 0) {
dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
goto out;
}
if (pdata->i2c_port == PI2C_PORT)
ret |= PM8607_MISC1_PI2C;
else
ret &= ~PM8607_MISC1_PI2C;
ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
if (ret < 0) {
dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
goto out;
}

count = ARRAY_SIZE(pm8607_devs);
for (i = 0; i < count; i++) {
Expand All @@ -121,14 +117,39 @@ int pm860x_device_init(struct pm8607_chip *chip,
}
}
out:
return ret;
return;
}

int pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
switch (chip->id) {
case CHIP_PM8606:
device_8606_init(chip, chip->client, pdata);
break;
case CHIP_PM8607:
device_8607_init(chip, chip->client, pdata);
break;
}

if (chip->companion) {
switch (chip->id) {
case CHIP_PM8607:
device_8606_init(chip, chip->companion, pdata);
break;
case CHIP_PM8606:
device_8607_init(chip, chip->companion, pdata);
break;
}
}
return 0;
}

void pm8607_device_exit(struct pm8607_chip *chip)
void pm860x_device_exit(struct pm860x_chip *chip)
{
mfd_remove_devices(chip->dev);
}

MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");
172 changes: 119 additions & 53 deletions trunk/drivers/mfd/88pm860x-i2c.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* I2C driver for Marvell 88PM8607
* I2C driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
Expand All @@ -12,12 +12,11 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/mfd/88pm8607.h>
#include <linux/mfd/88pm860x.h>

static inline int pm8607_read_device(struct pm8607_chip *chip,
static inline int pm860x_read_device(struct i2c_client *i2c,
int reg, int bytes, void *dest)
{
struct i2c_client *i2c = chip->client;
unsigned char data;
int ret;

Expand All @@ -32,10 +31,9 @@ static inline int pm8607_read_device(struct pm8607_chip *chip,
return 0;
}

static inline int pm8607_write_device(struct pm8607_chip *chip,
static inline int pm860x_write_device(struct i2c_client *i2c,
int reg, int bytes, void *src)
{
struct i2c_client *i2c = chip->client;
unsigned char buf[bytes + 1];
int ret;

Expand All @@ -48,125 +46,193 @@ static inline int pm8607_write_device(struct pm8607_chip *chip,
return 0;
}

int pm8607_reg_read(struct pm8607_chip *chip, int reg)
int pm860x_reg_read(struct i2c_client *i2c, int reg)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char data;
int ret;

mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, 1, &data);
ret = pm860x_read_device(i2c, reg, 1, &data);
mutex_unlock(&chip->io_lock);

if (ret < 0)
return ret;
else
return (int)data;
}
EXPORT_SYMBOL(pm8607_reg_read);
EXPORT_SYMBOL(pm860x_reg_read);

int pm8607_reg_write(struct pm8607_chip *chip, int reg,
int pm860x_reg_write(struct i2c_client *i2c, int reg,
unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
int ret;

mutex_lock(&chip->io_lock);
ret = chip->write(chip, reg, 1, &data);
ret = pm860x_write_device(i2c, reg, 1, &data);
mutex_unlock(&chip->io_lock);

return ret;
}
EXPORT_SYMBOL(pm8607_reg_write);
EXPORT_SYMBOL(pm860x_reg_write);

int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
int pm860x_bulk_read(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
int ret;

mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, count, buf);
ret = pm860x_read_device(i2c, reg, count, buf);
mutex_unlock(&chip->io_lock);

return ret;
}
EXPORT_SYMBOL(pm8607_bulk_read);
EXPORT_SYMBOL(pm860x_bulk_read);

int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
int pm860x_bulk_write(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
int ret;

mutex_lock(&chip->io_lock);
ret = chip->write(chip, reg, count, buf);
ret = pm860x_write_device(i2c, reg, count, buf);
mutex_unlock(&chip->io_lock);

return ret;
}
EXPORT_SYMBOL(pm8607_bulk_write);
EXPORT_SYMBOL(pm860x_bulk_write);

int pm8607_set_bits(struct pm8607_chip *chip, int reg,
int pm860x_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char value;
int ret;

mutex_lock(&chip->io_lock);
ret = chip->read(chip, reg, 1, &value);
ret = pm860x_read_device(i2c, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= data;
ret = chip->write(chip, reg, 1, &value);
ret = pm860x_write_device(i2c, reg, 1, &value);
out:
mutex_unlock(&chip->io_lock);
return ret;
}
EXPORT_SYMBOL(pm8607_set_bits);
EXPORT_SYMBOL(pm860x_set_bits);


static const struct i2c_device_id pm860x_id_table[] = {
{ "88PM8607", 0 },
{ "88PM860x", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, pm860x_id_table);

static int verify_addr(struct i2c_client *i2c)
{
unsigned short addr_8607[] = {0x30, 0x34};
unsigned short addr_8606[] = {0x10, 0x11};
int size, i;

if (i2c == NULL)
return 0;
size = ARRAY_SIZE(addr_8606);
for (i = 0; i < size; i++) {
if (i2c->addr == *(addr_8606 + i))
return CHIP_PM8606;
}
size = ARRAY_SIZE(addr_8607);
for (i = 0; i < size; i++) {
if (i2c->addr == *(addr_8607 + i))
return CHIP_PM8607;
}
return 0;
}

static int __devinit pm860x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pm8607_platform_data *pdata = client->dev.platform_data;
struct pm8607_chip *chip;
int ret;

chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;

chip->client = client;
chip->dev = &client->dev;
chip->read = pm8607_read_device;
chip->write = pm8607_write_device;
memcpy(&chip->id, id, sizeof(struct i2c_device_id));
i2c_set_clientdata(client, chip);

mutex_init(&chip->io_lock);
dev_set_drvdata(chip->dev, chip);

ret = pm860x_device_init(chip, pdata);
if (ret < 0)
goto out;


struct pm860x_platform_data *pdata = client->dev.platform_data;
static struct pm860x_chip *chip;
struct i2c_board_info i2c_info = {
.type = "88PM860x",
.platform_data = client->dev.platform_data,
};
int addr_c, found_companion = 0;

if (pdata == NULL) {
pr_info("No platform data in %s!\n", __func__);
return -EINVAL;
}

/*
* Both client and companion client shares same platform driver.
* Driver distinguishes them by pdata->companion_addr.
* pdata->companion_addr is only assigned if companion chip exists.
* At the same time, the companion_addr shouldn't equal to client
* address.
*/
addr_c = pdata->companion_addr;
if (addr_c && (addr_c != client->addr)) {
i2c_info.addr = addr_c;
found_companion = 1;
}

if (found_companion || (addr_c == 0)) {
chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;

chip->id = verify_addr(client);
chip->companion_addr = addr_c;
chip->client = client;
i2c_set_clientdata(client, chip);
chip->dev = &client->dev;
mutex_init(&chip->io_lock);
dev_set_drvdata(chip->dev, chip);

if (found_companion) {
/*
* If this driver is built in, probe function is
* recursive.
* If this driver is built as module, the next probe
* function is called after the first one finished.
*/
chip->companion = i2c_new_device(client->adapter,
&i2c_info);
}
}

/*
* If companion chip existes, it's called by companion probe.
* If there's no companion chip, it's called by client probe.
*/
if ((addr_c == 0) || (addr_c == client->addr)) {
chip->companion = client;
i2c_set_clientdata(chip->companion, chip);
pm860x_device_init(chip, pdata);
}
return 0;

out:
i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}

static int __devexit pm860x_remove(struct i2c_client *client)
{
struct pm8607_chip *chip = i2c_get_clientdata(client);

struct pm860x_chip *chip = i2c_get_clientdata(client);

/*
* If companion existes, companion client is removed first.
* Because companion client is registered last and removed first.
*/
if (chip->companion_addr == client->addr)
return 0;
pm860x_device_exit(chip);
i2c_unregister_device(chip->companion);
i2c_set_clientdata(chip->companion, NULL);
i2c_set_clientdata(chip->client, NULL);
kfree(chip);
return 0;
}
Expand Down
Loading

0 comments on commit cabce2c

Please sign in to comment.