-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Driver for the GPIO block found in ti's tps65218 pmics. The device has two GPIOs and one GPO pin which can be configured as follows: GPIO1: -general-purpose, open-drain output controlled by GPO1 user bit and/or sequencer -DDR3 reset input signal from SOC. Signal is either latched or passed-trough to GPO2 pin. See below for details. GPO2: -general-purpose output controlled by GPO2 user bit -DDR3 reset output signal. Signal is controlled by GPIO1 and PGOOD. See below for details. -Output buffer can be configured as open-drain or push-pull. GPIO3: -general-purpose, open-drain output controlled by GPO3 user bit and/or sequencer -reset input-signal for DCDC1 and DCDC2. The input configurations are not meant to be used by the user so the driver only offers GPOs. v2: Added request routine that evaluates the fw config flags and removed module owner v3: Added .direction_input() routine, and took care of all Linus Walleij suggestions (clamp to bool, use proper include) Signed-off-by: Nicolas Saenz Julienne <nicolassaenzj@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
- Loading branch information
Nicolas Saenz Julienne
authored and
Linus Walleij
committed
Feb 11, 2016
1 parent
b866526
commit c366c76
Showing
3 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
/* | ||
* Copyright 2015 Verifone Int. | ||
* | ||
* Author: Nicolas Saenz Julienne <nicolassaenzj@gmail.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify i t | ||
* under the terms of the GNU General Public License as published by th e | ||
* Free Software Foundation; either version 2 of the License, or (at you r | ||
* option) any later version. | ||
* | ||
* This driver is based on the gpio-tps65912 implementation. | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/errno.h> | ||
#include <linux/gpio/driver.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/mfd/tps65218.h> | ||
#include "gpiolib.h" | ||
|
||
struct tps65218_gpio { | ||
struct tps65218 *tps65218; | ||
struct gpio_chip gpio_chip; | ||
}; | ||
|
||
static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
{ | ||
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc); | ||
struct tps65218 *tps65218 = tps65218_gpio->tps65218; | ||
unsigned int val; | ||
int ret; | ||
|
||
ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val); | ||
if (ret) | ||
return ret; | ||
|
||
return !!(val & (TPS65218_ENABLE2_GPIO1 << offset)); | ||
} | ||
|
||
static void tps65218_gpio_set(struct gpio_chip *gc, unsigned offset, | ||
int value) | ||
{ | ||
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc); | ||
struct tps65218 *tps65218 = tps65218_gpio->tps65218; | ||
|
||
if (value) | ||
tps65218_set_bits(tps65218, TPS65218_REG_ENABLE2, | ||
TPS65218_ENABLE2_GPIO1 << offset, | ||
TPS65218_ENABLE2_GPIO1 << offset, | ||
TPS65218_PROTECT_L1); | ||
else | ||
tps65218_clear_bits(tps65218, TPS65218_REG_ENABLE2, | ||
TPS65218_ENABLE2_GPIO1 << offset, | ||
TPS65218_PROTECT_L1); | ||
} | ||
|
||
static int tps65218_gpio_output(struct gpio_chip *gc, unsigned offset, | ||
int value) | ||
{ | ||
/* Only drives GPOs */ | ||
return 0; | ||
} | ||
|
||
static int tps65218_gpio_input(struct gpio_chip *gc, unsigned offset) | ||
{ | ||
return -EPERM; | ||
} | ||
|
||
static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset) | ||
{ | ||
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc); | ||
struct tps65218 *tps65218 = tps65218_gpio->tps65218; | ||
unsigned long flags = gc->desc[offset].flags; | ||
int ret; | ||
|
||
if (flags & FLAG_OPEN_SOURCE) { | ||
dev_err(gc->parent, "can't work as open source\n"); | ||
return -EINVAL; | ||
} | ||
|
||
switch (offset) { | ||
case 0: | ||
if (!(flags & FLAG_OPEN_DRAIN)) { | ||
dev_err(gc->parent, "GPO1 works only as open drain\n"); | ||
return -EINVAL; | ||
} | ||
|
||
/* Disable sequencer for GPO1 */ | ||
ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7, | ||
TPS65218_SEQ7_GPO1_SEQ_MASK, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
|
||
/* Setup GPO1 */ | ||
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1, | ||
TPS65218_CONFIG1_IO1_SEL, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
|
||
break; | ||
case 1: | ||
/* GP02 is push-pull by default, can be set as open drain. */ | ||
if (flags & FLAG_OPEN_DRAIN) { | ||
ret = tps65218_clear_bits(tps65218, | ||
TPS65218_REG_CONFIG1, | ||
TPS65218_CONFIG1_GPO2_BUF, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
/* Setup GPO2 */ | ||
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1, | ||
TPS65218_CONFIG1_IO1_SEL, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
|
||
break; | ||
|
||
case 2: | ||
if (!(flags & FLAG_OPEN_DRAIN)) { | ||
dev_err(gc->parent, "GPO3 works only as open drain\n"); | ||
return -EINVAL; | ||
} | ||
|
||
/* Disable sequencer for GPO3 */ | ||
ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7, | ||
TPS65218_SEQ7_GPO3_SEQ_MASK, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
|
||
/* Setup GPO3 */ | ||
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG2, | ||
TPS65218_CONFIG2_DC12_RST, | ||
TPS65218_PROTECT_L1); | ||
if (ret) | ||
return ret; | ||
|
||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static struct gpio_chip template_chip = { | ||
.label = "gpio-tps65218", | ||
.owner = THIS_MODULE, | ||
.request = tps65218_gpio_request, | ||
.direction_output = tps65218_gpio_output, | ||
.direction_input = tps65218_gpio_input, | ||
.get = tps65218_gpio_get, | ||
.set = tps65218_gpio_set, | ||
.can_sleep = true, | ||
.ngpio = 3, | ||
.base = -1, | ||
}; | ||
|
||
static int tps65218_gpio_probe(struct platform_device *pdev) | ||
{ | ||
struct tps65218 *tps65218 = dev_get_drvdata(pdev->dev.parent); | ||
struct tps65218_gpio *tps65218_gpio; | ||
int ret; | ||
|
||
tps65218_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65218_gpio), | ||
GFP_KERNEL); | ||
if (!tps65218_gpio) | ||
return -ENOMEM; | ||
|
||
tps65218_gpio->tps65218 = tps65218; | ||
tps65218_gpio->gpio_chip = template_chip; | ||
tps65218_gpio->gpio_chip.parent = &pdev->dev; | ||
#ifdef CONFIG_OF_GPIO | ||
tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node; | ||
#endif | ||
|
||
ret = gpiochip_add_data(&tps65218_gpio->gpio_chip, tps65218_gpio); | ||
if (ret < 0) { | ||
dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret); | ||
return ret; | ||
} | ||
|
||
platform_set_drvdata(pdev, tps65218_gpio); | ||
|
||
return ret; | ||
} | ||
|
||
static int tps65218_gpio_remove(struct platform_device *pdev) | ||
{ | ||
struct tps65218_gpio *tps65218_gpio = platform_get_drvdata(pdev); | ||
|
||
gpiochip_remove(&tps65218_gpio->gpio_chip); | ||
|
||
return 0; | ||
} | ||
|
||
static const struct of_device_id tps65218_dt_match[] = { | ||
{ .compatible = "ti,tps65218-gpio" }, | ||
{ } | ||
}; | ||
MODULE_DEVICE_TABLE(of, tps65218_dt_match); | ||
|
||
static struct platform_driver tps65218_gpio_driver = { | ||
.driver = { | ||
.name = "tps65218-gpio", | ||
.of_match_table = of_match_ptr(tps65218_dt_match) | ||
}, | ||
.probe = tps65218_gpio_probe, | ||
.remove = tps65218_gpio_remove, | ||
}; | ||
|
||
module_platform_driver(tps65218_gpio_driver); | ||
|
||
MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>"); | ||
MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs"); | ||
MODULE_LICENSE("GPL v2"); | ||
MODULE_ALIAS("platform:tps65218-gpio"); |