18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Driver for the Conexant CX23885/7/8 PCIe bridge
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Infrared device support routines - non-input, non-vl42_subdev routines
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "cx23885.h"
118c2ecf20Sopenharmony_ci#include "cx23885-ir.h"
128c2ecf20Sopenharmony_ci#include "cx23885-input.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define CX23885_IR_RX_FIFO_SERVICE_REQ		0
178c2ecf20Sopenharmony_ci#define CX23885_IR_RX_END_OF_RX_DETECTED	1
188c2ecf20Sopenharmony_ci#define CX23885_IR_RX_HW_FIFO_OVERRUN		2
198c2ecf20Sopenharmony_ci#define CX23885_IR_RX_SW_FIFO_OVERRUN		3
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define CX23885_IR_TX_FIFO_SERVICE_REQ		0
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_civoid cx23885_ir_rx_work_handler(struct work_struct *work)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct cx23885_dev *dev =
278c2ecf20Sopenharmony_ci			     container_of(work, struct cx23885_dev, ir_rx_work);
288c2ecf20Sopenharmony_ci	u32 events = 0;
298c2ecf20Sopenharmony_ci	unsigned long *notifications = &dev->ir_rx_notifications;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications))
328c2ecf20Sopenharmony_ci		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
338c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications))
348c2ecf20Sopenharmony_ci		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
358c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications))
368c2ecf20Sopenharmony_ci		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
378c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications))
388c2ecf20Sopenharmony_ci		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (events == 0)
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (dev->kernel_ir)
448c2ecf20Sopenharmony_ci		cx23885_input_rx_work_handler(dev, events);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_civoid cx23885_ir_tx_work_handler(struct work_struct *work)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct cx23885_dev *dev =
508c2ecf20Sopenharmony_ci			     container_of(work, struct cx23885_dev, ir_tx_work);
518c2ecf20Sopenharmony_ci	u32 events = 0;
528c2ecf20Sopenharmony_ci	unsigned long *notifications = &dev->ir_tx_notifications;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications))
558c2ecf20Sopenharmony_ci		events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (events == 0)
588c2ecf20Sopenharmony_ci		return;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Possibly called in an IRQ context */
638c2ecf20Sopenharmony_civoid cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
668c2ecf20Sopenharmony_ci	unsigned long *notifications = &dev->ir_rx_notifications;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ)
698c2ecf20Sopenharmony_ci		set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications);
708c2ecf20Sopenharmony_ci	if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED)
718c2ecf20Sopenharmony_ci		set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications);
728c2ecf20Sopenharmony_ci	if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN)
738c2ecf20Sopenharmony_ci		set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
748c2ecf20Sopenharmony_ci	if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
758c2ecf20Sopenharmony_ci		set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/*
788c2ecf20Sopenharmony_ci	 * For the integrated AV core, we are already in a workqueue context.
798c2ecf20Sopenharmony_ci	 * For the CX23888 integrated IR, we are in an interrupt context.
808c2ecf20Sopenharmony_ci	 */
818c2ecf20Sopenharmony_ci	if (sd == dev->sd_cx25840)
828c2ecf20Sopenharmony_ci		cx23885_ir_rx_work_handler(&dev->ir_rx_work);
838c2ecf20Sopenharmony_ci	else
848c2ecf20Sopenharmony_ci		schedule_work(&dev->ir_rx_work);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* Possibly called in an IRQ context */
888c2ecf20Sopenharmony_civoid cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
918c2ecf20Sopenharmony_ci	unsigned long *notifications = &dev->ir_tx_notifications;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
948c2ecf20Sopenharmony_ci		set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * For the integrated AV core, we are already in a workqueue context.
988c2ecf20Sopenharmony_ci	 * For the CX23888 integrated IR, we are in an interrupt context.
998c2ecf20Sopenharmony_ci	 */
1008c2ecf20Sopenharmony_ci	if (sd == dev->sd_cx25840)
1018c2ecf20Sopenharmony_ci		cx23885_ir_tx_work_handler(&dev->ir_tx_work);
1028c2ecf20Sopenharmony_ci	else
1038c2ecf20Sopenharmony_ci		schedule_work(&dev->ir_tx_work);
1048c2ecf20Sopenharmony_ci}
105