Skip to content

Commit

Permalink
media: seco-cec: add Consumer-IR support
Browse files Browse the repository at this point in the history
Introduce support for Consumer-IR into seco-cec driver, as it shares the
same interrupt for receiving messages.
The device decodes RC5 signals only, defaults to hauppauge mapping.
It will spawn an input interface using the RC framework (like CEC
device).

Signed-off-by: Ettore Chimenti <ek5.chimenti@gmail.com>
Reviewed-by: Sean Young <sean@mess.org>
Signed-off-by: Hans Verkuil <hansverk@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
  • Loading branch information
Ettore Chimenti authored and Mauro Carvalho Chehab committed Nov 22, 2018
1 parent b03c2fb commit daef957
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 1 deletion.
10 changes: 10 additions & 0 deletions drivers/media/platform/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,16 @@ config VIDEO_SECO_CEC
CEC bus is present in the HDMI connector and enables communication
between compatible devices.

config VIDEO_SECO_RC
bool "SECO Boards IR RC5 support"
depends on VIDEO_SECO_CEC
select RC_CORE
help
If you say yes here you will get support for the
SECO Boards Consumer-IR in seco-cec driver.
The embedded controller supports RC5 protocol only, default mapping
is set to rc-hauppauge.

endif #CEC_PLATFORM_DRIVERS

menuconfig SDR_PLATFORM_DRIVERS
Expand Down
125 changes: 124 additions & 1 deletion drivers/media/platform/seco-cec/seco-cec.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct secocec_data {
struct platform_device *pdev;
struct cec_adapter *cec_adap;
struct cec_notifier *notifier;
struct rc_dev *ir;
char ir_input_phys[32];
int irq;
};

Expand Down Expand Up @@ -340,6 +342,114 @@ struct cec_adap_ops secocec_cec_adap_ops = {
.adap_transmit = secocec_adap_transmit,
};

#ifdef CONFIG_VIDEO_SECO_RC
static int secocec_ir_probe(void *priv)
{
struct secocec_data *cec = priv;
struct device *dev = cec->dev;
int status;
u16 val;

/* Prepare the RC input device */
cec->ir = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
if (!cec->ir)
return -ENOMEM;

snprintf(cec->ir_input_phys, sizeof(cec->ir_input_phys),
"%s/input0", dev_name(dev));

cec->ir->device_name = dev_name(dev);
cec->ir->input_phys = cec->ir_input_phys;
cec->ir->input_id.bustype = BUS_HOST;
cec->ir->input_id.vendor = 0;
cec->ir->input_id.product = 0;
cec->ir->input_id.version = 1;
cec->ir->driver_name = SECOCEC_DEV_NAME;
cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
cec->ir->priv = cec;
cec->ir->map_name = RC_MAP_HAUPPAUGE;
cec->ir->timeout = MS_TO_NS(100);

/* Clear the status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
if (status != 0)
goto err;

status = smb_wr16(SECOCEC_STATUS_REG_1, val);
if (status != 0)
goto err;

/* Enable the interrupts */
status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
if (status != 0)
goto err;

status = smb_wr16(SECOCEC_ENABLE_REG_1,
val | SECOCEC_ENABLE_REG_1_IR);
if (status != 0)
goto err;

dev_dbg(dev, "IR enabled");

status = devm_rc_register_device(dev, cec->ir);

if (status) {
dev_err(dev, "Failed to prepare input device");
cec->ir = NULL;
goto err;
}

return 0;

err:
smb_rd16(SECOCEC_ENABLE_REG_1, &val);

smb_wr16(SECOCEC_ENABLE_REG_1,
val & ~SECOCEC_ENABLE_REG_1_IR);

dev_dbg(dev, "IR disabled");
return status;
}

static int secocec_ir_rx(struct secocec_data *priv)
{
struct secocec_data *cec = priv;
struct device *dev = cec->dev;
u16 val, status, key, addr, toggle;

if (!cec->ir)
return -ENODEV;

status = smb_rd16(SECOCEC_IR_READ_DATA, &val);
if (status != 0)
goto err;

key = val & SECOCEC_IR_COMMAND_MASK;
addr = (val & SECOCEC_IR_ADDRESS_MASK) >> SECOCEC_IR_ADDRESS_SHL;
toggle = (val & SECOCEC_IR_TOGGLE_MASK) >> SECOCEC_IR_TOGGLE_SHL;

rc_keydown(cec->ir, RC_PROTO_RC5, RC_SCANCODE_RC5(addr, key), toggle);

dev_dbg(dev, "IR key pressed: 0x%02x addr 0x%02x toggle 0x%02x", key,
addr, toggle);

return 0;

err:
dev_err(dev, "IR Receive message failed (%d)", status);
return -EIO;
}
#else
static void secocec_ir_rx(struct secocec_data *priv)
{
}

static int secocec_ir_probe(void *priv)
{
return 0;
}
#endif

static irqreturn_t secocec_irq_handler(int irq, void *priv)
{
struct secocec_data *cec = priv;
Expand Down Expand Up @@ -374,7 +484,8 @@ static irqreturn_t secocec_irq_handler(int irq, void *priv)

if (status_val & SECOCEC_STATUS_REG_1_IR) {
val |= SECOCEC_STATUS_REG_1_IR;
/* TODO IRDA RX */

secocec_ir_rx(cec);
}

/* Reset status register */
Expand Down Expand Up @@ -542,6 +653,10 @@ static int secocec_probe(struct platform_device *pdev)
if (secocec->notifier)
cec_register_cec_notifier(secocec->cec_adap, secocec->notifier);

ret = secocec_ir_probe(secocec);
if (ret)
goto err_delete_adapter;

platform_set_drvdata(pdev, secocec);

dev_dbg(dev, "Device registered");
Expand All @@ -559,7 +674,15 @@ static int secocec_probe(struct platform_device *pdev)
static int secocec_remove(struct platform_device *pdev)
{
struct secocec_data *secocec = platform_get_drvdata(pdev);
u16 val;

if (secocec->ir) {
smb_rd16(SECOCEC_ENABLE_REG_1, &val);

smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR);

dev_dbg(&pdev->dev, "IR disabled");
}
cec_unregister_adapter(secocec->cec_adap);

if (secocec->notifier)
Expand Down
11 changes: 11 additions & 0 deletions drivers/media/platform/seco-cec/seco-cec.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@

#define SECOCEC_IR_READ_DATA 0x3e

/*
* IR
*/

#define SECOCEC_IR_COMMAND_MASK 0x007F
#define SECOCEC_IR_COMMAND_SHL 0
#define SECOCEC_IR_ADDRESS_MASK 0x1F00
#define SECOCEC_IR_ADDRESS_SHL 7
#define SECOCEC_IR_TOGGLE_MASK 0x8000
#define SECOCEC_IR_TOGGLE_SHL 15

/*
* Enabling register
*/
Expand Down

0 comments on commit daef957

Please sign in to comment.