[media] rc: nuvoton-cir: Add support wakeup via sysfs filter callback
Nuvoton-cir utilizes the encoding capabilities of rc-core to convert scancodes from user space to pulse/space format understood by the underlying hardware. Converted samples are then written to the wakeup fifo along with other necessary configuration to enable wake up functionality. Signed-off-by: Antti Seppälä <a.seppala@gmail.com> Signed-off-by: James Hogan <james@albanarts.com> Signed-off-by: Sean Young <sean@mess.org> Cc: Jarod Wilson <jarod@redhat.com> Cc: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
914535c059
commit
97c129747a
|
@ -171,6 +171,41 @@ static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nvt_write_wakeup_codes(struct rc_dev *dev,
|
||||||
|
const u8 *wbuf, int count)
|
||||||
|
{
|
||||||
|
u8 tolerance, config;
|
||||||
|
struct nvt_dev *nvt = dev->priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* hardcode the tolerance to 10% */
|
||||||
|
tolerance = DIV_ROUND_UP(count, 10);
|
||||||
|
|
||||||
|
spin_lock(&nvt->lock);
|
||||||
|
|
||||||
|
nvt_clear_cir_wake_fifo(nvt);
|
||||||
|
nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
|
||||||
|
nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
|
||||||
|
|
||||||
|
config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
|
||||||
|
|
||||||
|
/* enable writes to wake fifo */
|
||||||
|
nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
|
||||||
|
CIR_WAKE_IRCON);
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
pr_info("Wake samples (%d) =", count);
|
||||||
|
else
|
||||||
|
pr_info("Wake sample fifo cleared");
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
nvt_cir_wake_reg_write(nvt, wbuf[i], CIR_WAKE_WR_FIFO_DATA);
|
||||||
|
|
||||||
|
nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
|
||||||
|
|
||||||
|
spin_unlock(&nvt->lock);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t wakeup_data_show(struct device *dev,
|
static ssize_t wakeup_data_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
|
@ -209,9 +244,7 @@ static ssize_t wakeup_data_store(struct device *dev,
|
||||||
const char *buf, size_t len)
|
const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct rc_dev *rc_dev = to_rc_dev(dev);
|
struct rc_dev *rc_dev = to_rc_dev(dev);
|
||||||
struct nvt_dev *nvt = rc_dev->priv;
|
u8 wake_buf[WAKEUP_MAX_SIZE];
|
||||||
unsigned long flags;
|
|
||||||
u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE];
|
|
||||||
char **argv;
|
char **argv;
|
||||||
int i, count;
|
int i, count;
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
|
@ -240,27 +273,7 @@ static ssize_t wakeup_data_store(struct device *dev,
|
||||||
wake_buf[i] |= BUF_PULSE_BIT;
|
wake_buf[i] |= BUF_PULSE_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hardcode the tolerance to 10% */
|
nvt_write_wakeup_codes(rc_dev, wake_buf, count);
|
||||||
tolerance = DIV_ROUND_UP(count, 10);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&nvt->lock, flags);
|
|
||||||
|
|
||||||
nvt_clear_cir_wake_fifo(nvt);
|
|
||||||
nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
|
|
||||||
nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
|
|
||||||
|
|
||||||
config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
|
|
||||||
|
|
||||||
/* enable writes to wake fifo */
|
|
||||||
nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
|
|
||||||
CIR_WAKE_IRCON);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA);
|
|
||||||
|
|
||||||
nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&nvt->lock, flags);
|
|
||||||
|
|
||||||
ret = len;
|
ret = len;
|
||||||
out:
|
out:
|
||||||
|
@ -657,6 +670,62 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
|
||||||
|
struct rc_scancode_filter *sc_filter)
|
||||||
|
{
|
||||||
|
u8 buf_val;
|
||||||
|
int i, ret, count;
|
||||||
|
unsigned int val;
|
||||||
|
struct ir_raw_event *raw;
|
||||||
|
u8 wake_buf[WAKEUP_MAX_SIZE];
|
||||||
|
bool complete;
|
||||||
|
|
||||||
|
/* Require mask to be set */
|
||||||
|
if (!sc_filter->mask)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw = kmalloc_array(WAKEUP_MAX_SIZE, sizeof(*raw), GFP_KERNEL);
|
||||||
|
if (!raw)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc_filter->data,
|
||||||
|
raw, WAKEUP_MAX_SIZE);
|
||||||
|
complete = (ret != -ENOBUFS);
|
||||||
|
if (!complete)
|
||||||
|
ret = WAKEUP_MAX_SIZE;
|
||||||
|
else if (ret < 0)
|
||||||
|
goto out_raw;
|
||||||
|
|
||||||
|
/* Inspect the ir samples */
|
||||||
|
for (i = 0, count = 0; i < ret && count < WAKEUP_MAX_SIZE; ++i) {
|
||||||
|
/* NS to US */
|
||||||
|
val = DIV_ROUND_UP(raw[i].duration, 1000L) / SAMPLE_PERIOD;
|
||||||
|
|
||||||
|
/* Split too large values into several smaller ones */
|
||||||
|
while (val > 0 && count < WAKEUP_MAX_SIZE) {
|
||||||
|
/* Skip last value for better comparison tolerance */
|
||||||
|
if (complete && i == ret - 1 && val < BUF_LEN_MASK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Clamp values to BUF_LEN_MASK at most */
|
||||||
|
buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
|
||||||
|
|
||||||
|
wake_buf[count] = buf_val;
|
||||||
|
val -= buf_val;
|
||||||
|
if ((raw[i]).pulse)
|
||||||
|
wake_buf[count] |= BUF_PULSE_BIT;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nvt_write_wakeup_codes(dev, wake_buf, count);
|
||||||
|
ret = 0;
|
||||||
|
out_raw:
|
||||||
|
kfree(raw);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nvt_tx_ir
|
* nvt_tx_ir
|
||||||
*
|
*
|
||||||
|
@ -1058,10 +1127,13 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
|
||||||
rdev->priv = nvt;
|
rdev->priv = nvt;
|
||||||
rdev->driver_type = RC_DRIVER_IR_RAW;
|
rdev->driver_type = RC_DRIVER_IR_RAW;
|
||||||
rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
|
rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
|
||||||
|
rdev->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER;
|
||||||
|
rdev->encode_wakeup = true;
|
||||||
rdev->open = nvt_open;
|
rdev->open = nvt_open;
|
||||||
rdev->close = nvt_close;
|
rdev->close = nvt_close;
|
||||||
rdev->tx_ir = nvt_tx_ir;
|
rdev->tx_ir = nvt_tx_ir;
|
||||||
rdev->s_tx_carrier = nvt_set_tx_carrier;
|
rdev->s_tx_carrier = nvt_set_tx_carrier;
|
||||||
|
rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
|
||||||
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
|
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
|
||||||
rdev->input_phys = "nuvoton/cir0";
|
rdev->input_phys = "nuvoton/cir0";
|
||||||
rdev->input_id.bustype = BUS_HOST;
|
rdev->input_id.bustype = BUS_HOST;
|
||||||
|
|
Loading…
Reference in New Issue