Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * Support for EC-connected GPIOs for identify
0005  * LED/button on Barco P50 board
0006  *
0007  * Copyright (C) 2021 Barco NV
0008  * Author: Santosh Kumar Yadav <santoshkumar.yadav@barco.com>
0009  */
0010 
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012 
0013 #include <linux/delay.h>
0014 #include <linux/dmi.h>
0015 #include <linux/err.h>
0016 #include <linux/io.h>
0017 #include <linux/kernel.h>
0018 #include <linux/leds.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/gpio_keys.h>
0022 #include <linux/gpio/driver.h>
0023 #include <linux/gpio/machine.h>
0024 #include <linux/input.h>
0025 
0026 
0027 #define DRIVER_NAME     "barco-p50-gpio"
0028 
0029 /* GPIO lines */
0030 #define P50_GPIO_LINE_LED   0
0031 #define P50_GPIO_LINE_BTN   1
0032 
0033 /* GPIO IO Ports */
0034 #define P50_GPIO_IO_PORT_BASE   0x299
0035 
0036 #define P50_PORT_DATA       0x00
0037 #define P50_PORT_CMD        0x01
0038 
0039 #define P50_STATUS_OBF      0x01 /* EC output buffer full */
0040 #define P50_STATUS_IBF      0x02 /* EC input buffer full */
0041 
0042 #define P50_CMD_READ        0xa0
0043 #define P50_CMD_WRITE       0x50
0044 
0045 /* EC mailbox registers */
0046 #define P50_MBOX_REG_CMD    0x00
0047 #define P50_MBOX_REG_STATUS 0x01
0048 #define P50_MBOX_REG_PARAM  0x02
0049 #define P50_MBOX_REG_DATA   0x03
0050 
0051 #define P50_MBOX_CMD_READ_GPIO  0x11
0052 #define P50_MBOX_CMD_WRITE_GPIO 0x12
0053 #define P50_MBOX_CMD_CLEAR  0xff
0054 
0055 #define P50_MBOX_STATUS_SUCCESS 0x01
0056 
0057 #define P50_MBOX_PARAM_LED  0x12
0058 #define P50_MBOX_PARAM_BTN  0x13
0059 
0060 
0061 struct p50_gpio {
0062     struct gpio_chip gc;
0063     struct mutex lock;
0064     unsigned long base;
0065     struct platform_device *leds_pdev;
0066     struct platform_device *keys_pdev;
0067 };
0068 
0069 static struct platform_device *gpio_pdev;
0070 
0071 static int gpio_params[] = {
0072     [P50_GPIO_LINE_LED] = P50_MBOX_PARAM_LED,
0073     [P50_GPIO_LINE_BTN] = P50_MBOX_PARAM_BTN,
0074 };
0075 
0076 static const char * const gpio_names[] = {
0077     [P50_GPIO_LINE_LED] = "identify-led",
0078     [P50_GPIO_LINE_BTN] = "identify-button",
0079 };
0080 
0081 
0082 static struct gpiod_lookup_table p50_gpio_led_table = {
0083     .dev_id = "leds-gpio",
0084     .table = {
0085         GPIO_LOOKUP_IDX(DRIVER_NAME, P50_GPIO_LINE_LED, NULL, 0, GPIO_ACTIVE_HIGH),
0086         {}
0087     }
0088 };
0089 
0090 /* GPIO LEDs */
0091 static struct gpio_led leds[] = {
0092     { .name = "identify" }
0093 };
0094 
0095 static struct gpio_led_platform_data leds_pdata = {
0096     .num_leds = ARRAY_SIZE(leds),
0097     .leds = leds,
0098 };
0099 
0100 /* GPIO keyboard */
0101 static struct gpio_keys_button buttons[] = {
0102     {
0103         .code = KEY_VENDOR,
0104         .gpio = P50_GPIO_LINE_BTN,
0105         .active_low = 1,
0106         .type = EV_KEY,
0107         .value = 1,
0108     },
0109 };
0110 
0111 static struct gpio_keys_platform_data keys_pdata = {
0112     .buttons = buttons,
0113     .nbuttons = ARRAY_SIZE(buttons),
0114     .poll_interval = 100,
0115     .rep = 0,
0116     .name = "identify",
0117 };
0118 
0119 
0120 /* low level access routines */
0121 
0122 static int p50_wait_ec(struct p50_gpio *p50, int mask, int expected)
0123 {
0124     int i, val;
0125 
0126     for (i = 0; i < 100; i++) {
0127         val = inb(p50->base + P50_PORT_CMD) & mask;
0128         if (val == expected)
0129             return 0;
0130         usleep_range(500, 2000);
0131     }
0132 
0133     dev_err(p50->gc.parent, "Timed out waiting for EC (0x%x)\n", val);
0134     return -ETIMEDOUT;
0135 }
0136 
0137 
0138 static int p50_read_mbox_reg(struct p50_gpio *p50, int reg)
0139 {
0140     int ret;
0141 
0142     ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
0143     if (ret)
0144         return ret;
0145 
0146     /* clear output buffer flag, prevent unfinished commands */
0147     inb(p50->base + P50_PORT_DATA);
0148 
0149     /* cmd/address */
0150     outb(P50_CMD_READ | reg, p50->base + P50_PORT_CMD);
0151 
0152     ret = p50_wait_ec(p50, P50_STATUS_OBF, P50_STATUS_OBF);
0153     if (ret)
0154         return ret;
0155 
0156     return inb(p50->base + P50_PORT_DATA);
0157 }
0158 
0159 static int p50_write_mbox_reg(struct p50_gpio *p50, int reg, int val)
0160 {
0161     int ret;
0162 
0163     ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
0164     if (ret)
0165         return ret;
0166 
0167     /* cmd/address */
0168     outb(P50_CMD_WRITE | reg, p50->base + P50_PORT_CMD);
0169 
0170     ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
0171     if (ret)
0172         return ret;
0173 
0174     /* data */
0175     outb(val, p50->base + P50_PORT_DATA);
0176 
0177     return 0;
0178 }
0179 
0180 
0181 /* mbox routines */
0182 
0183 static int p50_wait_mbox_idle(struct p50_gpio *p50)
0184 {
0185     int i, val;
0186 
0187     for (i = 0; i < 1000; i++) {
0188         val = p50_read_mbox_reg(p50, P50_MBOX_REG_CMD);
0189         /* cmd is 0 when idle */
0190         if (val <= 0)
0191             return val;
0192 
0193         usleep_range(500, 2000);
0194     }
0195 
0196     dev_err(p50->gc.parent, "Timed out waiting for EC mbox idle (CMD: 0x%x)\n", val);
0197 
0198     return -ETIMEDOUT;
0199 }
0200 
0201 static int p50_send_mbox_cmd(struct p50_gpio *p50, int cmd, int param, int data)
0202 {
0203     int ret;
0204 
0205     ret = p50_wait_mbox_idle(p50);
0206     if (ret)
0207         return ret;
0208 
0209     ret = p50_write_mbox_reg(p50, P50_MBOX_REG_DATA, data);
0210     if (ret)
0211         return ret;
0212 
0213     ret = p50_write_mbox_reg(p50, P50_MBOX_REG_PARAM, param);
0214     if (ret)
0215         return ret;
0216 
0217     ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, cmd);
0218     if (ret)
0219         return ret;
0220 
0221     ret = p50_wait_mbox_idle(p50);
0222     if (ret)
0223         return ret;
0224 
0225     ret = p50_read_mbox_reg(p50, P50_MBOX_REG_STATUS);
0226     if (ret < 0)
0227         return ret;
0228 
0229     if (ret == P50_MBOX_STATUS_SUCCESS)
0230         return 0;
0231 
0232     dev_err(p50->gc.parent, "Mbox command failed (CMD=0x%x STAT=0x%x PARAM=0x%x DATA=0x%x)\n",
0233         cmd, ret, param, data);
0234 
0235     return -EIO;
0236 }
0237 
0238 
0239 /* gpio routines */
0240 
0241 static int p50_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
0242 {
0243     switch (offset) {
0244     case P50_GPIO_LINE_BTN:
0245         return GPIO_LINE_DIRECTION_IN;
0246 
0247     case P50_GPIO_LINE_LED:
0248         return GPIO_LINE_DIRECTION_OUT;
0249 
0250     default:
0251         return -EINVAL;
0252     }
0253 }
0254 
0255 static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset)
0256 {
0257     struct p50_gpio *p50 = gpiochip_get_data(gc);
0258     int ret;
0259 
0260     mutex_lock(&p50->lock);
0261 
0262     ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0);
0263     if (ret == 0)
0264         ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
0265 
0266     mutex_unlock(&p50->lock);
0267 
0268     return ret;
0269 }
0270 
0271 static void p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
0272 {
0273     struct p50_gpio *p50 = gpiochip_get_data(gc);
0274 
0275     mutex_lock(&p50->lock);
0276 
0277     p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, gpio_params[offset], value);
0278 
0279     mutex_unlock(&p50->lock);
0280 }
0281 
0282 static int p50_gpio_probe(struct platform_device *pdev)
0283 {
0284     struct p50_gpio *p50;
0285     struct resource *res;
0286     int ret;
0287 
0288     res = platform_get_resource(pdev, IORESOURCE_IO, 0);
0289     if (!res) {
0290         dev_err(&pdev->dev, "Cannot get I/O ports\n");
0291         return -ENODEV;
0292     }
0293 
0294     if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) {
0295         dev_err(&pdev->dev, "Unable to reserve I/O region\n");
0296         return -EBUSY;
0297     }
0298 
0299     p50 = devm_kzalloc(&pdev->dev, sizeof(*p50), GFP_KERNEL);
0300     if (!p50)
0301         return -ENOMEM;
0302 
0303     platform_set_drvdata(pdev, p50);
0304     mutex_init(&p50->lock);
0305     p50->base = res->start;
0306     p50->gc.owner = THIS_MODULE;
0307     p50->gc.parent = &pdev->dev;
0308     p50->gc.label = dev_name(&pdev->dev);
0309     p50->gc.ngpio = ARRAY_SIZE(gpio_names);
0310     p50->gc.names = gpio_names;
0311     p50->gc.can_sleep = true;
0312     p50->gc.base = -1;
0313     p50->gc.get_direction = p50_gpio_get_direction;
0314     p50->gc.get = p50_gpio_get;
0315     p50->gc.set = p50_gpio_set;
0316 
0317 
0318     /* reset mbox */
0319     ret = p50_wait_mbox_idle(p50);
0320     if (ret)
0321         return ret;
0322 
0323     ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, P50_MBOX_CMD_CLEAR);
0324     if (ret)
0325         return ret;
0326 
0327     ret = p50_wait_mbox_idle(p50);
0328     if (ret)
0329         return ret;
0330 
0331 
0332     ret = devm_gpiochip_add_data(&pdev->dev, &p50->gc, p50);
0333     if (ret < 0) {
0334         dev_err(&pdev->dev, "Could not register gpiochip: %d\n", ret);
0335         return ret;
0336     }
0337 
0338     gpiod_add_lookup_table(&p50_gpio_led_table);
0339 
0340     p50->leds_pdev = platform_device_register_data(&pdev->dev,
0341         "leds-gpio", PLATFORM_DEVID_NONE, &leds_pdata, sizeof(leds_pdata));
0342 
0343     if (IS_ERR(p50->leds_pdev)) {
0344         ret = PTR_ERR(p50->leds_pdev);
0345         dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret);
0346         goto err_leds;
0347     }
0348 
0349     /* gpio-keys-polled uses old-style gpio interface, pass the right identifier */
0350     buttons[0].gpio += p50->gc.base;
0351 
0352     p50->keys_pdev =
0353         platform_device_register_data(&pdev->dev, "gpio-keys-polled",
0354                           PLATFORM_DEVID_NONE,
0355                           &keys_pdata, sizeof(keys_pdata));
0356 
0357     if (IS_ERR(p50->keys_pdev)) {
0358         ret = PTR_ERR(p50->keys_pdev);
0359         dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret);
0360         goto err_keys;
0361     }
0362 
0363     return 0;
0364 
0365 err_keys:
0366     platform_device_unregister(p50->leds_pdev);
0367 err_leds:
0368     gpiod_remove_lookup_table(&p50_gpio_led_table);
0369 
0370     return ret;
0371 }
0372 
0373 static int p50_gpio_remove(struct platform_device *pdev)
0374 {
0375     struct p50_gpio *p50 = platform_get_drvdata(pdev);
0376 
0377     platform_device_unregister(p50->keys_pdev);
0378     platform_device_unregister(p50->leds_pdev);
0379 
0380     gpiod_remove_lookup_table(&p50_gpio_led_table);
0381 
0382     return 0;
0383 }
0384 
0385 static struct platform_driver p50_gpio_driver = {
0386     .driver = {
0387         .name = DRIVER_NAME,
0388     },
0389     .probe = p50_gpio_probe,
0390     .remove = p50_gpio_remove,
0391 };
0392 
0393 /* Board setup */
0394 static const struct dmi_system_id dmi_ids[] __initconst = {
0395     {
0396         .matches = {
0397             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Barco"),
0398             DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "P50")
0399         },
0400     },
0401     {}
0402 };
0403 MODULE_DEVICE_TABLE(dmi, dmi_ids);
0404 
0405 static int __init p50_module_init(void)
0406 {
0407     struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1);
0408     int ret;
0409 
0410     if (!dmi_first_match(dmi_ids))
0411         return -ENODEV;
0412 
0413     ret = platform_driver_register(&p50_gpio_driver);
0414     if (ret)
0415         return ret;
0416 
0417     gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1);
0418     if (IS_ERR(gpio_pdev)) {
0419         pr_err("failed registering %s: %ld\n", DRIVER_NAME, PTR_ERR(gpio_pdev));
0420         platform_driver_unregister(&p50_gpio_driver);
0421         return PTR_ERR(gpio_pdev);
0422     }
0423 
0424     return 0;
0425 }
0426 
0427 static void __exit p50_module_exit(void)
0428 {
0429     platform_device_unregister(gpio_pdev);
0430     platform_driver_unregister(&p50_gpio_driver);
0431 }
0432 
0433 module_init(p50_module_init);
0434 module_exit(p50_module_exit);
0435 
0436 MODULE_AUTHOR("Santosh Kumar Yadav, Barco NV <santoshkumar.yadav@barco.com>");
0437 MODULE_DESCRIPTION("Barco P50 identify GPIOs driver");
0438 MODULE_LICENSE("GPL");