root/drivers/media/platform/seco-cec/seco-cec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_word_op
  2. secocec_adap_enable
  3. secocec_adap_log_addr
  4. secocec_adap_transmit
  5. secocec_tx_done
  6. secocec_rx_done
  7. secocec_ir_probe
  8. secocec_ir_rx
  9. secocec_ir_rx
  10. secocec_ir_probe
  11. secocec_irq_handler
  12. secocec_cec_find_hdmi_dev
  13. secocec_acpi_probe
  14. secocec_probe
  15. secocec_remove
  16. secocec_suspend
  17. secocec_resume

   1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2 /*
   3  * CEC driver for SECO X86 Boards
   4  *
   5  * Author:  Ettore Chimenti <ek5.chimenti@gmail.com>
   6  * Copyright (C) 2018, SECO SpA.
   7  * Copyright (C) 2018, Aidilab Srl.
   8  */
   9 
  10 #include <linux/module.h>
  11 #include <linux/acpi.h>
  12 #include <linux/delay.h>
  13 #include <linux/dmi.h>
  14 #include <linux/gpio/consumer.h>
  15 #include <linux/gpio.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/pci.h>
  18 #include <linux/platform_device.h>
  19 
  20 /* CEC Framework */
  21 #include <media/cec-notifier.h>
  22 
  23 #include "seco-cec.h"
  24 
  25 struct secocec_data {
  26         struct device *dev;
  27         struct platform_device *pdev;
  28         struct cec_adapter *cec_adap;
  29         struct cec_notifier *notifier;
  30         struct rc_dev *ir;
  31         char ir_input_phys[32];
  32         int irq;
  33 };
  34 
  35 #define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
  36                                              cmd, data, SMBUS_WRITE, NULL)
  37 #define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
  38                                        cmd, 0, SMBUS_READ, res)
  39 
  40 static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
  41                        u8 operation, u16 *result)
  42 {
  43         unsigned int count;
  44         short _data_format;
  45         int status = 0;
  46 
  47         switch (data_format) {
  48         case CMD_BYTE_DATA:
  49                 _data_format = BRA_SMB_CMD_BYTE_DATA;
  50                 break;
  51         case CMD_WORD_DATA:
  52                 _data_format = BRA_SMB_CMD_WORD_DATA;
  53                 break;
  54         default:
  55                 return -EINVAL;
  56         }
  57 
  58         /* Active wait until ready */
  59         for (count = 0; count <= SMBTIMEOUT; ++count) {
  60                 if (!(inb(HSTS) & BRA_INUSE_STS))
  61                         break;
  62                 udelay(SMB_POLL_UDELAY);
  63         }
  64 
  65         if (count > SMBTIMEOUT)
  66                 /* Reset the lock instead of failing */
  67                 outb(0xff, HSTS);
  68 
  69         outb(0x00, HCNT);
  70         outb((u8)(slave_addr & 0xfe) | operation, XMIT_SLVA);
  71         outb(cmd, HCMD);
  72         inb(HCNT);
  73 
  74         if (operation == SMBUS_WRITE) {
  75                 outb((u8)data, HDAT0);
  76                 outb((u8)(data >> 8), HDAT1);
  77         }
  78 
  79         outb(BRA_START + _data_format, HCNT);
  80 
  81         for (count = 0; count <= SMBTIMEOUT; count++) {
  82                 if (!(inb(HSTS) & BRA_HOST_BUSY))
  83                         break;
  84                 udelay(SMB_POLL_UDELAY);
  85         }
  86 
  87         if (count > SMBTIMEOUT) {
  88                 status = -EBUSY;
  89                 goto err;
  90         }
  91 
  92         if (inb(HSTS) & BRA_HSTS_ERR_MASK) {
  93                 status = -EIO;
  94                 goto err;
  95         }
  96 
  97         if (operation == SMBUS_READ)
  98                 *result = ((inb(HDAT0) & 0xff) + ((inb(HDAT1) & 0xff) << 8));
  99 
 100 err:
 101         outb(0xff, HSTS);
 102         return status;
 103 }
 104 
 105 static int secocec_adap_enable(struct cec_adapter *adap, bool enable)
 106 {
 107         struct secocec_data *cec = cec_get_drvdata(adap);
 108         struct device *dev = cec->dev;
 109         u16 val = 0;
 110         int status;
 111 
 112         if (enable) {
 113                 /* Clear the status register */
 114                 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
 115                 if (status)
 116                         goto err;
 117 
 118                 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 119                 if (status)
 120                         goto err;
 121 
 122                 /* Enable the interrupts */
 123                 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 124                 if (status)
 125                         goto err;
 126 
 127                 status = smb_wr16(SECOCEC_ENABLE_REG_1,
 128                                   val | SECOCEC_ENABLE_REG_1_CEC);
 129                 if (status)
 130                         goto err;
 131 
 132                 dev_dbg(dev, "Device enabled");
 133         } else {
 134                 /* Clear the status register */
 135                 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
 136                 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 137 
 138                 /* Disable the interrupts */
 139                 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 140                 status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
 141                                   ~SECOCEC_ENABLE_REG_1_CEC &
 142                                   ~SECOCEC_ENABLE_REG_1_IR);
 143 
 144                 dev_dbg(dev, "Device disabled");
 145         }
 146 
 147         return 0;
 148 err:
 149         return status;
 150 }
 151 
 152 static int secocec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
 153 {
 154         u16 enable_val = 0;
 155         int status;
 156 
 157         /* Disable device */
 158         status = smb_rd16(SECOCEC_ENABLE_REG_1, &enable_val);
 159         if (status)
 160                 return status;
 161 
 162         status = smb_wr16(SECOCEC_ENABLE_REG_1,
 163                           enable_val & ~SECOCEC_ENABLE_REG_1_CEC);
 164         if (status)
 165                 return status;
 166 
 167         /* Write logical address
 168          * NOTE: CEC_LOG_ADDR_INVALID is mapped to the 'Unregistered' LA
 169          */
 170         status = smb_wr16(SECOCEC_DEVICE_LA, logical_addr & 0xf);
 171         if (status)
 172                 return status;
 173 
 174         /* Re-enable device */
 175         status = smb_wr16(SECOCEC_ENABLE_REG_1,
 176                           enable_val | SECOCEC_ENABLE_REG_1_CEC);
 177         if (status)
 178                 return status;
 179 
 180         return 0;
 181 }
 182 
 183 static int secocec_adap_transmit(struct cec_adapter *adap, u8 attempts,
 184                                  u32 signal_free_time, struct cec_msg *msg)
 185 {
 186         u16 payload_len, payload_id_len, destination, val = 0;
 187         u8 *payload_msg;
 188         int status;
 189         u8 i;
 190 
 191         /* Device msg len already accounts for header */
 192         payload_id_len = msg->len - 1;
 193 
 194         /* Send data length */
 195         status = smb_wr16(SECOCEC_WRITE_DATA_LENGTH, payload_id_len);
 196         if (status)
 197                 goto err;
 198 
 199         /* Send Operation ID if present */
 200         if (payload_id_len > 0) {
 201                 status = smb_wr16(SECOCEC_WRITE_OPERATION_ID, msg->msg[1]);
 202                 if (status)
 203                         goto err;
 204         }
 205         /* Send data if present */
 206         if (payload_id_len > 1) {
 207                 /* Only data; */
 208                 payload_len = msg->len - 2;
 209                 payload_msg = &msg->msg[2];
 210 
 211                 /* Copy message into registers */
 212                 for (i = 0; i < payload_len; i += 2) {
 213                         /* hi byte */
 214                         val = payload_msg[i + 1] << 8;
 215 
 216                         /* lo byte */
 217                         val |= payload_msg[i];
 218 
 219                         status = smb_wr16(SECOCEC_WRITE_DATA_00 + i / 2, val);
 220                         if (status)
 221                                 goto err;
 222                 }
 223         }
 224         /* Send msg source/destination and fire msg */
 225         destination = msg->msg[0];
 226         status = smb_wr16(SECOCEC_WRITE_BYTE0, destination);
 227         if (status)
 228                 goto err;
 229 
 230         return 0;
 231 
 232 err:
 233         return status;
 234 }
 235 
 236 static void secocec_tx_done(struct cec_adapter *adap, u16 status_val)
 237 {
 238         if (status_val & SECOCEC_STATUS_TX_ERROR_MASK) {
 239                 if (status_val & SECOCEC_STATUS_TX_NACK_ERROR)
 240                         cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK);
 241                 else
 242                         cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR);
 243         } else {
 244                 cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK);
 245         }
 246 
 247         /* Reset status reg */
 248         status_val = SECOCEC_STATUS_TX_ERROR_MASK |
 249                 SECOCEC_STATUS_MSG_SENT_MASK |
 250                 SECOCEC_STATUS_TX_NACK_ERROR;
 251         smb_wr16(SECOCEC_STATUS, status_val);
 252 }
 253 
 254 static void secocec_rx_done(struct cec_adapter *adap, u16 status_val)
 255 {
 256         struct secocec_data *cec = cec_get_drvdata(adap);
 257         struct device *dev = cec->dev;
 258         struct cec_msg msg = { };
 259         bool flag_overflow = false;
 260         u8 payload_len, i = 0;
 261         u8 *payload_msg;
 262         u16 val = 0;
 263         int status;
 264 
 265         if (status_val & SECOCEC_STATUS_RX_OVERFLOW_MASK) {
 266                 /* NOTE: Untested, it also might not be necessary */
 267                 dev_warn(dev, "Received more than 16 bytes. Discarding");
 268                 flag_overflow = true;
 269         }
 270 
 271         if (status_val & SECOCEC_STATUS_RX_ERROR_MASK) {
 272                 dev_warn(dev, "Message received with errors. Discarding");
 273                 status = -EIO;
 274                 goto rxerr;
 275         }
 276 
 277         /* Read message length */
 278         status = smb_rd16(SECOCEC_READ_DATA_LENGTH, &val);
 279         if (status)
 280                 return;
 281 
 282         /* Device msg len already accounts for the header */
 283         msg.len = min(val + 1, CEC_MAX_MSG_SIZE);
 284 
 285         /* Read logical address */
 286         status = smb_rd16(SECOCEC_READ_BYTE0, &val);
 287         if (status)
 288                 return;
 289 
 290         /* device stores source LA and destination */
 291         msg.msg[0] = val;
 292 
 293         /* Read operation ID */
 294         status = smb_rd16(SECOCEC_READ_OPERATION_ID, &val);
 295         if (status)
 296                 return;
 297 
 298         msg.msg[1] = val;
 299 
 300         /* Read data if present */
 301         if (msg.len > 1) {
 302                 payload_len = msg.len - 2;
 303                 payload_msg = &msg.msg[2];
 304 
 305                 /* device stores 2 bytes in every 16-bit val */
 306                 for (i = 0; i < payload_len; i += 2) {
 307                         status = smb_rd16(SECOCEC_READ_DATA_00 + i / 2, &val);
 308                         if (status)
 309                                 return;
 310 
 311                         /* low byte, skipping header */
 312                         payload_msg[i] = val & 0x00ff;
 313 
 314                         /* hi byte */
 315                         payload_msg[i + 1] = (val & 0xff00) >> 8;
 316                 }
 317         }
 318 
 319         cec_received_msg(cec->cec_adap, &msg);
 320 
 321         /* Reset status reg */
 322         status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK;
 323         if (flag_overflow)
 324                 status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
 325 
 326         status = smb_wr16(SECOCEC_STATUS, status_val);
 327 
 328         return;
 329 
 330 rxerr:
 331         /* Reset error reg */
 332         status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK |
 333                 SECOCEC_STATUS_RX_ERROR_MASK;
 334         if (flag_overflow)
 335                 status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
 336         smb_wr16(SECOCEC_STATUS, status_val);
 337 }
 338 
 339 static const struct cec_adap_ops secocec_cec_adap_ops = {
 340         /* Low-level callbacks */
 341         .adap_enable = secocec_adap_enable,
 342         .adap_log_addr = secocec_adap_log_addr,
 343         .adap_transmit = secocec_adap_transmit,
 344 };
 345 
 346 #ifdef CONFIG_VIDEO_SECO_RC
 347 static int secocec_ir_probe(void *priv)
 348 {
 349         struct secocec_data *cec = priv;
 350         struct device *dev = cec->dev;
 351         int status;
 352         u16 val;
 353 
 354         /* Prepare the RC input device */
 355         cec->ir = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
 356         if (!cec->ir)
 357                 return -ENOMEM;
 358 
 359         snprintf(cec->ir_input_phys, sizeof(cec->ir_input_phys),
 360                  "%s/input0", dev_name(dev));
 361 
 362         cec->ir->device_name = dev_name(dev);
 363         cec->ir->input_phys = cec->ir_input_phys;
 364         cec->ir->input_id.bustype = BUS_HOST;
 365         cec->ir->input_id.vendor = 0;
 366         cec->ir->input_id.product = 0;
 367         cec->ir->input_id.version = 1;
 368         cec->ir->driver_name = SECOCEC_DEV_NAME;
 369         cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
 370         cec->ir->priv = cec;
 371         cec->ir->map_name = RC_MAP_HAUPPAUGE;
 372         cec->ir->timeout = MS_TO_NS(100);
 373 
 374         /* Clear the status register */
 375         status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
 376         if (status != 0)
 377                 goto err;
 378 
 379         status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 380         if (status != 0)
 381                 goto err;
 382 
 383         /* Enable the interrupts */
 384         status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 385         if (status != 0)
 386                 goto err;
 387 
 388         status = smb_wr16(SECOCEC_ENABLE_REG_1,
 389                           val | SECOCEC_ENABLE_REG_1_IR);
 390         if (status != 0)
 391                 goto err;
 392 
 393         dev_dbg(dev, "IR enabled");
 394 
 395         status = devm_rc_register_device(dev, cec->ir);
 396 
 397         if (status) {
 398                 dev_err(dev, "Failed to prepare input device");
 399                 cec->ir = NULL;
 400                 goto err;
 401         }
 402 
 403         return 0;
 404 
 405 err:
 406         smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 407 
 408         smb_wr16(SECOCEC_ENABLE_REG_1,
 409                  val & ~SECOCEC_ENABLE_REG_1_IR);
 410 
 411         dev_dbg(dev, "IR disabled");
 412         return status;
 413 }
 414 
 415 static int secocec_ir_rx(struct secocec_data *priv)
 416 {
 417         struct secocec_data *cec = priv;
 418         struct device *dev = cec->dev;
 419         u16 val, status, key, addr, toggle;
 420 
 421         if (!cec->ir)
 422                 return -ENODEV;
 423 
 424         status = smb_rd16(SECOCEC_IR_READ_DATA, &val);
 425         if (status != 0)
 426                 goto err;
 427 
 428         key = val & SECOCEC_IR_COMMAND_MASK;
 429         addr = (val & SECOCEC_IR_ADDRESS_MASK) >> SECOCEC_IR_ADDRESS_SHL;
 430         toggle = (val & SECOCEC_IR_TOGGLE_MASK) >> SECOCEC_IR_TOGGLE_SHL;
 431 
 432         rc_keydown(cec->ir, RC_PROTO_RC5, RC_SCANCODE_RC5(addr, key), toggle);
 433 
 434         dev_dbg(dev, "IR key pressed: 0x%02x addr 0x%02x toggle 0x%02x", key,
 435                 addr, toggle);
 436 
 437         return 0;
 438 
 439 err:
 440         dev_err(dev, "IR Receive message failed (%d)", status);
 441         return -EIO;
 442 }
 443 #else
 444 static void secocec_ir_rx(struct secocec_data *priv)
 445 {
 446 }
 447 
 448 static int secocec_ir_probe(void *priv)
 449 {
 450         return 0;
 451 }
 452 #endif
 453 
 454 static irqreturn_t secocec_irq_handler(int irq, void *priv)
 455 {
 456         struct secocec_data *cec = priv;
 457         struct device *dev = cec->dev;
 458         u16 status_val, cec_val, val = 0;
 459         int status;
 460 
 461         /*  Read status register */
 462         status = smb_rd16(SECOCEC_STATUS_REG_1, &status_val);
 463         if (status)
 464                 goto err;
 465 
 466         if (status_val & SECOCEC_STATUS_REG_1_CEC) {
 467                 /* Read CEC status register */
 468                 status = smb_rd16(SECOCEC_STATUS, &cec_val);
 469                 if (status)
 470                         goto err;
 471 
 472                 if (cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK)
 473                         secocec_rx_done(cec->cec_adap, cec_val);
 474 
 475                 if (cec_val & SECOCEC_STATUS_MSG_SENT_MASK)
 476                         secocec_tx_done(cec->cec_adap, cec_val);
 477 
 478                 if ((~cec_val & SECOCEC_STATUS_MSG_SENT_MASK) &&
 479                     (~cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK))
 480                         dev_warn_once(dev,
 481                                       "Message not received or sent, but interrupt fired");
 482 
 483                 val = SECOCEC_STATUS_REG_1_CEC;
 484         }
 485 
 486         if (status_val & SECOCEC_STATUS_REG_1_IR) {
 487                 val |= SECOCEC_STATUS_REG_1_IR;
 488 
 489                 secocec_ir_rx(cec);
 490         }
 491 
 492         /*  Reset status register */
 493         status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 494         if (status)
 495                 goto err;
 496 
 497         return IRQ_HANDLED;
 498 
 499 err:
 500         dev_err_once(dev, "IRQ: R/W SMBus operation failed (%d)", status);
 501 
 502         /*  Reset status register */
 503         val = SECOCEC_STATUS_REG_1_CEC | SECOCEC_STATUS_REG_1_IR;
 504         smb_wr16(SECOCEC_STATUS_REG_1, val);
 505 
 506         return IRQ_HANDLED;
 507 }
 508 
 509 struct cec_dmi_match {
 510         const char *sys_vendor;
 511         const char *product_name;
 512         const char *devname;
 513         const char *conn;
 514 };
 515 
 516 static const struct cec_dmi_match secocec_dmi_match_table[] = {
 517         /* UDOO X86 */
 518         { "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
 519 };
 520 
 521 static struct device *secocec_cec_find_hdmi_dev(struct device *dev,
 522                                                 const char **conn)
 523 {
 524         int i;
 525 
 526         for (i = 0 ; i < ARRAY_SIZE(secocec_dmi_match_table) ; ++i) {
 527                 const struct cec_dmi_match *m = &secocec_dmi_match_table[i];
 528 
 529                 if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
 530                     dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
 531                         struct device *d;
 532 
 533                         /* Find the device, bail out if not yet registered */
 534                         d = bus_find_device_by_name(&pci_bus_type, NULL,
 535                                                     m->devname);
 536                         if (!d)
 537                                 return ERR_PTR(-EPROBE_DEFER);
 538 
 539                         put_device(d);
 540                         *conn = m->conn;
 541                         return d;
 542                 }
 543         }
 544 
 545         return ERR_PTR(-EINVAL);
 546 }
 547 
 548 static int secocec_acpi_probe(struct secocec_data *sdev)
 549 {
 550         struct device *dev = sdev->dev;
 551         struct gpio_desc *gpio;
 552         int irq = 0;
 553 
 554         gpio = devm_gpiod_get(dev, NULL, GPIOF_IN);
 555         if (IS_ERR(gpio)) {
 556                 dev_err(dev, "Cannot request interrupt gpio");
 557                 return PTR_ERR(gpio);
 558         }
 559 
 560         irq = gpiod_to_irq(gpio);
 561         if (irq < 0) {
 562                 dev_err(dev, "Cannot find valid irq");
 563                 return -ENODEV;
 564         }
 565         dev_dbg(dev, "irq-gpio is bound to IRQ %d", irq);
 566 
 567         sdev->irq = irq;
 568 
 569         return 0;
 570 }
 571 
 572 static int secocec_probe(struct platform_device *pdev)
 573 {
 574         struct secocec_data *secocec;
 575         struct device *dev = &pdev->dev;
 576         struct device *hdmi_dev;
 577         const char *conn = NULL;
 578         int ret;
 579         u16 val;
 580 
 581         hdmi_dev = secocec_cec_find_hdmi_dev(&pdev->dev, &conn);
 582         if (IS_ERR(hdmi_dev))
 583                 return PTR_ERR(hdmi_dev);
 584 
 585         secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL);
 586         if (!secocec)
 587                 return -ENOMEM;
 588 
 589         dev_set_drvdata(dev, secocec);
 590 
 591         /* Request SMBus regions */
 592         if (!request_muxed_region(BRA_SMB_BASE_ADDR, 7, "CEC00001")) {
 593                 dev_err(dev, "Request memory region failed");
 594                 return -ENXIO;
 595         }
 596 
 597         secocec->pdev = pdev;
 598         secocec->dev = dev;
 599 
 600         if (!has_acpi_companion(dev)) {
 601                 dev_dbg(dev, "Cannot find any ACPI companion");
 602                 ret = -ENODEV;
 603                 goto err;
 604         }
 605 
 606         ret = secocec_acpi_probe(secocec);
 607         if (ret) {
 608                 dev_err(dev, "Cannot assign gpio to IRQ");
 609                 ret = -ENODEV;
 610                 goto err;
 611         }
 612 
 613         /* Firmware version check */
 614         ret = smb_rd16(SECOCEC_VERSION, &val);
 615         if (ret) {
 616                 dev_err(dev, "Cannot check fw version");
 617                 goto err;
 618         }
 619         if (val < SECOCEC_LATEST_FW) {
 620                 dev_err(dev, "CEC Firmware not supported (v.%04x). Use ver > v.%04x",
 621                         val, SECOCEC_LATEST_FW);
 622                 ret = -EINVAL;
 623                 goto err;
 624         }
 625 
 626         ret = devm_request_threaded_irq(dev,
 627                                         secocec->irq,
 628                                         NULL,
 629                                         secocec_irq_handler,
 630                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 631                                         dev_name(&pdev->dev), secocec);
 632 
 633         if (ret) {
 634                 dev_err(dev, "Cannot request IRQ %d", secocec->irq);
 635                 ret = -EIO;
 636                 goto err;
 637         }
 638 
 639         /* Allocate CEC adapter */
 640         secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops,
 641                                                  secocec,
 642                                                  dev_name(dev),
 643                                                  CEC_CAP_DEFAULTS |
 644                                                  CEC_CAP_CONNECTOR_INFO,
 645                                                  SECOCEC_MAX_ADDRS);
 646 
 647         if (IS_ERR(secocec->cec_adap)) {
 648                 ret = PTR_ERR(secocec->cec_adap);
 649                 goto err;
 650         }
 651 
 652         secocec->notifier = cec_notifier_cec_adap_register(hdmi_dev, conn,
 653                                                            secocec->cec_adap);
 654         if (!secocec->notifier) {
 655                 ret = -ENOMEM;
 656                 goto err_delete_adapter;
 657         }
 658 
 659         ret = cec_register_adapter(secocec->cec_adap, dev);
 660         if (ret)
 661                 goto err_notifier;
 662 
 663         ret = secocec_ir_probe(secocec);
 664         if (ret)
 665                 goto err_notifier;
 666 
 667         platform_set_drvdata(pdev, secocec);
 668 
 669         dev_dbg(dev, "Device registered");
 670 
 671         return ret;
 672 
 673 err_notifier:
 674         cec_notifier_cec_adap_unregister(secocec->notifier);
 675 err_delete_adapter:
 676         cec_delete_adapter(secocec->cec_adap);
 677 err:
 678         release_region(BRA_SMB_BASE_ADDR, 7);
 679         dev_err(dev, "%s device probe failed\n", dev_name(dev));
 680 
 681         return ret;
 682 }
 683 
 684 static int secocec_remove(struct platform_device *pdev)
 685 {
 686         struct secocec_data *secocec = platform_get_drvdata(pdev);
 687         u16 val;
 688 
 689         if (secocec->ir) {
 690                 smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 691 
 692                 smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR);
 693 
 694                 dev_dbg(&pdev->dev, "IR disabled");
 695         }
 696         cec_notifier_cec_adap_unregister(secocec->notifier);
 697         cec_unregister_adapter(secocec->cec_adap);
 698 
 699         release_region(BRA_SMB_BASE_ADDR, 7);
 700 
 701         dev_dbg(&pdev->dev, "CEC device removed");
 702 
 703         return 0;
 704 }
 705 
 706 #ifdef CONFIG_PM_SLEEP
 707 static int secocec_suspend(struct device *dev)
 708 {
 709         int status;
 710         u16 val;
 711 
 712         dev_dbg(dev, "Device going to suspend, disabling");
 713 
 714         /* Clear the status register */
 715         status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
 716         if (status)
 717                 goto err;
 718 
 719         status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 720         if (status)
 721                 goto err;
 722 
 723         /* Disable the interrupts */
 724         status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 725         if (status)
 726                 goto err;
 727 
 728         status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
 729                           ~SECOCEC_ENABLE_REG_1_CEC & ~SECOCEC_ENABLE_REG_1_IR);
 730         if (status)
 731                 goto err;
 732 
 733         return 0;
 734 
 735 err:
 736         dev_err(dev, "Suspend failed (err: %d)", status);
 737         return status;
 738 }
 739 
 740 static int secocec_resume(struct device *dev)
 741 {
 742         int status;
 743         u16 val;
 744 
 745         dev_dbg(dev, "Resuming device from suspend");
 746 
 747         /* Clear the status register */
 748         status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
 749         if (status)
 750                 goto err;
 751 
 752         status = smb_wr16(SECOCEC_STATUS_REG_1, val);
 753         if (status)
 754                 goto err;
 755 
 756         /* Enable the interrupts */
 757         status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
 758         if (status)
 759                 goto err;
 760 
 761         status = smb_wr16(SECOCEC_ENABLE_REG_1, val | SECOCEC_ENABLE_REG_1_CEC);
 762         if (status)
 763                 goto err;
 764 
 765         dev_dbg(dev, "Device resumed from suspend");
 766 
 767         return 0;
 768 
 769 err:
 770         dev_err(dev, "Resume failed (err: %d)", status);
 771         return status;
 772 }
 773 
 774 static SIMPLE_DEV_PM_OPS(secocec_pm_ops, secocec_suspend, secocec_resume);
 775 #define SECOCEC_PM_OPS (&secocec_pm_ops)
 776 #else
 777 #define SECOCEC_PM_OPS NULL
 778 #endif
 779 
 780 #ifdef CONFIG_ACPI
 781 static const struct acpi_device_id secocec_acpi_match[] = {
 782         {"CEC00001", 0},
 783         {},
 784 };
 785 
 786 MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
 787 #endif
 788 
 789 static struct platform_driver secocec_driver = {
 790         .driver = {
 791                    .name = SECOCEC_DEV_NAME,
 792                    .acpi_match_table = ACPI_PTR(secocec_acpi_match),
 793                    .pm = SECOCEC_PM_OPS,
 794         },
 795         .probe = secocec_probe,
 796         .remove = secocec_remove,
 797 };
 798 
 799 module_platform_driver(secocec_driver);
 800 
 801 MODULE_DESCRIPTION("SECO CEC X86 Driver");
 802 MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
 803 MODULE_LICENSE("Dual BSD/GPL");

/* [<][>][^][v][top][bottom][index][help] */