1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * TQ-Systems PLD MFD core driver, based on vendor driver by 4 * Vadim V.Vlasov <vvlasov@dev.rtsoft.ru> 5 * 6 * Copyright (c) 2015 TQ-Systems GmbH 7 * Copyright (c) 2019 Andrew Lunn <andrew@lunn.ch> 8 */ 9 10 #include <linux/delay.h> 11 #include <linux/dmi.h> 12 #include <linux/i2c.h> 13 #include <linux/io.h> 14 #include <linux/mfd/core.h> 15 #include <linux/module.h> 16 #include <linux/platform_data/i2c-ocores.h> 17 #include <linux/platform_device.h> 18 19 #define TQMX86_IOBASE 0x180 20 #define TQMX86_IOSIZE 0x20 21 #define TQMX86_IOBASE_I2C 0x1a0 22 #define TQMX86_IOSIZE_I2C 0xa 23 #define TQMX86_IOBASE_WATCHDOG 0x18b 24 #define TQMX86_IOSIZE_WATCHDOG 0x2 25 #define TQMX86_IOBASE_GPIO 0x18d 26 #define TQMX86_IOSIZE_GPIO 0x4 27 28 #define TQMX86_REG_BOARD_ID 0x00 29 #define TQMX86_REG_BOARD_ID_E38M 1 30 #define TQMX86_REG_BOARD_ID_50UC 2 31 #define TQMX86_REG_BOARD_ID_E38C 3 32 #define TQMX86_REG_BOARD_ID_60EB 4 33 #define TQMX86_REG_BOARD_ID_E39MS 5 34 #define TQMX86_REG_BOARD_ID_E39C1 6 35 #define TQMX86_REG_BOARD_ID_E39C2 7 36 #define TQMX86_REG_BOARD_ID_70EB 8 37 #define TQMX86_REG_BOARD_ID_80UC 9 38 #define TQMX86_REG_BOARD_ID_110EB 11 39 #define TQMX86_REG_BOARD_ID_E40M 12 40 #define TQMX86_REG_BOARD_ID_E40S 13 41 #define TQMX86_REG_BOARD_ID_E40C1 14 42 #define TQMX86_REG_BOARD_ID_E40C2 15 43 #define TQMX86_REG_BOARD_REV 0x01 44 #define TQMX86_REG_IO_EXT_INT 0x06 45 #define TQMX86_REG_IO_EXT_INT_NONE 0 46 #define TQMX86_REG_IO_EXT_INT_7 1 47 #define TQMX86_REG_IO_EXT_INT_9 2 48 #define TQMX86_REG_IO_EXT_INT_12 3 49 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 50 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 51 #define TQMX86_REG_SAUC 0x17 52 53 #define TQMX86_REG_I2C_DETECT 0x1a7 54 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 55 56 static uint gpio_irq; 57 module_param(gpio_irq, uint, 0); 58 MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (7, 9, 12)"); 59 60 static const struct resource tqmx_i2c_soft_resources[] = { 61 DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), 62 }; 63 64 static const struct resource tqmx_watchdog_resources[] = { 65 DEFINE_RES_IO(TQMX86_IOBASE_WATCHDOG, TQMX86_IOSIZE_WATCHDOG), 66 }; 67 68 /* 69 * The IRQ resource must be first, since it is updated with the 70 * configured IRQ in the probe function. 71 */ 72 static struct resource tqmx_gpio_resources[] = { 73 DEFINE_RES_IRQ(0), 74 DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), 75 }; 76 77 static struct i2c_board_info tqmx86_i2c_devices[] = { 78 { 79 /* 4K EEPROM at 0x50 */ 80 I2C_BOARD_INFO("24c32", 0x50), 81 }, 82 }; 83 84 static struct ocores_i2c_platform_data ocores_platform_data = { 85 .num_devices = ARRAY_SIZE(tqmx86_i2c_devices), 86 .devices = tqmx86_i2c_devices, 87 }; 88 89 static const struct mfd_cell tqmx86_i2c_soft_dev[] = { 90 { 91 .name = "ocores-i2c", 92 .platform_data = &ocores_platform_data, 93 .pdata_size = sizeof(ocores_platform_data), 94 .resources = tqmx_i2c_soft_resources, 95 .num_resources = ARRAY_SIZE(tqmx_i2c_soft_resources), 96 }, 97 }; 98 99 static const struct mfd_cell tqmx86_devs[] = { 100 { 101 .name = "tqmx86-wdt", 102 .resources = tqmx_watchdog_resources, 103 .num_resources = ARRAY_SIZE(tqmx_watchdog_resources), 104 .ignore_resource_conflicts = true, 105 }, 106 { 107 .name = "tqmx86-gpio", 108 .resources = tqmx_gpio_resources, 109 .num_resources = ARRAY_SIZE(tqmx_gpio_resources), 110 .ignore_resource_conflicts = true, 111 }, 112 }; 113 114 static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) 115 { 116 switch (board_id) { 117 case TQMX86_REG_BOARD_ID_E38M: 118 return "TQMxE38M"; 119 case TQMX86_REG_BOARD_ID_50UC: 120 return "TQMx50UC"; 121 case TQMX86_REG_BOARD_ID_E38C: 122 return "TQMxE38C"; 123 case TQMX86_REG_BOARD_ID_60EB: 124 return "TQMx60EB"; 125 case TQMX86_REG_BOARD_ID_E39MS: 126 return (sauc == 0xff) ? "TQMxE39M" : "TQMxE39S"; 127 case TQMX86_REG_BOARD_ID_E39C1: 128 return "TQMxE39C1"; 129 case TQMX86_REG_BOARD_ID_E39C2: 130 return "TQMxE39C2"; 131 case TQMX86_REG_BOARD_ID_70EB: 132 return "TQMx70EB"; 133 case TQMX86_REG_BOARD_ID_80UC: 134 return "TQMx80UC"; 135 case TQMX86_REG_BOARD_ID_110EB: 136 return "TQMx110EB"; 137 case TQMX86_REG_BOARD_ID_E40M: 138 return "TQMxE40M"; 139 case TQMX86_REG_BOARD_ID_E40S: 140 return "TQMxE40S"; 141 case TQMX86_REG_BOARD_ID_E40C1: 142 return "TQMxE40C1"; 143 case TQMX86_REG_BOARD_ID_E40C2: 144 return "TQMxE40C2"; 145 default: 146 return "Unknown"; 147 } 148 } 149 150 static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) 151 { 152 switch (board_id) { 153 case TQMX86_REG_BOARD_ID_50UC: 154 case TQMX86_REG_BOARD_ID_60EB: 155 case TQMX86_REG_BOARD_ID_70EB: 156 case TQMX86_REG_BOARD_ID_80UC: 157 case TQMX86_REG_BOARD_ID_110EB: 158 case TQMX86_REG_BOARD_ID_E40M: 159 case TQMX86_REG_BOARD_ID_E40S: 160 case TQMX86_REG_BOARD_ID_E40C1: 161 case TQMX86_REG_BOARD_ID_E40C2: 162 return 24000; 163 case TQMX86_REG_BOARD_ID_E39MS: 164 case TQMX86_REG_BOARD_ID_E39C1: 165 case TQMX86_REG_BOARD_ID_E39C2: 166 return 25000; 167 case TQMX86_REG_BOARD_ID_E38M: 168 case TQMX86_REG_BOARD_ID_E38C: 169 return 33000; 170 default: 171 dev_warn(dev, "unknown board %d, assuming 24MHz LPC clock\n", 172 board_id); 173 return 24000; 174 } 175 } 176 177 static int tqmx86_probe(struct platform_device *pdev) 178 { 179 u8 board_id, sauc, rev, i2c_det, io_ext_int_val; 180 struct device *dev = &pdev->dev; 181 u8 gpio_irq_cfg, readback; 182 const char *board_name; 183 void __iomem *io_base; 184 int err; 185 186 switch (gpio_irq) { 187 case 0: 188 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; 189 break; 190 case 7: 191 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_7; 192 break; 193 case 9: 194 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_9; 195 break; 196 case 12: 197 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_12; 198 break; 199 default: 200 pr_err("tqmx86: Invalid GPIO IRQ (%d)\n", gpio_irq); 201 return -EINVAL; 202 } 203 204 io_base = devm_ioport_map(dev, TQMX86_IOBASE, TQMX86_IOSIZE); 205 if (!io_base) 206 return -ENOMEM; 207 208 board_id = ioread8(io_base + TQMX86_REG_BOARD_ID); 209 sauc = ioread8(io_base + TQMX86_REG_SAUC); 210 board_name = tqmx86_board_id_to_name(board_id, sauc); 211 rev = ioread8(io_base + TQMX86_REG_BOARD_REV); 212 213 dev_info(dev, 214 "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", 215 board_name, board_id, rev >> 4, rev & 0xf); 216 217 /* 218 * The I2C_DETECT register is in the range assigned to the I2C driver 219 * later, so we don't extend TQMX86_IOSIZE. Use inb() for this one-off 220 * access instead of ioport_map + unmap. 221 */ 222 i2c_det = inb(TQMX86_REG_I2C_DETECT); 223 224 if (gpio_irq_cfg) { 225 io_ext_int_val = 226 gpio_irq_cfg << TQMX86_REG_IO_EXT_INT_GPIO_SHIFT; 227 iowrite8(io_ext_int_val, io_base + TQMX86_REG_IO_EXT_INT); 228 readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); 229 if (readback != io_ext_int_val) { 230 dev_warn(dev, "GPIO interrupts not supported.\n"); 231 return -EINVAL; 232 } 233 234 /* Assumes the IRQ resource is first. */ 235 tqmx_gpio_resources[0].start = gpio_irq; 236 } else { 237 tqmx_gpio_resources[0].flags = 0; 238 } 239 240 ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); 241 242 if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { 243 err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 244 tqmx86_i2c_soft_dev, 245 ARRAY_SIZE(tqmx86_i2c_soft_dev), 246 NULL, 0, NULL); 247 if (err) 248 return err; 249 } 250 251 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 252 tqmx86_devs, 253 ARRAY_SIZE(tqmx86_devs), 254 NULL, 0, NULL); 255 } 256 257 static int tqmx86_create_platform_device(const struct dmi_system_id *id) 258 { 259 struct platform_device *pdev; 260 int err; 261 262 pdev = platform_device_alloc("tqmx86", -1); 263 if (!pdev) 264 return -ENOMEM; 265 266 err = platform_device_add(pdev); 267 if (err) 268 platform_device_put(pdev); 269 270 return err; 271 } 272 273 static const struct dmi_system_id tqmx86_dmi_table[] __initconst = { 274 { 275 .ident = "TQMX86", 276 .matches = { 277 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Group"), 278 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 279 }, 280 .callback = tqmx86_create_platform_device, 281 }, 282 { 283 .ident = "TQMX86", 284 .matches = { 285 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Systems"), 286 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 287 }, 288 .callback = tqmx86_create_platform_device, 289 }, 290 {} 291 }; 292 MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); 293 294 static struct platform_driver tqmx86_driver = { 295 .driver = { 296 .name = "tqmx86", 297 }, 298 .probe = tqmx86_probe, 299 }; 300 301 static int __init tqmx86_init(void) 302 { 303 if (!dmi_check_system(tqmx86_dmi_table)) 304 return -ENODEV; 305 306 return platform_driver_register(&tqmx86_driver); 307 } 308 309 module_init(tqmx86_init); 310 311 MODULE_DESCRIPTION("TQMx86 PLD Core Driver"); 312 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 313 MODULE_LICENSE("GPL"); 314 MODULE_ALIAS("platform:tqmx86"); 315