diff --git a/drivers/misc/tegra-cec/tegra_cec.c b/drivers/misc/tegra-cec/tegra_cec.c index eaf68014..affe3cde 100644 --- a/drivers/misc/tegra-cec/tegra_cec.c +++ b/drivers/misc/tegra-cec/tegra_cec.c @@ -325,9 +325,49 @@ out: return IRQ_HANDLED; } +static int tegra_cec_dump_registers(struct tegra_cec *cec) +{ + int value, i; + + dev_info(cec->dev, "base address = %llx\n", (u64)cec->cec_base); + for(i = 0; i <= TEGRA_CEC_HW_SPARE; i+=4) + { + value = readl(cec->cec_base + i); + dev_info(cec->dev, "offset %08x: %08x\n", i, value); + } + return i; + +} + +static int tegra_cec_set_rx_snoop(struct tegra_cec *cec, u32 enable) +{ + u32 state; + + if (!atomic_read(&cec->init_done)) + return -EAGAIN; + state = readl(cec->cec_base + TEGRA_CEC_HW_CONTROL); + if (((state & TEGRA_CEC_HWCTRL_RX_SNOOP) != 0) ^ (enable != 0)) { + state ^= TEGRA_CEC_HWCTRL_RX_SNOOP; + writel(state, cec->cec_base + TEGRA_CEC_HW_CONTROL); + } + return 0; +} + +static int tegra_cec_get_rx_snoop(struct tegra_cec *cec, u32 *state) +{ + if (!atomic_read(&cec->init_done)) + return -EAGAIN; + *state = (readl(cec->cec_base + TEGRA_CEC_HW_CONTROL) & TEGRA_CEC_HWCTRL_RX_SNOOP) >> 15; + return 0; +} + + static long tegra_cec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int err; + u32 state; + struct tegra_cec *cec = file->private_data; if (_IOC_TYPE(cmd) != TEGRA_CEC_IOC_MAGIC) @@ -339,6 +379,27 @@ static long tegra_cec_ioctl(struct file *file, unsigned int cmd, tegra_cec_error_recovery(cec); mutex_unlock(&cec->recovery_lock); break; + case TEGRA_CEC_IOCTL_DUMP_REGISTERS: + tegra_cec_dump_registers(cec); + break; + case TEGRA_CEC_IOCTL_SET_RX_SNOOP: + err = !access_ok(VERIFY_READ, arg, sizeof(u32)); + if (err) + return -EFAULT; + if (copy_from_user((u32 *) &state, (u32 *) arg, sizeof(u32))) + return -EFAULT; + tegra_cec_set_rx_snoop(cec, state); + break; + case TEGRA_CEC_IOCTL_GET_RX_SNOOP: + err = !access_ok(VERIFY_WRITE, arg, sizeof(u32)); + if (err) + return -EFAULT; + err = tegra_cec_get_rx_snoop(cec, &state); + if (!err) { + if (copy_to_user((u32 *) arg, &state, sizeof(u32))) + return -EFAULT; + } + break; default: dev_err(cec->dev, "unsupported ioctl\n"); return -EINVAL; diff --git a/drivers/misc/tegra-cec/tegra_cec.h b/drivers/misc/tegra-cec/tegra_cec.h index 34300d0f..70881a3d 100644 --- a/drivers/misc/tegra-cec/tegra_cec.h +++ b/drivers/misc/tegra-cec/tegra_cec.h @@ -77,6 +77,7 @@ static int tegra_cec_remove(struct platform_device *pdev); #define TEGRA_CEC_INT_MASK 0X034 #define TEGRA_CEC_HW_DEBUG_RX 0X038 #define TEGRA_CEC_HW_DEBUG_TX 0X03C +#define TEGRA_CEC_HW_SPARE 0X03C #define TEGRA_CEC_MAX_LOGICAL_ADDR 15 #define TEGRA_CEC_HWCTRL_RX_LADDR_UNREG 0x0 @@ -167,5 +168,8 @@ static int tegra_cec_remove(struct platform_device *pdev); #define TEGRA_CEC_IOC_MAGIC 'C' #define TEGRA_CEC_IOCTL_ERROR_RECOVERY _IO(TEGRA_CEC_IOC_MAGIC, 1) +#define TEGRA_CEC_IOCTL_DUMP_REGISTERS _IO(TEGRA_CEC_IOC_MAGIC, 2) +#define TEGRA_CEC_IOCTL_SET_RX_SNOOP _IO(TEGRA_CEC_IOC_MAGIC, 3) +#define TEGRA_CEC_IOCTL_GET_RX_SNOOP _IO(TEGRA_CEC_IOC_MAGIC, 4) #endif /* TEGRA_CEC_H */