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