Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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