xref: /openbmc/linux/drivers/mfd/wm8350-gpio.c (revision 2874c5fd)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20e720393SMark Brown /*
30e720393SMark Brown  * wm8350-core.c  --  Device access for Wolfson WM8350
40e720393SMark Brown  *
50e720393SMark Brown  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
60e720393SMark Brown  *
70e720393SMark Brown  * Author: Liam Girdwood
80e720393SMark Brown  */
90e720393SMark Brown 
100e720393SMark Brown #include <linux/kernel.h>
110e720393SMark Brown #include <linux/module.h>
120e720393SMark Brown #include <linux/errno.h>
130e720393SMark Brown 
140e720393SMark Brown #include <linux/mfd/wm8350/core.h>
150e720393SMark Brown #include <linux/mfd/wm8350/gpio.h>
160e720393SMark Brown #include <linux/mfd/wm8350/pmic.h>
170e720393SMark Brown 
gpio_set_dir(struct wm8350 * wm8350,int gpio,int dir)180e720393SMark Brown static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
190e720393SMark Brown {
200e720393SMark Brown 	int ret;
210e720393SMark Brown 
220e720393SMark Brown 	wm8350_reg_unlock(wm8350);
230e720393SMark Brown 	if (dir == WM8350_GPIO_DIR_OUT)
240e720393SMark Brown 		ret = wm8350_clear_bits(wm8350,
250e720393SMark Brown 					WM8350_GPIO_CONFIGURATION_I_O,
260e720393SMark Brown 					1 << gpio);
270e720393SMark Brown 	else
280e720393SMark Brown 		ret = wm8350_set_bits(wm8350,
290e720393SMark Brown 				      WM8350_GPIO_CONFIGURATION_I_O,
300e720393SMark Brown 				      1 << gpio);
310e720393SMark Brown 	wm8350_reg_lock(wm8350);
320e720393SMark Brown 	return ret;
330e720393SMark Brown }
340e720393SMark Brown 
wm8350_gpio_set_debounce(struct wm8350 * wm8350,int gpio,int db)35aa9d842cSSascha Hauer static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
360e720393SMark Brown {
370e720393SMark Brown 	if (db == WM8350_GPIO_DEBOUNCE_ON)
380e720393SMark Brown 		return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
390e720393SMark Brown 				       1 << gpio);
400e720393SMark Brown 	else
410e720393SMark Brown 		return wm8350_clear_bits(wm8350,
420e720393SMark Brown 					 WM8350_GPIO_DEBOUNCE, 1 << gpio);
430e720393SMark Brown }
440e720393SMark Brown 
gpio_set_func(struct wm8350 * wm8350,int gpio,int func)450e720393SMark Brown static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
460e720393SMark Brown {
470e720393SMark Brown 	u16 reg;
480e720393SMark Brown 
490e720393SMark Brown 	wm8350_reg_unlock(wm8350);
500e720393SMark Brown 	switch (gpio) {
510e720393SMark Brown 	case 0:
520e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
530e720393SMark Brown 		    & ~WM8350_GP0_FN_MASK;
540e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
550e720393SMark Brown 				 reg | ((func & 0xf) << 0));
560e720393SMark Brown 		break;
570e720393SMark Brown 	case 1:
580e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
590e720393SMark Brown 		    & ~WM8350_GP1_FN_MASK;
600e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
610e720393SMark Brown 				 reg | ((func & 0xf) << 4));
620e720393SMark Brown 		break;
630e720393SMark Brown 	case 2:
640e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
650e720393SMark Brown 		    & ~WM8350_GP2_FN_MASK;
660e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
670e720393SMark Brown 				 reg | ((func & 0xf) << 8));
680e720393SMark Brown 		break;
690e720393SMark Brown 	case 3:
700e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
710e720393SMark Brown 		    & ~WM8350_GP3_FN_MASK;
720e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
730e720393SMark Brown 				 reg | ((func & 0xf) << 12));
740e720393SMark Brown 		break;
750e720393SMark Brown 	case 4:
760e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
770e720393SMark Brown 		    & ~WM8350_GP4_FN_MASK;
780e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
790e720393SMark Brown 				 reg | ((func & 0xf) << 0));
800e720393SMark Brown 		break;
810e720393SMark Brown 	case 5:
820e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
830e720393SMark Brown 		    & ~WM8350_GP5_FN_MASK;
840e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
850e720393SMark Brown 				 reg | ((func & 0xf) << 4));
860e720393SMark Brown 		break;
870e720393SMark Brown 	case 6:
880e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
890e720393SMark Brown 		    & ~WM8350_GP6_FN_MASK;
900e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
910e720393SMark Brown 				 reg | ((func & 0xf) << 8));
920e720393SMark Brown 		break;
930e720393SMark Brown 	case 7:
940e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
950e720393SMark Brown 		    & ~WM8350_GP7_FN_MASK;
960e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
970e720393SMark Brown 				 reg | ((func & 0xf) << 12));
980e720393SMark Brown 		break;
990e720393SMark Brown 	case 8:
1000e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
1010e720393SMark Brown 		    & ~WM8350_GP8_FN_MASK;
1020e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
1030e720393SMark Brown 				 reg | ((func & 0xf) << 0));
1040e720393SMark Brown 		break;
1050e720393SMark Brown 	case 9:
1060e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
1070e720393SMark Brown 		    & ~WM8350_GP9_FN_MASK;
1080e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
1090e720393SMark Brown 				 reg | ((func & 0xf) << 4));
1100e720393SMark Brown 		break;
1110e720393SMark Brown 	case 10:
1120e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
1130e720393SMark Brown 		    & ~WM8350_GP10_FN_MASK;
1140e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
1150e720393SMark Brown 				 reg | ((func & 0xf) << 8));
1160e720393SMark Brown 		break;
1170e720393SMark Brown 	case 11:
1180e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
1190e720393SMark Brown 		    & ~WM8350_GP11_FN_MASK;
1200e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
1210e720393SMark Brown 				 reg | ((func & 0xf) << 12));
1220e720393SMark Brown 		break;
1230e720393SMark Brown 	case 12:
1240e720393SMark Brown 		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
1250e720393SMark Brown 		    & ~WM8350_GP12_FN_MASK;
1260e720393SMark Brown 		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
1270e720393SMark Brown 				 reg | ((func & 0xf) << 0));
1280e720393SMark Brown 		break;
1290e720393SMark Brown 	default:
1300e720393SMark Brown 		wm8350_reg_lock(wm8350);
1310e720393SMark Brown 		return -EINVAL;
1320e720393SMark Brown 	}
1330e720393SMark Brown 
1340e720393SMark Brown 	wm8350_reg_lock(wm8350);
1350e720393SMark Brown 	return 0;
1360e720393SMark Brown }
1370e720393SMark Brown 
gpio_set_pull_up(struct wm8350 * wm8350,int gpio,int up)1380e720393SMark Brown static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
1390e720393SMark Brown {
1400e720393SMark Brown 	if (up)
1410e720393SMark Brown 		return wm8350_set_bits(wm8350,
1420e720393SMark Brown 				       WM8350_GPIO_PIN_PULL_UP_CONTROL,
1430e720393SMark Brown 				       1 << gpio);
1440e720393SMark Brown 	else
1450e720393SMark Brown 		return wm8350_clear_bits(wm8350,
1460e720393SMark Brown 					 WM8350_GPIO_PIN_PULL_UP_CONTROL,
1470e720393SMark Brown 					 1 << gpio);
1480e720393SMark Brown }
1490e720393SMark Brown 
gpio_set_pull_down(struct wm8350 * wm8350,int gpio,int down)1500e720393SMark Brown static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
1510e720393SMark Brown {
1520e720393SMark Brown 	if (down)
1530e720393SMark Brown 		return wm8350_set_bits(wm8350,
1540e720393SMark Brown 				       WM8350_GPIO_PULL_DOWN_CONTROL,
1550e720393SMark Brown 				       1 << gpio);
1560e720393SMark Brown 	else
1570e720393SMark Brown 		return wm8350_clear_bits(wm8350,
1580e720393SMark Brown 					 WM8350_GPIO_PULL_DOWN_CONTROL,
1590e720393SMark Brown 					 1 << gpio);
1600e720393SMark Brown }
1610e720393SMark Brown 
gpio_set_polarity(struct wm8350 * wm8350,int gpio,int pol)1620e720393SMark Brown static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
1630e720393SMark Brown {
1640e720393SMark Brown 	if (pol == WM8350_GPIO_ACTIVE_HIGH)
1650e720393SMark Brown 		return wm8350_set_bits(wm8350,
1660e720393SMark Brown 				       WM8350_GPIO_PIN_POLARITY_TYPE,
1670e720393SMark Brown 				       1 << gpio);
1680e720393SMark Brown 	else
1690e720393SMark Brown 		return wm8350_clear_bits(wm8350,
1700e720393SMark Brown 					 WM8350_GPIO_PIN_POLARITY_TYPE,
1710e720393SMark Brown 					 1 << gpio);
1720e720393SMark Brown }
1730e720393SMark Brown 
gpio_set_invert(struct wm8350 * wm8350,int gpio,int invert)1740e720393SMark Brown static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
1750e720393SMark Brown {
1760e720393SMark Brown 	if (invert == WM8350_GPIO_INVERT_ON)
1770e720393SMark Brown 		return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
1780e720393SMark Brown 	else
1790e720393SMark Brown 		return wm8350_clear_bits(wm8350,
1800e720393SMark Brown 					 WM8350_GPIO_INT_MODE, 1 << gpio);
1810e720393SMark Brown }
1820e720393SMark Brown 
wm8350_gpio_config(struct wm8350 * wm8350,int gpio,int dir,int func,int pol,int pull,int invert,int debounce)1830e720393SMark Brown int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
1840e720393SMark Brown 		       int pol, int pull, int invert, int debounce)
1850e720393SMark Brown {
1860e720393SMark Brown 	/* make sure we never pull up and down at the same time */
1870e720393SMark Brown 	if (pull == WM8350_GPIO_PULL_NONE) {
1880e720393SMark Brown 		if (gpio_set_pull_up(wm8350, gpio, 0))
1890e720393SMark Brown 			goto err;
1900e720393SMark Brown 		if (gpio_set_pull_down(wm8350, gpio, 0))
1910e720393SMark Brown 			goto err;
1920e720393SMark Brown 	} else if (pull == WM8350_GPIO_PULL_UP) {
1930e720393SMark Brown 		if (gpio_set_pull_down(wm8350, gpio, 0))
1940e720393SMark Brown 			goto err;
1950e720393SMark Brown 		if (gpio_set_pull_up(wm8350, gpio, 1))
1960e720393SMark Brown 			goto err;
1970e720393SMark Brown 	} else if (pull == WM8350_GPIO_PULL_DOWN) {
1980e720393SMark Brown 		if (gpio_set_pull_up(wm8350, gpio, 0))
1990e720393SMark Brown 			goto err;
2000e720393SMark Brown 		if (gpio_set_pull_down(wm8350, gpio, 1))
2010e720393SMark Brown 			goto err;
2020e720393SMark Brown 	}
2030e720393SMark Brown 
2040e720393SMark Brown 	if (gpio_set_invert(wm8350, gpio, invert))
2050e720393SMark Brown 		goto err;
2060e720393SMark Brown 	if (gpio_set_polarity(wm8350, gpio, pol))
2070e720393SMark Brown 		goto err;
208aa9d842cSSascha Hauer 	if (wm8350_gpio_set_debounce(wm8350, gpio, debounce))
2090e720393SMark Brown 		goto err;
2100e720393SMark Brown 	if (gpio_set_dir(wm8350, gpio, dir))
2110e720393SMark Brown 		goto err;
2120e720393SMark Brown 	return gpio_set_func(wm8350, gpio, func);
2130e720393SMark Brown 
2140e720393SMark Brown err:
2150e720393SMark Brown 	return -EIO;
2160e720393SMark Brown }
2170e720393SMark Brown EXPORT_SYMBOL_GPL(wm8350_gpio_config);
218