Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for the Chrontel CH7322 CEC Controller
0004  *
0005  * Copyright 2020 Google LLC.
0006  */
0007 
0008 /*
0009  * Notes
0010  *
0011  * - This device powers on in Auto Mode which has limited functionality. This
0012  *   driver disables Auto Mode when it attaches.
0013  *
0014  */
0015 
0016 #include <linux/cec.h>
0017 #include <linux/dmi.h>
0018 #include <linux/i2c.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/module.h>
0021 #include <linux/mutex.h>
0022 #include <linux/pci.h>
0023 #include <linux/regmap.h>
0024 #include <media/cec.h>
0025 #include <media/cec-notifier.h>
0026 
0027 #define CH7322_WRITE        0x00
0028 #define CH7322_WRITE_MSENT      0x80
0029 #define CH7322_WRITE_BOK        0x40
0030 #define CH7322_WRITE_NMASK      0x0f
0031 
0032 /* Write buffer is 0x01-0x10 */
0033 #define CH7322_WRBUF        0x01
0034 #define CH7322_WRBUF_LEN    0x10
0035 
0036 #define CH7322_READ     0x40
0037 #define CH7322_READ_NRDT        0x80
0038 #define CH7322_READ_MSENT       0x20
0039 #define CH7322_READ_NMASK       0x0f
0040 
0041 /* Read buffer is 0x41-0x50 */
0042 #define CH7322_RDBUF        0x41
0043 #define CH7322_RDBUF_LEN    0x10
0044 
0045 #define CH7322_MODE     0x11
0046 #define CH7322_MODE_AUTO        0x78
0047 #define CH7322_MODE_SW          0xb5
0048 
0049 #define CH7322_RESET        0x12
0050 #define CH7322_RESET_RST        0x00
0051 
0052 #define CH7322_POWER        0x13
0053 #define CH7322_POWER_FPD        0x04
0054 
0055 #define CH7322_CFG0     0x17
0056 #define CH7322_CFG0_EOBEN       0x40
0057 #define CH7322_CFG0_PEOB        0x20
0058 #define CH7322_CFG0_CLRSPP      0x10
0059 #define CH7322_CFG0_FLOW        0x08
0060 
0061 #define CH7322_CFG1     0x1a
0062 #define CH7322_CFG1_STDBYO      0x04
0063 #define CH7322_CFG1_HPBP        0x02
0064 #define CH7322_CFG1_PIO         0x01
0065 
0066 #define CH7322_INTCTL       0x1b
0067 #define CH7322_INTCTL_INTPB     0x80
0068 #define CH7322_INTCTL_STDBY     0x40
0069 #define CH7322_INTCTL_HPDFALL       0x20
0070 #define CH7322_INTCTL_HPDRISE       0x10
0071 #define CH7322_INTCTL_RXMSG     0x08
0072 #define CH7322_INTCTL_TXMSG     0x04
0073 #define CH7322_INTCTL_NEWPHA        0x02
0074 #define CH7322_INTCTL_ERROR     0x01
0075 
0076 #define CH7322_DVCLKFNH 0x1d
0077 #define CH7322_DVCLKFNL 0x1e
0078 
0079 #define CH7322_CTL      0x31
0080 #define CH7322_CTL_FSTDBY       0x80
0081 #define CH7322_CTL_PLSEN        0x40
0082 #define CH7322_CTL_PLSPB        0x20
0083 #define CH7322_CTL_SPADL        0x10
0084 #define CH7322_CTL_HINIT        0x08
0085 #define CH7322_CTL_WPHYA        0x04
0086 #define CH7322_CTL_H1T          0x02
0087 #define CH7322_CTL_S1T          0x01
0088 
0089 #define CH7322_PAWH     0x32
0090 #define CH7322_PAWL     0x33
0091 
0092 #define CH7322_ADDLW        0x34
0093 #define CH7322_ADDLW_MASK   0xf0
0094 
0095 #define CH7322_ADDLR        0x3d
0096 #define CH7322_ADDLR_HPD        0x80
0097 #define CH7322_ADDLR_MASK       0x0f
0098 
0099 #define CH7322_INTDATA      0x3e
0100 #define CH7322_INTDATA_MODE     0x80
0101 #define CH7322_INTDATA_STDBY        0x40
0102 #define CH7322_INTDATA_HPDFALL      0x20
0103 #define CH7322_INTDATA_HPDRISE      0x10
0104 #define CH7322_INTDATA_RXMSG        0x08
0105 #define CH7322_INTDATA_TXMSG        0x04
0106 #define CH7322_INTDATA_NEWPHA       0x02
0107 #define CH7322_INTDATA_ERROR        0x01
0108 
0109 #define CH7322_EVENT        0x3f
0110 #define CH7322_EVENT_TXERR      0x80
0111 #define CH7322_EVENT_HRST       0x40
0112 #define CH7322_EVENT_HFST       0x20
0113 #define CH7322_EVENT_PHACHG     0x10
0114 #define CH7322_EVENT_ACTST      0x08
0115 #define CH7322_EVENT_PHARDY     0x04
0116 #define CH7322_EVENT_BSOK       0x02
0117 #define CH7322_EVENT_ERRADCF        0x01
0118 
0119 #define CH7322_DID      0x51
0120 #define CH7322_DID_CH7322       0x5b
0121 #define CH7322_DID_CH7323       0x5f
0122 
0123 #define CH7322_REVISIONID   0x52
0124 
0125 #define CH7322_PARH     0x53
0126 #define CH7322_PARL     0x54
0127 
0128 #define CH7322_IOCFG2       0x75
0129 #define CH7322_IOCFG_CIO        0x80
0130 #define CH7322_IOCFG_IOCFGMASK      0x78
0131 #define CH7322_IOCFG_AUDIO      0x04
0132 #define CH7322_IOCFG_SPAMST     0x02
0133 #define CH7322_IOCFG_SPAMSP     0x01
0134 
0135 #define CH7322_CTL3     0x7b
0136 #define CH7322_CTL3_SWENA       0x80
0137 #define CH7322_CTL3_FC_INIT     0x40
0138 #define CH7322_CTL3_SML_FL      0x20
0139 #define CH7322_CTL3_SM_RDST     0x10
0140 #define CH7322_CTL3_SPP_CIAH        0x08
0141 #define CH7322_CTL3_SPP_CIAL        0x04
0142 #define CH7322_CTL3_SPP_ACTH        0x02
0143 #define CH7322_CTL3_SPP_ACTL        0x01
0144 
0145 /* BOK status means NACK */
0146 #define CH7322_TX_FLAG_NACK BIT(0)
0147 /* Device will retry automatically */
0148 #define CH7322_TX_FLAG_RETRY    BIT(1)
0149 
0150 struct ch7322 {
0151     struct i2c_client *i2c;
0152     struct regmap *regmap;
0153     struct cec_adapter *cec;
0154     struct mutex mutex; /* device access mutex */
0155     u8 tx_flags;
0156 };
0157 
0158 static const struct regmap_config ch7322_regmap = {
0159     .reg_bits = 8,
0160     .val_bits = 8,
0161     .max_register = 0x7f,
0162     .disable_locking = true,
0163 };
0164 
0165 static int ch7322_send_message(struct ch7322 *ch7322, const struct cec_msg *msg)
0166 {
0167     unsigned int val;
0168     unsigned int len = msg->len;
0169     int ret;
0170     int i;
0171 
0172     WARN_ON(!mutex_is_locked(&ch7322->mutex));
0173 
0174     if (len > CH7322_WRBUF_LEN || len < 1)
0175         return -EINVAL;
0176 
0177     ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
0178     if (ret)
0179         return ret;
0180 
0181     /* Buffer not ready */
0182     if (!(val & CH7322_WRITE_MSENT))
0183         return -EBUSY;
0184 
0185     if (cec_msg_opcode(msg) == -1 &&
0186         cec_msg_initiator(msg) == cec_msg_destination(msg)) {
0187         ch7322->tx_flags = CH7322_TX_FLAG_NACK | CH7322_TX_FLAG_RETRY;
0188     } else if (cec_msg_is_broadcast(msg)) {
0189         ch7322->tx_flags = CH7322_TX_FLAG_NACK;
0190     } else {
0191         ch7322->tx_flags = CH7322_TX_FLAG_RETRY;
0192     }
0193 
0194     ret = regmap_write(ch7322->regmap, CH7322_WRITE, len - 1);
0195     if (ret)
0196         return ret;
0197 
0198     for (i = 0; i < len; i++) {
0199         ret = regmap_write(ch7322->regmap,
0200                    CH7322_WRBUF + i, msg->msg[i]);
0201         if (ret)
0202             return ret;
0203     }
0204 
0205     return 0;
0206 }
0207 
0208 static int ch7322_receive_message(struct ch7322 *ch7322, struct cec_msg *msg)
0209 {
0210     unsigned int val;
0211     int ret = 0;
0212     int i;
0213 
0214     WARN_ON(!mutex_is_locked(&ch7322->mutex));
0215 
0216     ret = regmap_read(ch7322->regmap, CH7322_READ, &val);
0217     if (ret)
0218         return ret;
0219 
0220     /* Message not ready */
0221     if (!(val & CH7322_READ_NRDT))
0222         return -EIO;
0223 
0224     msg->len = (val & CH7322_READ_NMASK) + 1;
0225 
0226     /* Read entire RDBUF to clear state */
0227     for (i = 0; i < CH7322_RDBUF_LEN; i++) {
0228         ret = regmap_read(ch7322->regmap, CH7322_RDBUF + i, &val);
0229         if (ret)
0230             return ret;
0231         msg->msg[i] = (u8)val;
0232     }
0233 
0234     return 0;
0235 }
0236 
0237 static void ch7322_tx_done(struct ch7322 *ch7322)
0238 {
0239     int ret;
0240     unsigned int val;
0241     u8 status, flags;
0242 
0243     mutex_lock(&ch7322->mutex);
0244     ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val);
0245     flags = ch7322->tx_flags;
0246     mutex_unlock(&ch7322->mutex);
0247 
0248     /*
0249      * The device returns a one-bit OK status which usually means ACK but
0250      * actually means NACK when sending a logical address query or a
0251      * broadcast.
0252      */
0253     if (ret)
0254         status = CEC_TX_STATUS_ERROR;
0255     else if ((val & CH7322_WRITE_BOK) && (flags & CH7322_TX_FLAG_NACK))
0256         status = CEC_TX_STATUS_NACK;
0257     else if (val & CH7322_WRITE_BOK)
0258         status = CEC_TX_STATUS_OK;
0259     else if (flags & CH7322_TX_FLAG_NACK)
0260         status = CEC_TX_STATUS_OK;
0261     else
0262         status = CEC_TX_STATUS_NACK;
0263 
0264     if (status == CEC_TX_STATUS_NACK && (flags & CH7322_TX_FLAG_RETRY))
0265         status |= CEC_TX_STATUS_MAX_RETRIES;
0266 
0267     cec_transmit_attempt_done(ch7322->cec, status);
0268 }
0269 
0270 static void ch7322_rx_done(struct ch7322 *ch7322)
0271 {
0272     struct cec_msg msg;
0273     int ret;
0274 
0275     mutex_lock(&ch7322->mutex);
0276     ret = ch7322_receive_message(ch7322, &msg);
0277     mutex_unlock(&ch7322->mutex);
0278 
0279     if (ret)
0280         dev_err(&ch7322->i2c->dev, "cec receive error: %d\n", ret);
0281     else
0282         cec_received_msg(ch7322->cec, &msg);
0283 }
0284 
0285 /*
0286  * This device can either monitor the DDC lines to obtain the physical address
0287  * or it can allow the host to program it. This driver lets the device obtain
0288  * it.
0289  */
0290 static void ch7322_phys_addr(struct ch7322 *ch7322)
0291 {
0292     unsigned int pah, pal;
0293     int ret = 0;
0294 
0295     mutex_lock(&ch7322->mutex);
0296     ret |= regmap_read(ch7322->regmap, CH7322_PARH, &pah);
0297     ret |= regmap_read(ch7322->regmap, CH7322_PARL, &pal);
0298     mutex_unlock(&ch7322->mutex);
0299 
0300     if (ret)
0301         dev_err(&ch7322->i2c->dev, "phys addr error\n");
0302     else
0303         cec_s_phys_addr(ch7322->cec, pal | (pah << 8), false);
0304 }
0305 
0306 static irqreturn_t ch7322_irq(int irq, void *dev)
0307 {
0308     struct ch7322 *ch7322 = dev;
0309     unsigned int data = 0;
0310 
0311     mutex_lock(&ch7322->mutex);
0312     regmap_read(ch7322->regmap, CH7322_INTDATA, &data);
0313     regmap_write(ch7322->regmap, CH7322_INTDATA, data);
0314     mutex_unlock(&ch7322->mutex);
0315 
0316     if (data & CH7322_INTDATA_HPDFALL)
0317         cec_phys_addr_invalidate(ch7322->cec);
0318 
0319     if (data & CH7322_INTDATA_TXMSG)
0320         ch7322_tx_done(ch7322);
0321 
0322     if (data & CH7322_INTDATA_RXMSG)
0323         ch7322_rx_done(ch7322);
0324 
0325     if (data & CH7322_INTDATA_NEWPHA)
0326         ch7322_phys_addr(ch7322);
0327 
0328     if (data & CH7322_INTDATA_ERROR)
0329         dev_dbg(&ch7322->i2c->dev, "unknown error\n");
0330 
0331     return IRQ_HANDLED;
0332 }
0333 
0334 /* This device is always enabled */
0335 static int ch7322_cec_adap_enable(struct cec_adapter *adap, bool enable)
0336 {
0337     return 0;
0338 }
0339 
0340 static int ch7322_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
0341 {
0342     struct ch7322 *ch7322 = cec_get_drvdata(adap);
0343     int ret;
0344 
0345     mutex_lock(&ch7322->mutex);
0346     ret = regmap_update_bits(ch7322->regmap, CH7322_ADDLW,
0347                  CH7322_ADDLW_MASK, log_addr << 4);
0348     mutex_unlock(&ch7322->mutex);
0349 
0350     return ret;
0351 }
0352 
0353 static int ch7322_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
0354                     u32 signal_free_time, struct cec_msg *msg)
0355 {
0356     struct ch7322 *ch7322 = cec_get_drvdata(adap);
0357     int ret;
0358 
0359     mutex_lock(&ch7322->mutex);
0360     ret = ch7322_send_message(ch7322, msg);
0361     mutex_unlock(&ch7322->mutex);
0362 
0363     return ret;
0364 }
0365 
0366 static const struct cec_adap_ops ch7322_cec_adap_ops = {
0367     .adap_enable = ch7322_cec_adap_enable,
0368     .adap_log_addr = ch7322_cec_adap_log_addr,
0369     .adap_transmit = ch7322_cec_adap_transmit,
0370 };
0371 
0372 #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
0373 
0374 struct ch7322_conn_match {
0375     const char *dev_name;
0376     const char *pci_name;
0377     const char *port_name;
0378 };
0379 
0380 static struct ch7322_conn_match google_endeavour[] = {
0381     { "i2c-PRP0001:00", "0000:00:02.0", "Port B" },
0382     { "i2c-PRP0001:01", "0000:00:02.0", "Port C" },
0383     { },
0384 };
0385 
0386 static const struct dmi_system_id ch7322_dmi_table[] = {
0387     {
0388         .matches = {
0389             DMI_MATCH(DMI_BOARD_VENDOR, "Google"),
0390             DMI_MATCH(DMI_BOARD_NAME, "Endeavour"),
0391         },
0392         .driver_data = google_endeavour,
0393     },
0394     { },
0395 };
0396 
0397 /* Make a best-effort attempt to locate a matching HDMI port */
0398 static int ch7322_get_port(struct i2c_client *client,
0399                struct device **dev,
0400                const char **port)
0401 {
0402     const struct dmi_system_id *system;
0403     const struct ch7322_conn_match *conn;
0404 
0405     *dev = NULL;
0406     *port = NULL;
0407 
0408     system = dmi_first_match(ch7322_dmi_table);
0409     if (!system)
0410         return 0;
0411 
0412     for (conn = system->driver_data; conn->dev_name; conn++) {
0413         if (!strcmp(dev_name(&client->dev), conn->dev_name)) {
0414             struct device *d;
0415 
0416             d = bus_find_device_by_name(&pci_bus_type, NULL,
0417                             conn->pci_name);
0418             if (!d)
0419                 return -EPROBE_DEFER;
0420 
0421             put_device(d);
0422 
0423             *dev = d;
0424             *port = conn->port_name;
0425 
0426             return 0;
0427         }
0428     }
0429 
0430     return 0;
0431 }
0432 
0433 #else
0434 
0435 static int ch7322_get_port(struct i2c_client *client,
0436                struct device **dev,
0437                const char **port)
0438 {
0439     *dev = NULL;
0440     *port = NULL;
0441 
0442     return 0;
0443 }
0444 
0445 #endif
0446 
0447 static int ch7322_probe(struct i2c_client *client)
0448 {
0449     struct device *hdmi_dev;
0450     const char *port_name;
0451     struct ch7322 *ch7322;
0452     struct cec_notifier *notifier = NULL;
0453     u32 caps = CEC_CAP_DEFAULTS;
0454     int ret;
0455     unsigned int val;
0456 
0457     ret = ch7322_get_port(client, &hdmi_dev, &port_name);
0458     if (ret)
0459         return ret;
0460 
0461     if (hdmi_dev)
0462         caps |= CEC_CAP_CONNECTOR_INFO;
0463 
0464     ch7322 = devm_kzalloc(&client->dev, sizeof(*ch7322), GFP_KERNEL);
0465     if (!ch7322)
0466         return -ENOMEM;
0467 
0468     ch7322->regmap = devm_regmap_init_i2c(client, &ch7322_regmap);
0469     if (IS_ERR(ch7322->regmap))
0470         return PTR_ERR(ch7322->regmap);
0471 
0472     ret = regmap_read(ch7322->regmap, CH7322_DID, &val);
0473     if (ret)
0474         return ret;
0475 
0476     if (val != CH7322_DID_CH7322)
0477         return -EOPNOTSUPP;
0478 
0479     mutex_init(&ch7322->mutex);
0480     ch7322->i2c = client;
0481     ch7322->tx_flags = 0;
0482 
0483     i2c_set_clientdata(client, ch7322);
0484 
0485     /* Disable auto mode */
0486     ret = regmap_write(ch7322->regmap, CH7322_MODE, CH7322_MODE_SW);
0487     if (ret)
0488         goto err_mutex;
0489 
0490     /* Enable logical address register */
0491     ret = regmap_update_bits(ch7322->regmap, CH7322_CTL,
0492                  CH7322_CTL_SPADL, CH7322_CTL_SPADL);
0493     if (ret)
0494         goto err_mutex;
0495 
0496     ch7322->cec = cec_allocate_adapter(&ch7322_cec_adap_ops, ch7322,
0497                        dev_name(&client->dev),
0498                        caps, 1);
0499 
0500     if (IS_ERR(ch7322->cec)) {
0501         ret = PTR_ERR(ch7322->cec);
0502         goto err_mutex;
0503     }
0504 
0505     ch7322->cec->adap_controls_phys_addr = true;
0506 
0507     if (hdmi_dev) {
0508         notifier = cec_notifier_cec_adap_register(hdmi_dev,
0509                               port_name,
0510                               ch7322->cec);
0511         if (!notifier) {
0512             ret = -ENOMEM;
0513             goto err_cec;
0514         }
0515     }
0516 
0517     /* Configure, mask, and clear interrupt */
0518     ret = regmap_write(ch7322->regmap, CH7322_CFG1, 0);
0519     if (ret)
0520         goto err_notifier;
0521     ret = regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
0522     if (ret)
0523         goto err_notifier;
0524     ret = regmap_write(ch7322->regmap, CH7322_INTDATA, 0xff);
0525     if (ret)
0526         goto err_notifier;
0527 
0528     /* If HPD is up read physical address */
0529     ret = regmap_read(ch7322->regmap, CH7322_ADDLR, &val);
0530     if (ret)
0531         goto err_notifier;
0532     if (val & CH7322_ADDLR_HPD)
0533         ch7322_phys_addr(ch7322);
0534 
0535     ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
0536                     ch7322_irq,
0537                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
0538                     client->name, ch7322);
0539     if (ret)
0540         goto err_notifier;
0541 
0542     /* Unmask interrupt */
0543     mutex_lock(&ch7322->mutex);
0544     ret = regmap_write(ch7322->regmap, CH7322_INTCTL, 0xff);
0545     mutex_unlock(&ch7322->mutex);
0546 
0547     if (ret)
0548         goto err_notifier;
0549 
0550     ret = cec_register_adapter(ch7322->cec, &client->dev);
0551     if (ret)
0552         goto err_notifier;
0553 
0554     dev_info(&client->dev, "device registered\n");
0555 
0556     return 0;
0557 
0558 err_notifier:
0559     if (notifier)
0560         cec_notifier_cec_adap_unregister(notifier, ch7322->cec);
0561 err_cec:
0562     cec_delete_adapter(ch7322->cec);
0563 err_mutex:
0564     mutex_destroy(&ch7322->mutex);
0565     return ret;
0566 }
0567 
0568 static int ch7322_remove(struct i2c_client *client)
0569 {
0570     struct ch7322 *ch7322 = i2c_get_clientdata(client);
0571 
0572     /* Mask interrupt */
0573     mutex_lock(&ch7322->mutex);
0574     regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB);
0575     mutex_unlock(&ch7322->mutex);
0576 
0577     cec_unregister_adapter(ch7322->cec);
0578     mutex_destroy(&ch7322->mutex);
0579 
0580     dev_info(&client->dev, "device unregistered\n");
0581 
0582     return 0;
0583 }
0584 
0585 static const struct of_device_id ch7322_of_match[] = {
0586     { .compatible = "chrontel,ch7322", },
0587     {},
0588 };
0589 MODULE_DEVICE_TABLE(of, ch7322_of_match);
0590 
0591 static struct i2c_driver ch7322_i2c_driver = {
0592     .driver = {
0593         .name = "ch7322",
0594         .of_match_table = of_match_ptr(ch7322_of_match),
0595     },
0596     .probe_new  = ch7322_probe,
0597     .remove     = ch7322_remove,
0598 };
0599 
0600 module_i2c_driver(ch7322_i2c_driver);
0601 
0602 MODULE_DESCRIPTION("Chrontel CH7322 CEC Controller Driver");
0603 MODULE_AUTHOR("Jeff Chase <jnchase@google.com>");
0604 MODULE_LICENSE("GPL");