1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* 4 * Support for EC-connected GPIOs for identify 5 * LED/button on Barco P50 board 6 * 7 * Copyright (C) 2021 Barco NV 8 * Author: Santosh Kumar Yadav <santoshkumar.yadav@barco.com> 9 */ 10 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 13 #include <linux/delay.h> 14 #include <linux/dmi.h> 15 #include <linux/err.h> 16 #include <linux/io.h> 17 #include <linux/kernel.h> 18 #include <linux/leds.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/gpio_keys.h> 22 #include <linux/gpio/driver.h> 23 #include <linux/gpio/machine.h> 24 #include <linux/input.h> 25 26 27 #define DRIVER_NAME "barco-p50-gpio" 28 29 /* GPIO lines */ 30 #define P50_GPIO_LINE_LED 0 31 #define P50_GPIO_LINE_BTN 1 32 33 /* GPIO IO Ports */ 34 #define P50_GPIO_IO_PORT_BASE 0x299 35 36 #define P50_PORT_DATA 0x00 37 #define P50_PORT_CMD 0x01 38 39 #define P50_STATUS_OBF 0x01 /* EC output buffer full */ 40 #define P50_STATUS_IBF 0x02 /* EC input buffer full */ 41 42 #define P50_CMD_READ 0xa0 43 #define P50_CMD_WRITE 0x50 44 45 /* EC mailbox registers */ 46 #define P50_MBOX_REG_CMD 0x00 47 #define P50_MBOX_REG_STATUS 0x01 48 #define P50_MBOX_REG_PARAM 0x02 49 #define P50_MBOX_REG_DATA 0x03 50 51 #define P50_MBOX_CMD_READ_GPIO 0x11 52 #define P50_MBOX_CMD_WRITE_GPIO 0x12 53 #define P50_MBOX_CMD_CLEAR 0xff 54 55 #define P50_MBOX_STATUS_SUCCESS 0x01 56 57 #define P50_MBOX_PARAM_LED 0x12 58 #define P50_MBOX_PARAM_BTN 0x13 59 60 61 struct p50_gpio { 62 struct gpio_chip gc; 63 struct mutex lock; 64 unsigned long base; 65 struct platform_device *leds_pdev; 66 struct platform_device *keys_pdev; 67 }; 68 69 static struct platform_device *gpio_pdev; 70 71 static int gpio_params[] = { 72 [P50_GPIO_LINE_LED] = P50_MBOX_PARAM_LED, 73 [P50_GPIO_LINE_BTN] = P50_MBOX_PARAM_BTN, 74 }; 75 76 static const char * const gpio_names[] = { 77 [P50_GPIO_LINE_LED] = "identify-led", 78 [P50_GPIO_LINE_BTN] = "identify-button", 79 }; 80 81 82 static struct gpiod_lookup_table p50_gpio_led_table = { 83 .dev_id = "leds-gpio", 84 .table = { 85 GPIO_LOOKUP_IDX(DRIVER_NAME, P50_GPIO_LINE_LED, NULL, 0, GPIO_ACTIVE_HIGH), 86 {} 87 } 88 }; 89 90 /* GPIO LEDs */ 91 static struct gpio_led leds[] = { 92 { .name = "identify" } 93 }; 94 95 static struct gpio_led_platform_data leds_pdata = { 96 .num_leds = ARRAY_SIZE(leds), 97 .leds = leds, 98 }; 99 100 /* GPIO keyboard */ 101 static struct gpio_keys_button buttons[] = { 102 { 103 .code = KEY_VENDOR, 104 .gpio = P50_GPIO_LINE_BTN, 105 .active_low = 1, 106 .type = EV_KEY, 107 .value = 1, 108 }, 109 }; 110 111 static struct gpio_keys_platform_data keys_pdata = { 112 .buttons = buttons, 113 .nbuttons = ARRAY_SIZE(buttons), 114 .poll_interval = 100, 115 .rep = 0, 116 .name = "identify", 117 }; 118 119 120 /* low level access routines */ 121 122 static int p50_wait_ec(struct p50_gpio *p50, int mask, int expected) 123 { 124 int i, val; 125 126 for (i = 0; i < 100; i++) { 127 val = inb(p50->base + P50_PORT_CMD) & mask; 128 if (val == expected) 129 return 0; 130 usleep_range(500, 2000); 131 } 132 133 dev_err(p50->gc.parent, "Timed out waiting for EC (0x%x)\n", val); 134 return -ETIMEDOUT; 135 } 136 137 138 static int p50_read_mbox_reg(struct p50_gpio *p50, int reg) 139 { 140 int ret; 141 142 ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); 143 if (ret) 144 return ret; 145 146 /* clear output buffer flag, prevent unfinished commands */ 147 inb(p50->base + P50_PORT_DATA); 148 149 /* cmd/address */ 150 outb(P50_CMD_READ | reg, p50->base + P50_PORT_CMD); 151 152 ret = p50_wait_ec(p50, P50_STATUS_OBF, P50_STATUS_OBF); 153 if (ret) 154 return ret; 155 156 return inb(p50->base + P50_PORT_DATA); 157 } 158 159 static int p50_write_mbox_reg(struct p50_gpio *p50, int reg, int val) 160 { 161 int ret; 162 163 ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); 164 if (ret) 165 return ret; 166 167 /* cmd/address */ 168 outb(P50_CMD_WRITE | reg, p50->base + P50_PORT_CMD); 169 170 ret = p50_wait_ec(p50, P50_STATUS_IBF, 0); 171 if (ret) 172 return ret; 173 174 /* data */ 175 outb(val, p50->base + P50_PORT_DATA); 176 177 return 0; 178 } 179 180 181 /* mbox routines */ 182 183 static int p50_wait_mbox_idle(struct p50_gpio *p50) 184 { 185 int i, val; 186 187 for (i = 0; i < 1000; i++) { 188 val = p50_read_mbox_reg(p50, P50_MBOX_REG_CMD); 189 /* cmd is 0 when idle */ 190 if (val <= 0) 191 return val; 192 193 usleep_range(500, 2000); 194 } 195 196 dev_err(p50->gc.parent, "Timed out waiting for EC mbox idle (CMD: 0x%x)\n", val); 197 198 return -ETIMEDOUT; 199 } 200 201 static int p50_send_mbox_cmd(struct p50_gpio *p50, int cmd, int param, int data) 202 { 203 int ret; 204 205 ret = p50_wait_mbox_idle(p50); 206 if (ret) 207 return ret; 208 209 ret = p50_write_mbox_reg(p50, P50_MBOX_REG_DATA, data); 210 if (ret) 211 return ret; 212 213 ret = p50_write_mbox_reg(p50, P50_MBOX_REG_PARAM, param); 214 if (ret) 215 return ret; 216 217 ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, cmd); 218 if (ret) 219 return ret; 220 221 ret = p50_wait_mbox_idle(p50); 222 if (ret) 223 return ret; 224 225 ret = p50_read_mbox_reg(p50, P50_MBOX_REG_STATUS); 226 if (ret < 0) 227 return ret; 228 229 if (ret == P50_MBOX_STATUS_SUCCESS) 230 return 0; 231 232 dev_err(p50->gc.parent, "Mbox command failed (CMD=0x%x STAT=0x%x PARAM=0x%x DATA=0x%x)\n", 233 cmd, ret, param, data); 234 235 return -EIO; 236 } 237 238 239 /* gpio routines */ 240 241 static int p50_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 242 { 243 switch (offset) { 244 case P50_GPIO_LINE_BTN: 245 return GPIO_LINE_DIRECTION_IN; 246 247 case P50_GPIO_LINE_LED: 248 return GPIO_LINE_DIRECTION_OUT; 249 250 default: 251 return -EINVAL; 252 } 253 } 254 255 static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset) 256 { 257 struct p50_gpio *p50 = gpiochip_get_data(gc); 258 int ret; 259 260 mutex_lock(&p50->lock); 261 262 ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0); 263 if (ret == 0) 264 ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); 265 266 mutex_unlock(&p50->lock); 267 268 return ret; 269 } 270 271 static void p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 272 { 273 struct p50_gpio *p50 = gpiochip_get_data(gc); 274 275 mutex_lock(&p50->lock); 276 277 p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, gpio_params[offset], value); 278 279 mutex_unlock(&p50->lock); 280 } 281 282 static int p50_gpio_probe(struct platform_device *pdev) 283 { 284 struct p50_gpio *p50; 285 struct resource *res; 286 int ret; 287 288 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 289 if (!res) { 290 dev_err(&pdev->dev, "Cannot get I/O ports\n"); 291 return -ENODEV; 292 } 293 294 if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { 295 dev_err(&pdev->dev, "Unable to reserve I/O region\n"); 296 return -EBUSY; 297 } 298 299 p50 = devm_kzalloc(&pdev->dev, sizeof(*p50), GFP_KERNEL); 300 if (!p50) 301 return -ENOMEM; 302 303 platform_set_drvdata(pdev, p50); 304 mutex_init(&p50->lock); 305 p50->base = res->start; 306 p50->gc.owner = THIS_MODULE; 307 p50->gc.parent = &pdev->dev; 308 p50->gc.label = dev_name(&pdev->dev); 309 p50->gc.ngpio = ARRAY_SIZE(gpio_names); 310 p50->gc.names = gpio_names; 311 p50->gc.can_sleep = true; 312 p50->gc.base = -1; 313 p50->gc.get_direction = p50_gpio_get_direction; 314 p50->gc.get = p50_gpio_get; 315 p50->gc.set = p50_gpio_set; 316 317 318 /* reset mbox */ 319 ret = p50_wait_mbox_idle(p50); 320 if (ret) 321 return ret; 322 323 ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, P50_MBOX_CMD_CLEAR); 324 if (ret) 325 return ret; 326 327 ret = p50_wait_mbox_idle(p50); 328 if (ret) 329 return ret; 330 331 332 ret = devm_gpiochip_add_data(&pdev->dev, &p50->gc, p50); 333 if (ret < 0) { 334 dev_err(&pdev->dev, "Could not register gpiochip: %d\n", ret); 335 return ret; 336 } 337 338 gpiod_add_lookup_table(&p50_gpio_led_table); 339 340 p50->leds_pdev = platform_device_register_data(&pdev->dev, 341 "leds-gpio", PLATFORM_DEVID_NONE, &leds_pdata, sizeof(leds_pdata)); 342 343 if (IS_ERR(p50->leds_pdev)) { 344 ret = PTR_ERR(p50->leds_pdev); 345 dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret); 346 goto err_leds; 347 } 348 349 /* gpio-keys-polled uses old-style gpio interface, pass the right identifier */ 350 buttons[0].gpio += p50->gc.base; 351 352 p50->keys_pdev = 353 platform_device_register_data(&pdev->dev, "gpio-keys-polled", 354 PLATFORM_DEVID_NONE, 355 &keys_pdata, sizeof(keys_pdata)); 356 357 if (IS_ERR(p50->keys_pdev)) { 358 ret = PTR_ERR(p50->keys_pdev); 359 dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret); 360 goto err_keys; 361 } 362 363 return 0; 364 365 err_keys: 366 platform_device_unregister(p50->leds_pdev); 367 err_leds: 368 gpiod_remove_lookup_table(&p50_gpio_led_table); 369 370 return ret; 371 } 372 373 static void p50_gpio_remove(struct platform_device *pdev) 374 { 375 struct p50_gpio *p50 = platform_get_drvdata(pdev); 376 377 platform_device_unregister(p50->keys_pdev); 378 platform_device_unregister(p50->leds_pdev); 379 380 gpiod_remove_lookup_table(&p50_gpio_led_table); 381 } 382 383 static struct platform_driver p50_gpio_driver = { 384 .driver = { 385 .name = DRIVER_NAME, 386 }, 387 .probe = p50_gpio_probe, 388 .remove_new = p50_gpio_remove, 389 }; 390 391 /* Board setup */ 392 static const struct dmi_system_id dmi_ids[] __initconst = { 393 { 394 .matches = { 395 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Barco"), 396 DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "P50") 397 }, 398 }, 399 {} 400 }; 401 MODULE_DEVICE_TABLE(dmi, dmi_ids); 402 403 static int __init p50_module_init(void) 404 { 405 struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1); 406 int ret; 407 408 if (!dmi_first_match(dmi_ids)) 409 return -ENODEV; 410 411 ret = platform_driver_register(&p50_gpio_driver); 412 if (ret) 413 return ret; 414 415 gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1); 416 if (IS_ERR(gpio_pdev)) { 417 pr_err("failed registering %s: %ld\n", DRIVER_NAME, PTR_ERR(gpio_pdev)); 418 platform_driver_unregister(&p50_gpio_driver); 419 return PTR_ERR(gpio_pdev); 420 } 421 422 return 0; 423 } 424 425 static void __exit p50_module_exit(void) 426 { 427 platform_device_unregister(gpio_pdev); 428 platform_driver_unregister(&p50_gpio_driver); 429 } 430 431 module_init(p50_module_init); 432 module_exit(p50_module_exit); 433 434 MODULE_AUTHOR("Santosh Kumar Yadav, Barco NV <santoshkumar.yadav@barco.com>"); 435 MODULE_DESCRIPTION("Barco P50 identify GPIOs driver"); 436 MODULE_LICENSE("GPL"); 437