Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / mfd / wm8350-gpio.c
diff --git a/kernel/drivers/mfd/wm8350-gpio.c b/kernel/drivers/mfd/wm8350-gpio.c
new file mode 100644 (file)
index 0000000..d584f6b
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * wm8350-core.c  --  Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+
+static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
+{
+       int ret;
+
+       wm8350_reg_unlock(wm8350);
+       if (dir == WM8350_GPIO_DIR_OUT)
+               ret = wm8350_clear_bits(wm8350,
+                                       WM8350_GPIO_CONFIGURATION_I_O,
+                                       1 << gpio);
+       else
+               ret = wm8350_set_bits(wm8350,
+                                     WM8350_GPIO_CONFIGURATION_I_O,
+                                     1 << gpio);
+       wm8350_reg_lock(wm8350);
+       return ret;
+}
+
+static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+{
+       if (db == WM8350_GPIO_DEBOUNCE_ON)
+               return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_DEBOUNCE, 1 << gpio);
+}
+
+static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
+{
+       u16 reg;
+
+       wm8350_reg_unlock(wm8350);
+       switch (gpio) {
+       case 0:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP0_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 1:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP1_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 2:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP2_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 3:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+                   & ~WM8350_GP3_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 4:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP4_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 5:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP5_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 6:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP6_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 7:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+                   & ~WM8350_GP7_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 8:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP8_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 0));
+               break;
+       case 9:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP9_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 4));
+               break;
+       case 10:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP10_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 8));
+               break;
+       case 11:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+                   & ~WM8350_GP11_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+                                reg | ((func & 0xf) << 12));
+               break;
+       case 12:
+               reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
+                   & ~WM8350_GP12_FN_MASK;
+               wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
+                                reg | ((func & 0xf) << 0));
+               break;
+       default:
+               wm8350_reg_lock(wm8350);
+               return -EINVAL;
+       }
+
+       wm8350_reg_lock(wm8350);
+       return 0;
+}
+
+static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
+{
+       if (up)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PIN_PULL_UP_CONTROL,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PIN_PULL_UP_CONTROL,
+                                        1 << gpio);
+}
+
+static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
+{
+       if (down)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PULL_DOWN_CONTROL,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PULL_DOWN_CONTROL,
+                                        1 << gpio);
+}
+
+static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
+{
+       if (pol == WM8350_GPIO_ACTIVE_HIGH)
+               return wm8350_set_bits(wm8350,
+                                      WM8350_GPIO_PIN_POLARITY_TYPE,
+                                      1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_PIN_POLARITY_TYPE,
+                                        1 << gpio);
+}
+
+static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
+{
+       if (invert == WM8350_GPIO_INVERT_ON)
+               return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
+       else
+               return wm8350_clear_bits(wm8350,
+                                        WM8350_GPIO_INT_MODE, 1 << gpio);
+}
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+                      int pol, int pull, int invert, int debounce)
+{
+       /* make sure we never pull up and down at the same time */
+       if (pull == WM8350_GPIO_PULL_NONE) {
+               if (gpio_set_pull_up(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_down(wm8350, gpio, 0))
+                       goto err;
+       } else if (pull == WM8350_GPIO_PULL_UP) {
+               if (gpio_set_pull_down(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_up(wm8350, gpio, 1))
+                       goto err;
+       } else if (pull == WM8350_GPIO_PULL_DOWN) {
+               if (gpio_set_pull_up(wm8350, gpio, 0))
+                       goto err;
+               if (gpio_set_pull_down(wm8350, gpio, 1))
+                       goto err;
+       }
+
+       if (gpio_set_invert(wm8350, gpio, invert))
+               goto err;
+       if (gpio_set_polarity(wm8350, gpio, pol))
+               goto err;
+       if (wm8350_gpio_set_debounce(wm8350, gpio, debounce))
+               goto err;
+       if (gpio_set_dir(wm8350, gpio, dir))
+               goto err;
+       return gpio_set_func(wm8350, gpio, func);
+
+err:
+       return -EIO;
+}
+EXPORT_SYMBOL_GPL(wm8350_gpio_config);