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_120UC 10 39 #define TQMX86_REG_BOARD_ID_110EB 11 40 #define TQMX86_REG_BOARD_ID_E40M 12 41 #define TQMX86_REG_BOARD_ID_E40S 13 42 #define TQMX86_REG_BOARD_ID_E40C1 14 43 #define TQMX86_REG_BOARD_ID_E40C2 15 44 #define TQMX86_REG_BOARD_ID_130UC 16 45 #define TQMX86_REG_BOARD_ID_E41S 19 46 #define TQMX86_REG_BOARD_REV 0x01 47 #define TQMX86_REG_IO_EXT_INT 0x06 48 #define TQMX86_REG_IO_EXT_INT_NONE 0 49 #define TQMX86_REG_IO_EXT_INT_7 1 50 #define TQMX86_REG_IO_EXT_INT_9 2 51 #define TQMX86_REG_IO_EXT_INT_12 3 52 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 53 #define TQMX86_REG_IO_EXT_INT_I2C1_SHIFT 0 54 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 55 #define TQMX86_REG_SAUC 0x17 56 57 #define TQMX86_REG_I2C_DETECT 0x1a7 58 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 59 60 static uint gpio_irq; 61 module_param(gpio_irq, uint, 0); 62 MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (valid parameters: 7, 9, 12)"); 63 64 static uint i2c1_irq; 65 module_param(i2c1_irq, uint, 0); 66 MODULE_PARM_DESC(i2c1_irq, "I2C1 IRQ number (valid parameters: 7, 9, 12)"); 67 68 enum tqmx86_i2c1_resource_type { 69 TQMX86_I2C1_IO, 70 TQMX86_I2C1_IRQ, 71 }; 72 73 static struct resource tqmx_i2c_soft_resources[] = { 74 [TQMX86_I2C1_IO] = DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), 75 /* Placeholder for IRQ resource */ 76 [TQMX86_I2C1_IRQ] = {}, 77 }; 78 79 static const struct resource tqmx_watchdog_resources[] = { 80 DEFINE_RES_IO(TQMX86_IOBASE_WATCHDOG, TQMX86_IOSIZE_WATCHDOG), 81 }; 82 83 enum tqmx86_gpio_resource_type { 84 TQMX86_GPIO_IO, 85 TQMX86_GPIO_IRQ, 86 }; 87 88 static struct resource tqmx_gpio_resources[] = { 89 [TQMX86_GPIO_IO] = DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), 90 /* Placeholder for IRQ resource */ 91 [TQMX86_GPIO_IRQ] = {}, 92 }; 93 94 static struct i2c_board_info tqmx86_i2c_devices[] = { 95 { 96 /* 4K EEPROM at 0x50 */ 97 I2C_BOARD_INFO("24c32", 0x50), 98 }, 99 }; 100 101 static struct ocores_i2c_platform_data ocores_platform_data = { 102 .num_devices = ARRAY_SIZE(tqmx86_i2c_devices), 103 .devices = tqmx86_i2c_devices, 104 }; 105 106 static const struct mfd_cell tqmx86_i2c_soft_dev[] = { 107 { 108 .name = "ocores-i2c", 109 .platform_data = &ocores_platform_data, 110 .pdata_size = sizeof(ocores_platform_data), 111 .resources = tqmx_i2c_soft_resources, 112 .num_resources = ARRAY_SIZE(tqmx_i2c_soft_resources), 113 }, 114 }; 115 116 static const struct mfd_cell tqmx86_devs[] = { 117 { 118 .name = "tqmx86-wdt", 119 .resources = tqmx_watchdog_resources, 120 .num_resources = ARRAY_SIZE(tqmx_watchdog_resources), 121 .ignore_resource_conflicts = true, 122 }, 123 { 124 .name = "tqmx86-gpio", 125 .resources = tqmx_gpio_resources, 126 .num_resources = ARRAY_SIZE(tqmx_gpio_resources), 127 .ignore_resource_conflicts = true, 128 }, 129 }; 130 131 static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) 132 { 133 switch (board_id) { 134 case TQMX86_REG_BOARD_ID_E38M: 135 return "TQMxE38M"; 136 case TQMX86_REG_BOARD_ID_50UC: 137 return "TQMx50UC"; 138 case TQMX86_REG_BOARD_ID_E38C: 139 return "TQMxE38C"; 140 case TQMX86_REG_BOARD_ID_60EB: 141 return "TQMx60EB"; 142 case TQMX86_REG_BOARD_ID_E39MS: 143 return (sauc == 0xff) ? "TQMxE39M" : "TQMxE39S"; 144 case TQMX86_REG_BOARD_ID_E39C1: 145 return "TQMxE39C1"; 146 case TQMX86_REG_BOARD_ID_E39C2: 147 return "TQMxE39C2"; 148 case TQMX86_REG_BOARD_ID_70EB: 149 return "TQMx70EB"; 150 case TQMX86_REG_BOARD_ID_80UC: 151 return "TQMx80UC"; 152 case TQMX86_REG_BOARD_ID_120UC: 153 return "TQMx120UC"; 154 case TQMX86_REG_BOARD_ID_110EB: 155 return "TQMx110EB"; 156 case TQMX86_REG_BOARD_ID_E40M: 157 return "TQMxE40M"; 158 case TQMX86_REG_BOARD_ID_E40S: 159 return "TQMxE40S"; 160 case TQMX86_REG_BOARD_ID_E40C1: 161 return "TQMxE40C1"; 162 case TQMX86_REG_BOARD_ID_E40C2: 163 return "TQMxE40C2"; 164 case TQMX86_REG_BOARD_ID_130UC: 165 return "TQMx130UC"; 166 case TQMX86_REG_BOARD_ID_E41S: 167 return "TQMxE41S"; 168 default: 169 return "Unknown"; 170 } 171 } 172 173 static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) 174 { 175 switch (board_id) { 176 case TQMX86_REG_BOARD_ID_50UC: 177 case TQMX86_REG_BOARD_ID_60EB: 178 case TQMX86_REG_BOARD_ID_70EB: 179 case TQMX86_REG_BOARD_ID_80UC: 180 case TQMX86_REG_BOARD_ID_120UC: 181 case TQMX86_REG_BOARD_ID_110EB: 182 case TQMX86_REG_BOARD_ID_E40M: 183 case TQMX86_REG_BOARD_ID_E40S: 184 case TQMX86_REG_BOARD_ID_E40C1: 185 case TQMX86_REG_BOARD_ID_E40C2: 186 case TQMX86_REG_BOARD_ID_130UC: 187 case TQMX86_REG_BOARD_ID_E41S: 188 return 24000; 189 case TQMX86_REG_BOARD_ID_E39MS: 190 case TQMX86_REG_BOARD_ID_E39C1: 191 case TQMX86_REG_BOARD_ID_E39C2: 192 return 25000; 193 case TQMX86_REG_BOARD_ID_E38M: 194 case TQMX86_REG_BOARD_ID_E38C: 195 return 33000; 196 default: 197 dev_warn(dev, "unknown board %d, assuming 24MHz LPC clock\n", 198 board_id); 199 return 24000; 200 } 201 } 202 203 static int tqmx86_setup_irq(struct device *dev, const char *label, u8 irq, 204 void __iomem *io_base, u8 reg_shift) 205 { 206 u8 val, readback; 207 int irq_cfg; 208 209 switch (irq) { 210 case 0: 211 irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; 212 break; 213 case 7: 214 irq_cfg = TQMX86_REG_IO_EXT_INT_7; 215 break; 216 case 9: 217 irq_cfg = TQMX86_REG_IO_EXT_INT_9; 218 break; 219 case 12: 220 irq_cfg = TQMX86_REG_IO_EXT_INT_12; 221 break; 222 default: 223 dev_err(dev, "invalid %s IRQ (%d)\n", label, irq); 224 return -EINVAL; 225 } 226 227 val = ioread8(io_base + TQMX86_REG_IO_EXT_INT); 228 val &= ~(TQMX86_REG_IO_EXT_INT_MASK << reg_shift); 229 val |= (irq_cfg & TQMX86_REG_IO_EXT_INT_MASK) << reg_shift; 230 231 iowrite8(val, io_base + TQMX86_REG_IO_EXT_INT); 232 readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); 233 if (readback != val) { 234 dev_warn(dev, "%s interrupts not supported\n", label); 235 return -EINVAL; 236 } 237 238 return 0; 239 } 240 241 static int tqmx86_probe(struct platform_device *pdev) 242 { 243 u8 board_id, sauc, rev, i2c_det; 244 struct device *dev = &pdev->dev; 245 const char *board_name; 246 void __iomem *io_base; 247 int err; 248 249 io_base = devm_ioport_map(dev, TQMX86_IOBASE, TQMX86_IOSIZE); 250 if (!io_base) 251 return -ENOMEM; 252 253 board_id = ioread8(io_base + TQMX86_REG_BOARD_ID); 254 sauc = ioread8(io_base + TQMX86_REG_SAUC); 255 board_name = tqmx86_board_id_to_name(board_id, sauc); 256 rev = ioread8(io_base + TQMX86_REG_BOARD_REV); 257 258 dev_info(dev, 259 "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", 260 board_name, board_id, rev >> 4, rev & 0xf); 261 262 /* 263 * The I2C_DETECT register is in the range assigned to the I2C driver 264 * later, so we don't extend TQMX86_IOSIZE. Use inb() for this one-off 265 * access instead of ioport_map + unmap. 266 */ 267 i2c_det = inb(TQMX86_REG_I2C_DETECT); 268 269 if (gpio_irq) { 270 err = tqmx86_setup_irq(dev, "GPIO", gpio_irq, io_base, 271 TQMX86_REG_IO_EXT_INT_GPIO_SHIFT); 272 if (!err) 273 tqmx_gpio_resources[TQMX86_GPIO_IRQ] = DEFINE_RES_IRQ(gpio_irq); 274 } 275 276 ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); 277 278 if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { 279 if (i2c1_irq) { 280 err = tqmx86_setup_irq(dev, "I2C1", i2c1_irq, io_base, 281 TQMX86_REG_IO_EXT_INT_I2C1_SHIFT); 282 if (!err) 283 tqmx_i2c_soft_resources[TQMX86_I2C1_IRQ] = DEFINE_RES_IRQ(i2c1_irq); 284 } 285 286 err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 287 tqmx86_i2c_soft_dev, 288 ARRAY_SIZE(tqmx86_i2c_soft_dev), 289 NULL, 0, NULL); 290 if (err) 291 return err; 292 } 293 294 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 295 tqmx86_devs, 296 ARRAY_SIZE(tqmx86_devs), 297 NULL, 0, NULL); 298 } 299 300 static int tqmx86_create_platform_device(const struct dmi_system_id *id) 301 { 302 struct platform_device *pdev; 303 int err; 304 305 pdev = platform_device_alloc("tqmx86", -1); 306 if (!pdev) 307 return -ENOMEM; 308 309 err = platform_device_add(pdev); 310 if (err) 311 platform_device_put(pdev); 312 313 return err; 314 } 315 316 static const struct dmi_system_id tqmx86_dmi_table[] __initconst = { 317 { 318 .ident = "TQMX86", 319 .matches = { 320 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Group"), 321 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 322 }, 323 .callback = tqmx86_create_platform_device, 324 }, 325 { 326 .ident = "TQMX86", 327 .matches = { 328 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Systems"), 329 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 330 }, 331 .callback = tqmx86_create_platform_device, 332 }, 333 {} 334 }; 335 MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); 336 337 static struct platform_driver tqmx86_driver = { 338 .driver = { 339 .name = "tqmx86", 340 }, 341 .probe = tqmx86_probe, 342 }; 343 344 static int __init tqmx86_init(void) 345 { 346 if (!dmi_check_system(tqmx86_dmi_table)) 347 return -ENODEV; 348 349 return platform_driver_register(&tqmx86_driver); 350 } 351 352 module_init(tqmx86_init); 353 354 MODULE_DESCRIPTION("TQMx86 PLD Core Driver"); 355 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 356 MODULE_LICENSE("GPL"); 357 MODULE_ALIAS("platform:tqmx86"); 358