1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * UP Board FPGA driver. 4 * 5 * FPGA provides more GPIO driving power, LEDS and pin mux function. 6 * 7 * Copyright (c) AAEON. All rights reserved. 8 * Copyright (C) 2024 Bootlin 9 * 10 * Author: Gary Wang <garywang@aaeon.com.tw> 11 * Author: Thomas Richard <thomas.richard@bootlin.com> 12 */ 13 14 #include <linux/bitfield.h> 15 #include <linux/device.h> 16 #include <linux/err.h> 17 #include <linux/gpio/consumer.h> 18 #include <linux/mfd/core.h> 19 #include <linux/mfd/upboard-fpga.h> 20 #include <linux/module.h> 21 #include <linux/platform_device.h> 22 #include <linux/property.h> 23 #include <linux/regmap.h> 24 #include <linux/sysfs.h> 25 26 #define UPBOARD_AAEON_MANUFACTURER_ID 0x01 27 #define UPBOARD_MANUFACTURER_ID_MASK GENMASK(7, 0) 28 29 #define UPBOARD_ADDRESS_SIZE 7 30 #define UPBOARD_REGISTER_SIZE 16 31 32 #define UPBOARD_READ_FLAG BIT(UPBOARD_ADDRESS_SIZE) 33 34 #define UPBOARD_FW_ID_MAJOR_SUPPORTED 0x0 35 36 #define UPBOARD_FW_ID_BUILD_MASK GENMASK(15, 12) 37 #define UPBOARD_FW_ID_MAJOR_MASK GENMASK(11, 8) 38 #define UPBOARD_FW_ID_MINOR_MASK GENMASK(7, 4) 39 #define UPBOARD_FW_ID_PATCH_MASK GENMASK(3, 0) 40 41 static int upboard_fpga_read(void *context, unsigned int reg, unsigned int *val) 42 { 43 struct upboard_fpga *fpga = context; 44 int i; 45 46 /* Clear to start new transaction */ 47 gpiod_set_value(fpga->clear_gpio, 0); 48 gpiod_set_value(fpga->clear_gpio, 1); 49 50 reg |= UPBOARD_READ_FLAG; 51 52 /* Send clock and addr from strobe & datain pins */ 53 for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) { 54 gpiod_set_value(fpga->strobe_gpio, 0); 55 gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i))); 56 gpiod_set_value(fpga->strobe_gpio, 1); 57 } 58 59 gpiod_set_value(fpga->strobe_gpio, 0); 60 *val = 0; 61 62 /* Read data from dataout pin */ 63 for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) { 64 gpiod_set_value(fpga->strobe_gpio, 1); 65 gpiod_set_value(fpga->strobe_gpio, 0); 66 *val |= gpiod_get_value(fpga->dataout_gpio) << i; 67 } 68 69 gpiod_set_value(fpga->strobe_gpio, 1); 70 71 return 0; 72 } 73 74 static int upboard_fpga_write(void *context, unsigned int reg, unsigned int val) 75 { 76 struct upboard_fpga *fpga = context; 77 int i; 78 79 /* Clear to start new transcation */ 80 gpiod_set_value(fpga->clear_gpio, 0); 81 gpiod_set_value(fpga->clear_gpio, 1); 82 83 /* Send clock and addr from strobe & datain pins */ 84 for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) { 85 gpiod_set_value(fpga->strobe_gpio, 0); 86 gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i))); 87 gpiod_set_value(fpga->strobe_gpio, 1); 88 } 89 90 gpiod_set_value(fpga->strobe_gpio, 0); 91 92 /* Write data to datain pin */ 93 for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) { 94 gpiod_set_value(fpga->datain_gpio, !!(val & BIT(i))); 95 gpiod_set_value(fpga->strobe_gpio, 1); 96 gpiod_set_value(fpga->strobe_gpio, 0); 97 } 98 99 gpiod_set_value(fpga->strobe_gpio, 1); 100 101 return 0; 102 } 103 104 static const struct regmap_range upboard_up_readable_ranges[] = { 105 regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID), 106 regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0), 107 regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1), 108 regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1), 109 }; 110 111 static const struct regmap_range upboard_up_writable_ranges[] = { 112 regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0), 113 regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1), 114 regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1), 115 }; 116 117 static const struct regmap_access_table upboard_up_readable_table = { 118 .yes_ranges = upboard_up_readable_ranges, 119 .n_yes_ranges = ARRAY_SIZE(upboard_up_readable_ranges), 120 }; 121 122 static const struct regmap_access_table upboard_up_writable_table = { 123 .yes_ranges = upboard_up_writable_ranges, 124 .n_yes_ranges = ARRAY_SIZE(upboard_up_writable_ranges), 125 }; 126 127 static const struct regmap_config upboard_up_regmap_config = { 128 .reg_bits = UPBOARD_ADDRESS_SIZE, 129 .val_bits = UPBOARD_REGISTER_SIZE, 130 .max_register = UPBOARD_REG_MAX, 131 .reg_read = upboard_fpga_read, 132 .reg_write = upboard_fpga_write, 133 .fast_io = false, 134 .cache_type = REGCACHE_NONE, 135 .rd_table = &upboard_up_readable_table, 136 .wr_table = &upboard_up_writable_table, 137 }; 138 139 static const struct regmap_range upboard_up2_readable_ranges[] = { 140 regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID), 141 regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1), 142 regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2), 143 regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2), 144 }; 145 146 static const struct regmap_range upboard_up2_writable_ranges[] = { 147 regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1), 148 regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2), 149 regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2), 150 }; 151 152 static const struct regmap_access_table upboard_up2_readable_table = { 153 .yes_ranges = upboard_up2_readable_ranges, 154 .n_yes_ranges = ARRAY_SIZE(upboard_up2_readable_ranges), 155 }; 156 157 static const struct regmap_access_table upboard_up2_writable_table = { 158 .yes_ranges = upboard_up2_writable_ranges, 159 .n_yes_ranges = ARRAY_SIZE(upboard_up2_writable_ranges), 160 }; 161 162 static const struct regmap_config upboard_up2_regmap_config = { 163 .reg_bits = UPBOARD_ADDRESS_SIZE, 164 .val_bits = UPBOARD_REGISTER_SIZE, 165 .max_register = UPBOARD_REG_MAX, 166 .reg_read = upboard_fpga_read, 167 .reg_write = upboard_fpga_write, 168 .fast_io = false, 169 .cache_type = REGCACHE_NONE, 170 .rd_table = &upboard_up2_readable_table, 171 .wr_table = &upboard_up2_writable_table, 172 }; 173 174 static const struct mfd_cell upboard_up_mfd_cells[] = { 175 { .name = "upboard-pinctrl" }, 176 { .name = "upboard-leds" }, 177 }; 178 179 static const struct upboard_fpga_data upboard_up_fpga_data = { 180 .type = UPBOARD_UP_FPGA, 181 .regmap_config = &upboard_up_regmap_config, 182 }; 183 184 static const struct upboard_fpga_data upboard_up2_fpga_data = { 185 .type = UPBOARD_UP2_FPGA, 186 .regmap_config = &upboard_up2_regmap_config, 187 }; 188 189 static int upboard_fpga_gpio_init(struct upboard_fpga *fpga) 190 { 191 fpga->enable_gpio = devm_gpiod_get(fpga->dev, "enable", GPIOD_ASIS); 192 if (IS_ERR(fpga->enable_gpio)) 193 return PTR_ERR(fpga->enable_gpio); 194 195 fpga->clear_gpio = devm_gpiod_get(fpga->dev, "clear", GPIOD_OUT_LOW); 196 if (IS_ERR(fpga->clear_gpio)) 197 return PTR_ERR(fpga->clear_gpio); 198 199 fpga->strobe_gpio = devm_gpiod_get(fpga->dev, "strobe", GPIOD_OUT_LOW); 200 if (IS_ERR(fpga->strobe_gpio)) 201 return PTR_ERR(fpga->strobe_gpio); 202 203 fpga->datain_gpio = devm_gpiod_get(fpga->dev, "datain", GPIOD_OUT_LOW); 204 if (IS_ERR(fpga->datain_gpio)) 205 return PTR_ERR(fpga->datain_gpio); 206 207 fpga->dataout_gpio = devm_gpiod_get(fpga->dev, "dataout", GPIOD_IN); 208 if (IS_ERR(fpga->dataout_gpio)) 209 return PTR_ERR(fpga->dataout_gpio); 210 211 gpiod_set_value(fpga->enable_gpio, 1); 212 213 return 0; 214 } 215 216 static int upboard_fpga_get_firmware_version(struct upboard_fpga *fpga) 217 { 218 unsigned int platform_id, manufacturer_id; 219 int ret; 220 221 if (!fpga) 222 return -ENOMEM; 223 224 ret = regmap_read(fpga->regmap, UPBOARD_REG_PLATFORM_ID, &platform_id); 225 if (ret) 226 return ret; 227 228 manufacturer_id = platform_id & UPBOARD_MANUFACTURER_ID_MASK; 229 if (manufacturer_id != UPBOARD_AAEON_MANUFACTURER_ID) 230 return dev_err_probe(fpga->dev, -ENODEV, 231 "driver not compatible with custom FPGA FW from manufacturer id %#02x.", 232 manufacturer_id); 233 234 ret = regmap_read(fpga->regmap, UPBOARD_REG_FIRMWARE_ID, &fpga->firmware_version); 235 if (ret) 236 return ret; 237 238 if (FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version) != 239 UPBOARD_FW_ID_MAJOR_SUPPORTED) 240 return dev_err_probe(fpga->dev, -ENODEV, 241 "unsupported FPGA FW v%lu.%lu.%lu build %#02lx", 242 FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version), 243 FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version), 244 FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version), 245 FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version)); 246 return 0; 247 } 248 249 static ssize_t upboard_fpga_version_show(struct device *dev, struct device_attribute *attr, 250 char *buf) 251 { 252 struct upboard_fpga *fpga = dev_get_drvdata(dev); 253 254 return sysfs_emit(buf, "FPGA FW v%lu.%lu.%lu build %#02lx\n", 255 FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version), 256 FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version), 257 FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version), 258 FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version)); 259 } 260 261 static DEVICE_ATTR_RO(upboard_fpga_version); 262 263 static struct attribute *upboard_fpga_attrs[] = { 264 &dev_attr_upboard_fpga_version.attr, 265 NULL 266 }; 267 268 ATTRIBUTE_GROUPS(upboard_fpga); 269 270 static int upboard_fpga_probe(struct platform_device *pdev) 271 { 272 struct device *dev = &pdev->dev; 273 struct upboard_fpga *fpga; 274 int ret; 275 276 fpga = devm_kzalloc(dev, sizeof(*fpga), GFP_KERNEL); 277 if (!fpga) 278 return -ENOMEM; 279 280 fpga->fpga_data = device_get_match_data(dev); 281 282 fpga->dev = dev; 283 284 platform_set_drvdata(pdev, fpga); 285 286 fpga->regmap = devm_regmap_init(dev, NULL, fpga, fpga->fpga_data->regmap_config); 287 if (IS_ERR(fpga->regmap)) 288 return PTR_ERR(fpga->regmap); 289 290 ret = upboard_fpga_gpio_init(fpga); 291 if (ret) 292 return dev_err_probe(dev, ret, "Failed to initialize FPGA common GPIOs"); 293 294 ret = upboard_fpga_get_firmware_version(fpga); 295 if (ret) 296 return ret; 297 298 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, upboard_up_mfd_cells, 299 ARRAY_SIZE(upboard_up_mfd_cells), NULL, 0, NULL); 300 } 301 302 static const struct acpi_device_id upboard_fpga_acpi_match[] = { 303 { "AANT0F01", (kernel_ulong_t)&upboard_up2_fpga_data }, 304 { "AANT0F04", (kernel_ulong_t)&upboard_up_fpga_data }, 305 {} 306 }; 307 MODULE_DEVICE_TABLE(acpi, upboard_fpga_acpi_match); 308 309 static struct platform_driver upboard_fpga_driver = { 310 .driver = { 311 .name = "upboard-fpga", 312 .acpi_match_table = upboard_fpga_acpi_match, 313 .dev_groups = upboard_fpga_groups, 314 }, 315 .probe = upboard_fpga_probe, 316 }; 317 318 module_platform_driver(upboard_fpga_driver); 319 320 MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>"); 321 MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>"); 322 MODULE_DESCRIPTION("UP Board FPGA driver"); 323 MODULE_LICENSE("GPL"); 324