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