media: vivid: add CEC pin monitoring emulation
[sfrench/cifs-2.6.git] / drivers / media / platform / vivid / vivid-cec.c
index e157057589698d698370df824b88bb5ffe1f9c0e..b55d278d38a7720fb073aa1b6f2820adbcadb50d 100644 (file)
 #include "vivid-core.h"
 #include "vivid-cec.h"
 
+#define CEC_TIM_START_BIT_TOTAL                4500
+#define CEC_TIM_START_BIT_LOW          3700
+#define CEC_TIM_START_BIT_HIGH         800
+#define CEC_TIM_DATA_BIT_TOTAL         2400
+#define CEC_TIM_DATA_BIT_0_LOW         1500
+#define CEC_TIM_DATA_BIT_0_HIGH                900
+#define CEC_TIM_DATA_BIT_1_LOW         600
+#define CEC_TIM_DATA_BIT_1_HIGH                1800
+
 void vivid_cec_bus_free_work(struct vivid_dev *dev)
 {
        spin_lock(&dev->cec_slock);
@@ -64,6 +73,58 @@ static bool vivid_cec_find_dest_adap(struct vivid_dev *dev,
        return false;
 }
 
+static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts,
+                                     const struct cec_msg *msg, bool nacked)
+{
+       unsigned int len = nacked ? 1 : msg->len;
+       unsigned int i;
+       bool bit;
+
+       if (adap == NULL)
+               return;
+       ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL +
+                              len * 10 * CEC_TIM_DATA_BIT_TOTAL));
+       cec_queue_pin_cec_event(adap, false, ts);
+       ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW);
+       cec_queue_pin_cec_event(adap, true, ts);
+       ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH);
+
+       for (i = 0; i < 10 * len; i++) {
+               switch (i % 10) {
+               case 0 ... 7:
+                       bit = msg->msg[i / 10] & (0x80 >> (i % 10));
+                       break;
+               case 8: /* EOM */
+                       bit = i / 10 == msg->len - 1;
+                       break;
+               case 9: /* ACK */
+                       bit = cec_msg_is_broadcast(msg) ^ nacked;
+                       break;
+               }
+               cec_queue_pin_cec_event(adap, false, ts);
+               if (bit)
+                       ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW);
+               else
+                       ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW);
+               cec_queue_pin_cec_event(adap, true, ts);
+               if (bit)
+                       ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH);
+               else
+                       ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH);
+       }
+}
+
+static void vivid_cec_pin_events(struct vivid_dev *dev,
+                                const struct cec_msg *msg, bool nacked)
+{
+       ktime_t ts = ktime_get();
+       unsigned int i;
+
+       vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked);
+       for (i = 0; i < MAX_OUTPUTS; i++)
+               vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked);
+}
+
 static void vivid_cec_xfer_done_worker(struct work_struct *work)
 {
        struct vivid_cec_work *cw =
@@ -84,6 +145,7 @@ static void vivid_cec_xfer_done_worker(struct work_struct *work)
        dev->cec_xfer_start_jiffies = 0;
        list_del(&cw->list);
        spin_unlock(&dev->cec_slock);
+       vivid_cec_pin_events(dev, &cw->msg, !valid_dest);
        cec_transmit_attempt_done(cw->adap, cw->tx_status);
 
        /* Broadcast message */
@@ -118,6 +180,7 @@ static void vivid_cec_xfer_try_worker(struct work_struct *work)
 
 static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
+       adap->cec_pin_is_high = true;
        return 0;
 }
 
@@ -219,8 +282,7 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
                                         bool is_source)
 {
        char name[sizeof(dev->vid_out_dev.name) + 2];
-       u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |
-               CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL;
+       u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
 
        snprintf(name, sizeof(name), "%s%d",
                 is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name,