1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com> 4 */ 5 6#include <dm.h> 7#include <asm/gpio.h> 8#include <power/max77663.h> 9#include <power/pmic.h> 10 11#define NUM_ENTRIES 11 /* 8 GPIOs + 3 KEYs */ 12#define NUM_GPIOS 8 13 14#define MAX77663_CNFG1_GPIO 0x36 15#define GPIO_REG_ADDR(offset) (MAX77663_CNFG1_GPIO + (offset)) 16 17#define MAX77663_CNFG_GPIO_DIR_MASK BIT(1) 18#define MAX77663_CNFG_GPIO_DIR_INPUT BIT(1) 19#define MAX77663_CNFG_GPIO_DIR_OUTPUT 0 20#define MAX77663_CNFG_GPIO_INPUT_VAL_MASK BIT(2) 21#define MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK BIT(3) 22#define MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH BIT(3) 23#define MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW 0 24#define MAX77663_CNFG_IRQ GENMASK(5, 4) 25 26#define MAX77663_ONOFFSTAT_REG 0x15 27#define EN0 BIT(2) /* KEY 2 */ 28#define ACOK BIT(1) /* KEY 1 */ 29#define LID BIT(0) /* KEY 0 */ 30 31static int max77663_gpio_direction_input(struct udevice *dev, unsigned int offset) 32{ 33 int ret; 34 35 if (offset >= NUM_GPIOS) 36 return 0; 37 38 ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset), 39 MAX77663_CNFG_GPIO_DIR_MASK, 40 MAX77663_CNFG_GPIO_DIR_INPUT); 41 if (ret < 0) 42 log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret); 43 44 return ret; 45} 46 47static int max77663_gpio_direction_output(struct udevice *dev, unsigned int offset, 48 int value) 49{ 50 u8 val; 51 int ret; 52 53 if (offset >= NUM_GPIOS) 54 return -EINVAL; 55 56 val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH : 57 MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW; 58 59 ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset), 60 MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val); 61 if (ret < 0) { 62 log_debug("%s: CNFG_GPIOx val update failed: %d\n", __func__, ret); 63 return ret; 64 } 65 66 ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset), 67 MAX77663_CNFG_GPIO_DIR_MASK, 68 MAX77663_CNFG_GPIO_DIR_OUTPUT); 69 if (ret < 0) 70 log_debug("%s: CNFG_GPIOx dir update failed: %d\n", __func__, ret); 71 72 return ret; 73} 74 75static int max77663_gpio_get_value(struct udevice *dev, unsigned int offset) 76{ 77 int ret; 78 79 if (offset >= NUM_GPIOS) { 80 ret = pmic_reg_read(dev->parent, MAX77663_ONOFFSTAT_REG); 81 if (ret < 0) { 82 log_debug("%s: ONOFFSTAT_REG read failed: %d\n", __func__, ret); 83 return ret; 84 } 85 86 return !!(ret & BIT(offset - NUM_GPIOS)); 87 } 88 89 ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset)); 90 if (ret < 0) { 91 log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret); 92 return ret; 93 } 94 95 if (ret & MAX77663_CNFG_GPIO_DIR_MASK) 96 return !!(ret & MAX77663_CNFG_GPIO_INPUT_VAL_MASK); 97 else 98 return !!(ret & MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK); 99} 100 101static int max77663_gpio_set_value(struct udevice *dev, unsigned int offset, 102 int value) 103{ 104 u8 val; 105 int ret; 106 107 if (offset >= NUM_GPIOS) 108 return -EINVAL; 109 110 val = (value) ? MAX77663_CNFG_GPIO_OUTPUT_VAL_HIGH : 111 MAX77663_CNFG_GPIO_OUTPUT_VAL_LOW; 112 113 ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(offset), 114 MAX77663_CNFG_GPIO_OUTPUT_VAL_MASK, val); 115 if (ret < 0) 116 log_debug("%s: CNFG_GPIO_OUT update failed: %d\n", __func__, ret); 117 118 return ret; 119} 120 121static int max77663_gpio_get_function(struct udevice *dev, unsigned int offset) 122{ 123 int ret; 124 125 if (offset >= NUM_GPIOS) 126 return GPIOF_INPUT; 127 128 ret = pmic_reg_read(dev->parent, GPIO_REG_ADDR(offset)); 129 if (ret < 0) { 130 log_debug("%s: CNFG_GPIOx read failed: %d\n", __func__, ret); 131 return ret; 132 } 133 134 if (ret & MAX77663_CNFG_GPIO_DIR_MASK) 135 return GPIOF_INPUT; 136 else 137 return GPIOF_OUTPUT; 138} 139 140static const struct dm_gpio_ops max77663_gpio_ops = { 141 .direction_input = max77663_gpio_direction_input, 142 .direction_output = max77663_gpio_direction_output, 143 .get_value = max77663_gpio_get_value, 144 .set_value = max77663_gpio_set_value, 145 .get_function = max77663_gpio_get_function, 146}; 147 148static int max77663_gpio_probe(struct udevice *dev) 149{ 150 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 151 int i, ret; 152 153 uc_priv->gpio_count = NUM_ENTRIES; 154 uc_priv->bank_name = "GPIO"; 155 156 /* 157 * GPIO interrupts may be left ON after bootloader, hence let's 158 * pre-initialize hardware to the expected state by disabling all 159 * the interrupts. 160 */ 161 for (i = 0; i < NUM_GPIOS; i++) { 162 ret = pmic_clrsetbits(dev->parent, GPIO_REG_ADDR(i), 163 MAX77663_CNFG_IRQ, 0); 164 if (ret < 0) { 165 log_debug("%s: failed to disable interrupt: %d\n", __func__, ret); 166 return ret; 167 } 168 } 169 170 return 0; 171} 172 173U_BOOT_DRIVER(max77663_gpio) = { 174 .name = MAX77663_GPIO_DRIVER, 175 .id = UCLASS_GPIO, 176 .probe = max77663_gpio_probe, 177 .ops = &max77663_gpio_ops, 178}; 179