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 0x160 20 #define TQMX86_IOSIZE 0x3f 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 0x20 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_E39M 5 34 #define TQMX86_REG_BOARD_ID_E39C 6 35 #define TQMX86_REG_BOARD_ID_E39x 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 0x21 44 #define TQMX86_REG_IO_EXT_INT 0x26 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 52 #define TQMX86_REG_I2C_DETECT 0x47 53 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 54 #define TQMX86_REG_I2C_INT_EN 0x49 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) 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_E39M: 126 return "TQMxE39M"; 127 case TQMX86_REG_BOARD_ID_E39C: 128 return "TQMxE39C"; 129 case TQMX86_REG_BOARD_ID_E39x: 130 return "TQMxE39x"; 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_E39M: 164 case TQMX86_REG_BOARD_ID_E39C: 165 case TQMX86_REG_BOARD_ID_E39x: 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, 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 board_name = tqmx86_board_id_to_name(board_id); 210 rev = ioread8(io_base + TQMX86_REG_BOARD_REV); 211 212 dev_info(dev, 213 "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", 214 board_name, board_id, rev >> 4, rev & 0xf); 215 216 i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT); 217 218 if (gpio_irq_cfg) { 219 io_ext_int_val = 220 gpio_irq_cfg << TQMX86_REG_IO_EXT_INT_GPIO_SHIFT; 221 iowrite8(io_ext_int_val, io_base + TQMX86_REG_IO_EXT_INT); 222 readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); 223 if (readback != io_ext_int_val) { 224 dev_warn(dev, "GPIO interrupts not supported.\n"); 225 return -EINVAL; 226 } 227 228 /* Assumes the IRQ resource is first. */ 229 tqmx_gpio_resources[0].start = gpio_irq; 230 } else { 231 tqmx_gpio_resources[0].flags = 0; 232 } 233 234 ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); 235 236 if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { 237 err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 238 tqmx86_i2c_soft_dev, 239 ARRAY_SIZE(tqmx86_i2c_soft_dev), 240 NULL, 0, NULL); 241 if (err) 242 return err; 243 } 244 245 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 246 tqmx86_devs, 247 ARRAY_SIZE(tqmx86_devs), 248 NULL, 0, NULL); 249 } 250 251 static int tqmx86_create_platform_device(const struct dmi_system_id *id) 252 { 253 struct platform_device *pdev; 254 int err; 255 256 pdev = platform_device_alloc("tqmx86", -1); 257 if (!pdev) 258 return -ENOMEM; 259 260 err = platform_device_add(pdev); 261 if (err) 262 platform_device_put(pdev); 263 264 return err; 265 } 266 267 static const struct dmi_system_id tqmx86_dmi_table[] __initconst = { 268 { 269 .ident = "TQMX86", 270 .matches = { 271 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Group"), 272 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 273 }, 274 .callback = tqmx86_create_platform_device, 275 }, 276 { 277 .ident = "TQMX86", 278 .matches = { 279 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Systems"), 280 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 281 }, 282 .callback = tqmx86_create_platform_device, 283 }, 284 {} 285 }; 286 MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); 287 288 static struct platform_driver tqmx86_driver = { 289 .driver = { 290 .name = "tqmx86", 291 }, 292 .probe = tqmx86_probe, 293 }; 294 295 static int __init tqmx86_init(void) 296 { 297 if (!dmi_check_system(tqmx86_dmi_table)) 298 return -ENODEV; 299 300 return platform_driver_register(&tqmx86_driver); 301 } 302 303 module_init(tqmx86_init); 304 305 MODULE_DESCRIPTION("TQMx86 PLD Core Driver"); 306 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 307 MODULE_LICENSE("GPL"); 308 MODULE_ALIAS("platform:tqmx86"); 309