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_90UC 10 39 #define TQMX86_REG_BOARD_REV 0x21 40 #define TQMX86_REG_IO_EXT_INT 0x26 41 #define TQMX86_REG_IO_EXT_INT_NONE 0 42 #define TQMX86_REG_IO_EXT_INT_7 1 43 #define TQMX86_REG_IO_EXT_INT_9 2 44 #define TQMX86_REG_IO_EXT_INT_12 3 45 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 46 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 47 48 #define TQMX86_REG_I2C_DETECT 0x47 49 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 50 #define TQMX86_REG_I2C_INT_EN 0x49 51 52 static uint gpio_irq; 53 module_param(gpio_irq, uint, 0); 54 MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (7, 9, 12)"); 55 56 static const struct resource tqmx_i2c_soft_resources[] = { 57 DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), 58 }; 59 60 static const struct resource tqmx_watchdog_resources[] = { 61 DEFINE_RES_IO(TQMX86_IOBASE_WATCHDOG, TQMX86_IOSIZE_WATCHDOG), 62 }; 63 64 /* 65 * The IRQ resource must be first, since it is updated with the 66 * configured IRQ in the probe function. 67 */ 68 static struct resource tqmx_gpio_resources[] = { 69 DEFINE_RES_IRQ(0), 70 DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), 71 }; 72 73 static struct i2c_board_info tqmx86_i2c_devices[] = { 74 { 75 /* 4K EEPROM at 0x50 */ 76 I2C_BOARD_INFO("24c32", 0x50), 77 }, 78 }; 79 80 static struct ocores_i2c_platform_data ocores_platfom_data = { 81 .num_devices = ARRAY_SIZE(tqmx86_i2c_devices), 82 .devices = tqmx86_i2c_devices, 83 }; 84 85 static const struct mfd_cell tqmx86_i2c_soft_dev[] = { 86 { 87 .name = "ocores-i2c", 88 .platform_data = &ocores_platfom_data, 89 .pdata_size = sizeof(ocores_platfom_data), 90 .resources = tqmx_i2c_soft_resources, 91 .num_resources = ARRAY_SIZE(tqmx_i2c_soft_resources), 92 }, 93 }; 94 95 static const struct mfd_cell tqmx86_devs[] = { 96 { 97 .name = "tqmx86-wdt", 98 .resources = tqmx_watchdog_resources, 99 .num_resources = ARRAY_SIZE(tqmx_watchdog_resources), 100 .ignore_resource_conflicts = true, 101 }, 102 { 103 .name = "tqmx86-gpio", 104 .resources = tqmx_gpio_resources, 105 .num_resources = ARRAY_SIZE(tqmx_gpio_resources), 106 .ignore_resource_conflicts = true, 107 }, 108 }; 109 110 static const char *tqmx86_board_id_to_name(u8 board_id) 111 { 112 switch (board_id) { 113 case TQMX86_REG_BOARD_ID_E38M: 114 return "TQMxE38M"; 115 case TQMX86_REG_BOARD_ID_50UC: 116 return "TQMx50UC"; 117 case TQMX86_REG_BOARD_ID_E38C: 118 return "TQMxE38C"; 119 case TQMX86_REG_BOARD_ID_60EB: 120 return "TQMx60EB"; 121 case TQMX86_REG_BOARD_ID_E39M: 122 return "TQMxE39M"; 123 case TQMX86_REG_BOARD_ID_E39C: 124 return "TQMxE39C"; 125 case TQMX86_REG_BOARD_ID_E39x: 126 return "TQMxE39x"; 127 case TQMX86_REG_BOARD_ID_70EB: 128 return "TQMx70EB"; 129 case TQMX86_REG_BOARD_ID_80UC: 130 return "TQMx80UC"; 131 case TQMX86_REG_BOARD_ID_90UC: 132 return "TQMx90UC"; 133 default: 134 return "Unknown"; 135 } 136 } 137 138 static int tqmx86_board_id_to_clk_rate(u8 board_id) 139 { 140 switch (board_id) { 141 case TQMX86_REG_BOARD_ID_50UC: 142 case TQMX86_REG_BOARD_ID_60EB: 143 case TQMX86_REG_BOARD_ID_70EB: 144 case TQMX86_REG_BOARD_ID_80UC: 145 case TQMX86_REG_BOARD_ID_90UC: 146 return 24000; 147 case TQMX86_REG_BOARD_ID_E39M: 148 case TQMX86_REG_BOARD_ID_E39C: 149 case TQMX86_REG_BOARD_ID_E39x: 150 return 25000; 151 case TQMX86_REG_BOARD_ID_E38M: 152 case TQMX86_REG_BOARD_ID_E38C: 153 return 33000; 154 default: 155 return 0; 156 } 157 } 158 159 static int tqmx86_probe(struct platform_device *pdev) 160 { 161 u8 board_id, rev, i2c_det, io_ext_int_val; 162 struct device *dev = &pdev->dev; 163 u8 gpio_irq_cfg, readback; 164 const char *board_name; 165 void __iomem *io_base; 166 int err; 167 168 switch (gpio_irq) { 169 case 0: 170 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; 171 break; 172 case 7: 173 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_7; 174 break; 175 case 9: 176 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_9; 177 break; 178 case 12: 179 gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_12; 180 break; 181 default: 182 pr_err("tqmx86: Invalid GPIO IRQ (%d)\n", gpio_irq); 183 return -EINVAL; 184 } 185 186 io_base = devm_ioport_map(dev, TQMX86_IOBASE, TQMX86_IOSIZE); 187 if (!io_base) 188 return -ENOMEM; 189 190 board_id = ioread8(io_base + TQMX86_REG_BOARD_ID); 191 board_name = tqmx86_board_id_to_name(board_id); 192 rev = ioread8(io_base + TQMX86_REG_BOARD_REV); 193 194 dev_info(dev, 195 "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", 196 board_name, board_id, rev >> 4, rev & 0xf); 197 198 i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT); 199 200 if (gpio_irq_cfg) { 201 io_ext_int_val = 202 gpio_irq_cfg << TQMX86_REG_IO_EXT_INT_GPIO_SHIFT; 203 iowrite8(io_ext_int_val, io_base + TQMX86_REG_IO_EXT_INT); 204 readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); 205 if (readback != io_ext_int_val) { 206 dev_warn(dev, "GPIO interrupts not supported.\n"); 207 return -EINVAL; 208 } 209 210 /* Assumes the IRQ resource is first. */ 211 tqmx_gpio_resources[0].start = gpio_irq; 212 } 213 214 ocores_platfom_data.clock_khz = tqmx86_board_id_to_clk_rate(board_id); 215 216 if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { 217 err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 218 tqmx86_i2c_soft_dev, 219 ARRAY_SIZE(tqmx86_i2c_soft_dev), 220 NULL, 0, NULL); 221 if (err) 222 return err; 223 } 224 225 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 226 tqmx86_devs, 227 ARRAY_SIZE(tqmx86_devs), 228 NULL, 0, NULL); 229 } 230 231 static int tqmx86_create_platform_device(const struct dmi_system_id *id) 232 { 233 struct platform_device *pdev; 234 int err; 235 236 pdev = platform_device_alloc("tqmx86", -1); 237 if (!pdev) 238 return -ENOMEM; 239 240 err = platform_device_add(pdev); 241 if (err) 242 platform_device_put(pdev); 243 244 return err; 245 } 246 247 static const struct dmi_system_id tqmx86_dmi_table[] __initconst = { 248 { 249 .ident = "TQMX86", 250 .matches = { 251 DMI_MATCH(DMI_SYS_VENDOR, "TQ-Group"), 252 DMI_MATCH(DMI_PRODUCT_NAME, "TQMx"), 253 }, 254 .callback = tqmx86_create_platform_device, 255 }, 256 {} 257 }; 258 MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); 259 260 static struct platform_driver tqmx86_driver = { 261 .driver = { 262 .name = "tqmx86", 263 }, 264 .probe = tqmx86_probe, 265 }; 266 267 static int __init tqmx86_init(void) 268 { 269 if (!dmi_check_system(tqmx86_dmi_table)) 270 return -ENODEV; 271 272 return platform_driver_register(&tqmx86_driver); 273 } 274 275 module_init(tqmx86_init); 276 277 MODULE_DESCRIPTION("TQMx86 PLD Core Driver"); 278 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 279 MODULE_LICENSE("GPL"); 280 MODULE_ALIAS("platform:tqmx86"); 281