summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorJustin Waters <justin.waters@timesys.com>2012-04-17 13:43:17 -0400
committerJustin Waters <justin.waters@timesys.com>2012-04-17 13:43:17 -0400
commit4f60d7e7027af17ceffc1a38e6dbe4e3e95c71ec (patch)
treedd33f3760e08226d5c05036d664d2d68fb3765dc /drivers/gpio
parentb1af6f532e0d348b153d5c148369229d24af361a (diff)
LogicPD Support for OMAP3/DM3/AM3 boards
From Logic BSP-2.0-5-01
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/twl4030-gpio.c105
-rw-r--r--drivers/gpio/twl4030-pwm.c126
3 files changed, 233 insertions, 0 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a5fa2b5d851..fc6eb59244b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -31,6 +31,8 @@ COBJS-$(CONFIG_MARVELL_MFP) += mvmfp.o
COBJS-$(CONFIG_MXC_GPIO) += mxc_gpio.o
COBJS-$(CONFIG_PCA953X) += pca953x.o
COBJS-$(CONFIG_S5P) += s5p_gpio.o
+COBJS-$(CONFIG_TWL4030_GPIO) += twl4030-gpio.o
+COBJS-$(CONFIG_TWL4030_PWM) += twl4030-pwm.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
new file mode 100644
index 00000000000..57c12fcfb95
--- /dev/null
+++ b/drivers/gpio/twl4030-gpio.c
@@ -0,0 +1,105 @@
+#include <common.h>
+#include <twl4030.h>
+
+#define BIT(x) (1 << (x))
+
+/* GPIO_CTRL Fields */
+#define MASK_GPIO_CTRL_GPIO_ON BIT(2)
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+ return twl4030_i2c_write_u8(TWL4030_CHIP_GPIO, data, address);
+}
+
+static inline int gpio_twl4030_read(u8 address)
+{
+ u8 data;
+ int ret = 0;
+
+ ret = twl4030_i2c_read_u8(TWL4030_CHIP_GPIO, &data, address);
+ return (ret < 0) ? ret : data;
+}
+
+int twl4030_set_gpio_direction(unsigned int gpio, unsigned int is_input)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 reg = 0;
+ u8 base = REG_GPIODATADIR1 + d_bnk;
+ int ret = 0;
+
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (is_input)
+ reg = ret & ~d_msk;
+ else
+ reg = ret | d_msk;
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+
+ return ret;
+}
+
+int twl4030_set_gpio_dataout(unsigned int gpio, unsigned int enable)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 base = 0;
+
+ if (enable)
+ base = REG_SETGPIODATAOUT1 + d_bnk;
+ else
+ base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+ return gpio_twl4030_write(base, d_msk);
+}
+
+int twl4030_get_gpio_datain(unsigned int gpio)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_off = gpio & 0x7;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & BIT(gpio))))
+ return -1;
+
+ base = REG_GPIODATAIN1 + d_bnk;
+ ret = gpio_twl4030_read(base);
+ if (ret > 0)
+ ret = (ret >> d_off) & 0x1;
+
+ return ret;
+}
+
+int twl4030_request_gpio(unsigned int gpio)
+{
+ int status = 0;
+
+ /* on first use, turn GPIO module "on" */
+ if (!gpio_usage_count) {
+ // struct twl4030_gpio_platform_data *pdata;
+ u8 value = MASK_GPIO_CTRL_GPIO_ON;
+
+ status = gpio_twl4030_write(REG_GPIO_CTRL, value);
+ }
+
+ if (!status)
+ gpio_usage_count |= (0x1 << gpio);
+
+ return status;
+}
+
+void twl4030_free_gpio(unsigned int gpio)
+{
+ gpio_usage_count &= ~BIT(gpio);
+
+ /* on last use, switch off GPIO module */
+ if (!gpio_usage_count)
+ gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+}
diff --git a/drivers/gpio/twl4030-pwm.c b/drivers/gpio/twl4030-pwm.c
new file mode 100644
index 00000000000..dfbb7f5b596
--- /dev/null
+++ b/drivers/gpio/twl4030-pwm.c
@@ -0,0 +1,126 @@
+#include <common.h>
+#include <twl4030.h>
+
+/* INTRB register offsets (TWL4030_CHIP_INTBR) */
+#define TWL_INTBR_PMBR1 0x92
+#define TWL_INTBR_GPBR1 0x91
+
+/*PWM0 register offsets (TWL4030_CHIP_PWM0) */
+#define TWL_LED_PWMON 0xf8
+#define TWL_LED_PWMOFF 0xf9
+
+#if 0
+#define PWM_PRINT(fmt, args...) printf(fmt, ## args)
+#else
+#define PWM_PRINT(fmt, args...)
+#endif
+
+int twl4030_set_pwm0(int level, int max_brightness)
+{
+ u8 mux_pwm, enb_pwm;
+ unsigned char c;
+ int status;
+
+ PWM_PRINT("%s: level %d\n", __FUNCTION__, level);
+ if (level > max_brightness)
+ return -1;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &mux_pwm, TWL_INTBR_PMBR1);
+ twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &enb_pwm, TWL_INTBR_GPBR1);
+
+ PWM_PRINT("%s: enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+
+ if (level == 0) {
+ /* disable pwm0 output and clock */
+ enb_pwm &= ~0x05;
+ /* change pwm0 pin to gpio pin */
+ mux_pwm &= ~0x0c;
+
+ PWM_PRINT("%s: disable enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ enb_pwm, TWL_INTBR_GPBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -2;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ mux_pwm, TWL_INTBR_PMBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -3;
+ }
+#if 0
+ PWM_PRINT("%s: turn off GPIO_%d as backlight!\n", __FUNCTION__, omap3logic_dss_lcd_data.lcd_gpio_backlight);
+ /* Turn off the backlight! */
+ gpio_set_value(omap3logic_dss_lcd_data.lcd_gpio_backlight, 0);
+#endif
+ return 0;
+ }
+
+ if (((enb_pwm & 0x5) != 0x5) || ((mux_pwm & 0x0c) != 0x4)) {
+ /* change gpio pin to pwm0 pin */
+ mux_pwm = (mux_pwm & ~0xc) | 0x04;
+ /* enable pwm0 output and clock*/
+ enb_pwm = (enb_pwm & ~0x5) | 0x05;
+
+ PWM_PRINT("%s: enable enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ mux_pwm, TWL_INTBR_PMBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -4;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ enb_pwm, TWL_INTBR_GPBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -5;
+ }
+#if 0
+ PWM_PRINT("%s: turn on GPIO_%d as backlight!\n", __FUNCTION__, omap3logic_dss_lcd_data.lcd_gpio_backlight);
+ /* Turn on the backlight! */
+ gpio_set_value(omap3logic_dss_lcd_data.lcd_gpio_backlight, 1);
+#endif
+ }
+
+ /* 255 -> 1, 1 -> 126 */
+ c = (max_brightness * 126 + (1 - 126) * level) / (max_brightness - 1);
+
+ PWM_PRINT("%s: c %d (%d%% on)\n", __FUNCTION__, c, (((max_brightness+1)-c) * 100)/(max_brightness+1));
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_PWM0, 0x7F, TWL_LED_PWMOFF);
+ if (status) {
+ PWM_PRINT("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -6;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_PWM0, c, TWL_LED_PWMON);
+ if (status) {
+ PWM_PRINT("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -7;
+ }
+ return 0;
+}
+
+void twl4030_dump_pwm0(void)
+{
+ int result;
+ u8 mux_pwm, enb_pwm;
+ u8 off_period, on_period;
+
+ result = twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &mux_pwm,
+ TWL_INTBR_PMBR1);
+ result |= twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &enb_pwm,
+ TWL_INTBR_GPBR1);
+
+ result |= twl4030_i2c_read_u8(TWL4030_CHIP_PWM0, &off_period,
+ TWL_LED_PWMOFF);
+ result |=twl4030_i2c_read_u8(TWL4030_CHIP_PWM0, &on_period,
+ TWL_LED_PWMON);
+
+ if (result) {
+ printf("%s: failed to read TWL regitsters; result %d\n", __FUNCTION__, result);
+ return;
+ }
+ printf("%s: mux_pwm %02x enb_pwm %02x off_period %02x on_period %02x\n",
+ __FUNCTION__, mux_pwm, enb_pwm, off_period, on_period);
+}