mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-07 04:09:21 +00:00
gpio: sx150x: Add device tree support for sx150x gpio
Add device tree support for sx150x IO Expander devices. Change-Id: I212957bc88278659c81e28e1003dbfc7509d9877 Signed-off-by: Bamidi RaviKiran <bamidir@codeaurora.org>
This commit is contained in:
parent
e9fa666b62
commit
3aa5f509d8
1 changed files with 133 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010, 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -18,7 +18,10 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/i2c/sx150x.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define NO_UPDATE_PENDING -1
|
||||
|
||||
|
@ -53,8 +56,11 @@ struct sx150x_chip {
|
|||
struct mutex lock;
|
||||
};
|
||||
|
||||
#define SX1508Q_ID 0
|
||||
#define SX1509Q_ID 1
|
||||
|
||||
static const struct sx150x_device_data sx150x_devices[] = {
|
||||
[0] = { /* sx1508q */
|
||||
[SX1508Q_ID] = { /* sx1508q */
|
||||
.reg_pullup = 0x03,
|
||||
.reg_pulldn = 0x04,
|
||||
.reg_drain = 0x05,
|
||||
|
@ -69,7 +75,7 @@ static const struct sx150x_device_data sx150x_devices[] = {
|
|||
.reg_reset = 0x7d,
|
||||
.ngpios = 8
|
||||
},
|
||||
[1] = { /* sx1509q */
|
||||
[SX1509Q_ID] = { /* sx1509q */
|
||||
.reg_pullup = 0x07,
|
||||
.reg_pulldn = 0x09,
|
||||
.reg_drain = 0x0b,
|
||||
|
@ -86,9 +92,24 @@ static const struct sx150x_device_data sx150x_devices[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id sx150x_match_table[] = {
|
||||
{
|
||||
.compatible = "sx1508q", .data = NULL,
|
||||
},
|
||||
{
|
||||
.compatible = "sx1509q", .data = NULL,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sx150x_match_table);
|
||||
#else
|
||||
#define sx150x_match_table NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id sx150x_id[] = {
|
||||
{"sx1508q", 0},
|
||||
{"sx1509q", 1},
|
||||
{"sx1508q", SX1508Q_ID},
|
||||
{"sx1509q", SX1509Q_ID},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sx150x_id);
|
||||
|
@ -424,6 +445,13 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
|
|||
{
|
||||
mutex_init(&chip->lock);
|
||||
|
||||
if (client->dev.of_node) {
|
||||
if (of_device_is_compatible(client->dev.of_node, "sx1508q"))
|
||||
driver_data = SX1508Q_ID;
|
||||
else
|
||||
driver_data = SX1509Q_ID;
|
||||
}
|
||||
|
||||
chip->client = client;
|
||||
chip->dev_cfg = &sx150x_devices[driver_data];
|
||||
chip->gpio_chip.label = client->name;
|
||||
|
@ -438,6 +466,10 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
|
|||
if (pdata->oscio_is_gpo)
|
||||
++chip->gpio_chip.ngpio;
|
||||
|
||||
if (client && client->dev.of_node)
|
||||
chip->gpio_chip.of_node =
|
||||
of_node_get(client->dev.of_node);
|
||||
|
||||
chip->irq_chip.name = client->name;
|
||||
chip->irq_chip.irq_mask = sx150x_irq_mask;
|
||||
chip->irq_chip.irq_unmask = sx150x_irq_unmask;
|
||||
|
@ -466,6 +498,29 @@ static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg)
|
|||
static int sx150x_reset(struct sx150x_chip *chip)
|
||||
{
|
||||
int err;
|
||||
struct device_node *np = chip->gpio_chip.of_node;
|
||||
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
|
||||
int rst_gpio;
|
||||
|
||||
if (np) {
|
||||
rst_gpio = of_get_named_gpio_flags(np, "sx150x,reset_gpio",
|
||||
0, &flags);
|
||||
if (rst_gpio < 0)
|
||||
pr_debug("%s: No Reset GPIO found %d\n",
|
||||
__func__, rst_gpio);
|
||||
else {
|
||||
err = gpio_request(rst_gpio, "sx150x_rst");
|
||||
if (err) {
|
||||
pr_err("Failed to get reset GPIO %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Max. time for NRESET low is 2.5ms */
|
||||
gpio_direction_output(rst_gpio, 0x0);
|
||||
usleep(2500);
|
||||
gpio_direction_output(rst_gpio, 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
err = i2c_smbus_write_byte_data(chip->client,
|
||||
chip->dev_cfg->reg_reset,
|
||||
|
@ -572,16 +627,85 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int sx150x_parse_dt(struct device *dev,
|
||||
struct sx150x_platform_data *pdata)
|
||||
{
|
||||
int rc;
|
||||
unsigned int temp;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
pdata->oscio_is_gpo = of_property_read_bool(np, "sx150x,oscio_is_gpo");
|
||||
pdata->reset_during_probe =
|
||||
of_property_read_bool(np, "sx150x,reset_onprobe");
|
||||
|
||||
rc = of_property_read_u32(np, "sx150x,pullup_ena", &temp);
|
||||
if (rc) {
|
||||
pr_err("%s: Failed to find pullup_ena %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
pdata->io_pullup_ena = temp;
|
||||
|
||||
rc = of_property_read_u32(np, "sx150x,pulldn_ena", &temp);
|
||||
if (rc) {
|
||||
pr_err("%s: Failed to find pulldn_ena %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
pdata->io_pulldn_ena = temp;
|
||||
|
||||
rc = of_property_read_u32(np, "sx150x,float_ena", &temp);
|
||||
if (rc) {
|
||||
pr_err("%s: Failed to find float_ena %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
pdata->io_open_drain_ena = temp;
|
||||
|
||||
rc = of_property_read_u32(np, "sx150x,polarity", &temp);
|
||||
if (rc) {
|
||||
pr_err("%s: Failed to find polarity %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
pdata->io_polarity = temp;
|
||||
|
||||
/* TODO: Add support for Interrupts */
|
||||
pdata->irq_summary = -1;
|
||||
pdata->gpio_base = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int sx150x_parse_dt(struct device *dev,
|
||||
struct sx150x_platform_data *pdata)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sx150x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WRITE_WORD_DATA;
|
||||
I2C_FUNC_SMBUS_WRITE_WORD_DATA;
|
||||
struct sx150x_platform_data *pdata;
|
||||
struct sx150x_chip *chip;
|
||||
int rc;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (client->dev.of_node) {
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct sx150x_platform_data), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "Failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = sx150x_parse_dt(&client->dev, pdata);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -640,7 +764,8 @@ static int sx150x_remove(struct i2c_client *client)
|
|||
static struct i2c_driver sx150x_driver = {
|
||||
.driver = {
|
||||
.name = "sx150x",
|
||||
.owner = THIS_MODULE
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(sx150x_match_table)
|
||||
},
|
||||
.probe = sx150x_probe,
|
||||
.remove = sx150x_remove,
|
||||
|
|
Loading…
Reference in a new issue