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 56static uint gpio_irq; 57module_param(gpio_irq, uint, 0); 58MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (7, 9, 12)"); 59 60static const struct resource tqmx_i2c_soft_resources[] = { 61 DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), 62}; 63 64static 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 */ 72static struct resource tqmx_gpio_resources[] = { 73 DEFINE_RES_IRQ(0), 74 DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), 75}; 76 77static struct i2c_board_info tqmx86_i2c_devices[] = { 78 { 79 /* 4K EEPROM at 0x50 */ 80 I2C_BOARD_INFO("24c32", 0x50), 81 }, 82}; 83 84static struct ocores_i2c_platform_data ocores_platform_data = { 85 .num_devices = ARRAY_SIZE(tqmx86_i2c_devices), 86 .devices = tqmx86_i2c_devices, 87}; 88 89static 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 99static 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 114static 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 150static 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 177static 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 257static 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 273static 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}; 292MODULE_DEVICE_TABLE(dmi, tqmx86_dmi_table); 293 294static struct platform_driver tqmx86_driver = { 295 .driver = { 296 .name = "tqmx86", 297 }, 298 .probe = tqmx86_probe, 299}; 300 301static 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 309module_init(tqmx86_init); 310 311MODULE_DESCRIPTION("TQMx86 PLD Core Driver"); 312MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 313MODULE_LICENSE("GPL"); 314MODULE_ALIAS("platform:tqmx86"); 315