mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 13:23:02 -04:00
Merge branch 'for-7.3/intel-thc-hid' into for-linus
- support for full I2C bus config parameters (Even Xu)
This commit is contained in:
@@ -175,7 +175,9 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
|
||||
if (i2c_param.addressing_mode != HIDI2C_ADDRESSING_MODE_7BIT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
qcdev->i2c_slave_addr = i2c_param.device_address;
|
||||
qcdev->i2c_config.addr_mode = HIDI2C_ADDRESSING_MODE_7BIT;
|
||||
|
||||
qcdev->i2c_config.target_addr = i2c_param.device_address;
|
||||
|
||||
ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ISUB,
|
||||
ACPI_TYPE_BUFFER, &i2c_config);
|
||||
@@ -184,24 +186,32 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
|
||||
|
||||
if (i2c_param.connection_speed > 0 &&
|
||||
i2c_param.connection_speed <= QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED) {
|
||||
qcdev->i2c_speed_mode = THC_I2C_STANDARD;
|
||||
qcdev->i2c_clock_hcnt = i2c_config.SMHX;
|
||||
qcdev->i2c_clock_lcnt = i2c_config.SMLX;
|
||||
qcdev->i2c_config.speed = THC_I2C_STANDARD;
|
||||
qcdev->i2c_config.scl_hcnt = (u32)i2c_config.SMHX;
|
||||
qcdev->i2c_config.scl_lcnt = (u32)i2c_config.SMLX;
|
||||
qcdev->i2c_config.sda_tx_hold = (u32)i2c_config.SMTD;
|
||||
qcdev->i2c_config.sda_rx_hold = (u32)i2c_config.SMRD;
|
||||
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED &&
|
||||
i2c_param.connection_speed <= QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED) {
|
||||
qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS;
|
||||
qcdev->i2c_clock_hcnt = i2c_config.FMHX;
|
||||
qcdev->i2c_clock_lcnt = i2c_config.FMLX;
|
||||
qcdev->i2c_config.speed = THC_I2C_FAST_AND_PLUS;
|
||||
qcdev->i2c_config.scl_hcnt = (u32)i2c_config.FMHX;
|
||||
qcdev->i2c_config.scl_lcnt = (u32)i2c_config.FMLX;
|
||||
qcdev->i2c_config.sda_tx_hold = (u32)i2c_config.FMTD;
|
||||
qcdev->i2c_config.sda_rx_hold = (u32)i2c_config.FMRD;
|
||||
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED &&
|
||||
i2c_param.connection_speed <= QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED) {
|
||||
qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS;
|
||||
qcdev->i2c_clock_hcnt = i2c_config.FPHX;
|
||||
qcdev->i2c_clock_lcnt = i2c_config.FPLX;
|
||||
qcdev->i2c_config.speed = THC_I2C_FAST_AND_PLUS;
|
||||
qcdev->i2c_config.scl_hcnt = (u32)i2c_config.FPHX;
|
||||
qcdev->i2c_config.scl_lcnt = (u32)i2c_config.FPLX;
|
||||
qcdev->i2c_config.sda_tx_hold = (u32)i2c_config.FPTD;
|
||||
qcdev->i2c_config.sda_rx_hold = (u32)i2c_config.FPRD;
|
||||
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED &&
|
||||
i2c_param.connection_speed <= QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED) {
|
||||
qcdev->i2c_speed_mode = THC_I2C_HIGH_SPEED;
|
||||
qcdev->i2c_clock_hcnt = i2c_config.HMHX;
|
||||
qcdev->i2c_clock_lcnt = i2c_config.HMLX;
|
||||
qcdev->i2c_config.speed = THC_I2C_HIGH_SPEED;
|
||||
qcdev->i2c_config.scl_hcnt = (u32)i2c_config.HMHX;
|
||||
qcdev->i2c_config.scl_lcnt = (u32)i2c_config.HMLX;
|
||||
qcdev->i2c_config.sda_tx_hold = (u32)i2c_config.HMTD;
|
||||
qcdev->i2c_config.sda_rx_hold = (u32)i2c_config.HMRD;
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -245,28 +255,33 @@ static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* try_recover - Try to recovery THC and Device
|
||||
* @qcdev: Pointer to quicki2c_device structure
|
||||
* try_recover - Recover callback to recover THC
|
||||
* @work: pointer to work_struct
|
||||
*
|
||||
* This function is an error handler, called when fatal error happens.
|
||||
* It try to reset touch device and re-configure THC to recovery
|
||||
* communication between touch device and THC.
|
||||
*
|
||||
* Return: 0 if successful or error code on failure
|
||||
* It try to reset Touch Device and re-configure THC to recover
|
||||
* transferring between Device and THC.
|
||||
*/
|
||||
static int try_recover(struct quicki2c_device *qcdev)
|
||||
static void try_recover(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct quicki2c_device *qcdev = container_of(work, struct quicki2c_device, recover_work);
|
||||
|
||||
thc_dma_unconfigure(qcdev->thc_hw);
|
||||
if (READ_ONCE(qcdev->recovery_disabled))
|
||||
return;
|
||||
|
||||
ret = thc_dma_configure(qcdev->thc_hw);
|
||||
if (ret) {
|
||||
dev_err(qcdev->dev, "Reconfig DMA failed\n");
|
||||
return ret;
|
||||
if (pm_runtime_resume_and_get(qcdev->dev))
|
||||
return;
|
||||
|
||||
thc_interrupt_enable(qcdev->thc_hw, false);
|
||||
|
||||
if (thc_rxdma_reset(qcdev->thc_hw)) {
|
||||
qcdev->state = QUICKI2C_DISABLED;
|
||||
dev_err(qcdev->dev, "RxDMA reset failed during recover, disable QuickI2C\n");
|
||||
} else {
|
||||
thc_interrupt_enable(qcdev->thc_hw, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
pm_runtime_put_autosuspend(qcdev->dev);
|
||||
}
|
||||
|
||||
static int handle_input_report(struct quicki2c_device *qcdev)
|
||||
@@ -343,11 +358,10 @@ static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
exit:
|
||||
thc_interrupt_enable(qcdev->thc_hw, true);
|
||||
|
||||
if (err_recover)
|
||||
if (try_recover(qcdev))
|
||||
qcdev->state = QUICKI2C_DISABLED;
|
||||
schedule_work(&qcdev->recover_work);
|
||||
else
|
||||
thc_interrupt_enable(qcdev->thc_hw, true);
|
||||
|
||||
pm_runtime_put_autosuspend(qcdev->dev);
|
||||
|
||||
@@ -386,6 +400,8 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
|
||||
qcdev->ddata = ddata;
|
||||
|
||||
init_waitqueue_head(&qcdev->reset_ack_wq);
|
||||
WRITE_ONCE(qcdev->recovery_disabled, false);
|
||||
INIT_WORK(&qcdev->recover_work, try_recover);
|
||||
|
||||
/* THC hardware init */
|
||||
qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr);
|
||||
@@ -411,10 +427,7 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = thc_i2c_subip_init(qcdev->thc_hw, qcdev->i2c_slave_addr,
|
||||
qcdev->i2c_speed_mode,
|
||||
qcdev->i2c_clock_hcnt,
|
||||
qcdev->i2c_clock_lcnt);
|
||||
ret = thc_i2c_subip_init(qcdev->thc_hw, &qcdev->i2c_config);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@@ -439,6 +452,9 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
|
||||
*/
|
||||
static void quicki2c_dev_deinit(struct quicki2c_device *qcdev)
|
||||
{
|
||||
WRITE_ONCE(qcdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qcdev->recover_work);
|
||||
|
||||
thc_interrupt_quiesce(qcdev->thc_hw, true);
|
||||
thc_interrupt_enable(qcdev->thc_hw, false);
|
||||
thc_ltr_unconfig(qcdev->thc_hw);
|
||||
@@ -772,13 +788,14 @@ static void quicki2c_remove(struct pci_dev *pdev)
|
||||
return;
|
||||
|
||||
quicki2c_hid_remove(qcdev);
|
||||
|
||||
quicki2c_dev_deinit(qcdev);
|
||||
|
||||
quicki2c_dma_deinit(qcdev);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(qcdev->dev);
|
||||
pm_runtime_get_noresume(qcdev->dev);
|
||||
|
||||
quicki2c_dev_deinit(qcdev);
|
||||
|
||||
pci_clear_master(pdev);
|
||||
}
|
||||
|
||||
@@ -797,10 +814,10 @@ static void quicki2c_shutdown(struct pci_dev *pdev)
|
||||
if (!qcdev)
|
||||
return;
|
||||
|
||||
quicki2c_dev_deinit(qcdev);
|
||||
|
||||
/* Must stop DMA before reboot to avoid DMA entering into unknown state */
|
||||
quicki2c_dma_deinit(qcdev);
|
||||
|
||||
quicki2c_dev_deinit(qcdev);
|
||||
}
|
||||
|
||||
static int quicki2c_suspend(struct device *device)
|
||||
@@ -827,6 +844,9 @@ static int quicki2c_suspend(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(qcdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qcdev->recover_work);
|
||||
|
||||
ret = thc_interrupt_quiesce(qcdev->thc_hw, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -868,6 +888,8 @@ static int quicki2c_resume(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(qcdev->recovery_disabled, false);
|
||||
|
||||
if (!device_may_wakeup(qcdev->dev))
|
||||
return quicki2c_set_power(qcdev, HIDI2C_ON);
|
||||
|
||||
@@ -884,6 +906,9 @@ static int quicki2c_freeze(struct device *device)
|
||||
if (!qcdev)
|
||||
return -ENODEV;
|
||||
|
||||
WRITE_ONCE(qcdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qcdev->recover_work);
|
||||
|
||||
ret = thc_interrupt_quiesce(qcdev->thc_hw, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -915,6 +940,8 @@ static int quicki2c_thaw(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(qcdev->recovery_disabled, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -939,6 +966,8 @@ static int quicki2c_poweroff(struct device *device)
|
||||
|
||||
thc_ltr_unconfig(qcdev->thc_hw);
|
||||
|
||||
quicki2c_dev_deinit(qcdev);
|
||||
|
||||
quicki2c_dma_deinit(qcdev);
|
||||
|
||||
return 0;
|
||||
@@ -959,10 +988,7 @@ static int quicki2c_restore(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = thc_i2c_subip_init(qcdev->thc_hw, qcdev->i2c_slave_addr,
|
||||
qcdev->i2c_speed_mode,
|
||||
qcdev->i2c_clock_hcnt,
|
||||
qcdev->i2c_clock_lcnt);
|
||||
ret = thc_i2c_subip_init(qcdev->thc_hw, &qcdev->i2c_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <linux/hid-over-i2c.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "intel-thc-dev.h"
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT1 0xA848
|
||||
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A
|
||||
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348
|
||||
@@ -159,7 +161,6 @@ struct quicki2c_ddata {
|
||||
|
||||
struct device;
|
||||
struct pci_dev;
|
||||
struct thc_device;
|
||||
struct hid_device;
|
||||
struct acpi_device;
|
||||
|
||||
@@ -174,13 +175,10 @@ struct acpi_device;
|
||||
* @state: THC I2C device state
|
||||
* @mem_addr: MMIO memory address
|
||||
* @dev_desc: Device descriptor for HIDI2C protocol
|
||||
* @i2c_slave_addr: HIDI2C device slave address
|
||||
* @i2c_config: I2C bus configuration
|
||||
* @hid_desc_addr: Register address for retrieve HID device descriptor
|
||||
* @active_ltr_val: THC active LTR value
|
||||
* @low_power_ltr_val: THC low power LTR value
|
||||
* @i2c_speed_mode: 0 - standard mode, 1 - fast mode, 2 - fast mode plus
|
||||
* @i2c_clock_hcnt: I2C CLK high period time (unit in cycle count)
|
||||
* @i2c_clock_lcnt: I2C CLK low period time (unit in cycle count)
|
||||
* @report_descriptor: Store a copy of device report descriptor
|
||||
* @input_buf: Store a copy of latest input report data
|
||||
* @report_buf: Store a copy of latest input/output report packet from set/get feature
|
||||
@@ -191,6 +189,8 @@ struct acpi_device;
|
||||
* @i2c_max_frame_size: Max RX frame size (unit in Bytes)
|
||||
* @i2c_int_delay_enable: Indicate interrupt delay feature enabled or not
|
||||
* @i2c_int_delay: Interrupt detection delay value (unit in 10 us)
|
||||
* @recover_work: Work structure for recovery
|
||||
* @recovery_disabled: Whether recovery work is blocked during teardown
|
||||
*/
|
||||
struct quicki2c_device {
|
||||
struct device *dev;
|
||||
@@ -204,16 +204,12 @@ struct quicki2c_device {
|
||||
void __iomem *mem_addr;
|
||||
|
||||
struct hidi2c_dev_descriptor dev_desc;
|
||||
u8 i2c_slave_addr;
|
||||
struct thc_i2c_config i2c_config;
|
||||
u16 hid_desc_addr;
|
||||
|
||||
u32 active_ltr_val;
|
||||
u32 low_power_ltr_val;
|
||||
|
||||
u32 i2c_speed_mode;
|
||||
u32 i2c_clock_hcnt;
|
||||
u32 i2c_clock_lcnt;
|
||||
|
||||
u8 *report_descriptor;
|
||||
u8 *input_buf;
|
||||
u8 *report_buf;
|
||||
@@ -226,6 +222,9 @@ struct quicki2c_device {
|
||||
u32 i2c_max_frame_size;
|
||||
u32 i2c_int_delay_enable;
|
||||
u32 i2c_int_delay;
|
||||
|
||||
struct work_struct recover_work;
|
||||
bool recovery_disabled;
|
||||
};
|
||||
|
||||
#endif /* _QUICKI2C_DEV_H_ */
|
||||
|
||||
@@ -252,34 +252,33 @@ static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* try_recover - Try to recovery THC and Device
|
||||
* @qsdev: pointer to quickspi device
|
||||
* try_recover - Recover callback to recover THC
|
||||
* @work: pointer to work_struct
|
||||
*
|
||||
* This function is a error handler, called when fatal error happens.
|
||||
* It try to reset Touch Device and re-configure THC to recovery
|
||||
* This function is an error handler, called when fatal error happens.
|
||||
* It try to reset Touch Device and re-configure THC to recover
|
||||
* transferring between Device and THC.
|
||||
*
|
||||
* Return: 0 if successful or error code on failed.
|
||||
*/
|
||||
static int try_recover(struct quickspi_device *qsdev)
|
||||
static void try_recover(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct quickspi_device *qsdev = container_of(work, struct quickspi_device, recover_work);
|
||||
|
||||
ret = reset_tic(qsdev);
|
||||
if (ret) {
|
||||
dev_err(qsdev->dev, "Reset touch device failed, ret = %d\n", ret);
|
||||
return ret;
|
||||
if (READ_ONCE(qsdev->recovery_disabled))
|
||||
return;
|
||||
|
||||
if (pm_runtime_resume_and_get(qsdev->dev))
|
||||
return;
|
||||
|
||||
thc_interrupt_enable(qsdev->thc_hw, false);
|
||||
|
||||
if (thc_rxdma_reset(qsdev->thc_hw)) {
|
||||
qsdev->state = QUICKSPI_DISABLED;
|
||||
dev_err(qsdev->dev, "RxDMA reset failed during recover, disable QuickSPI\n");
|
||||
} else {
|
||||
thc_interrupt_enable(qsdev->thc_hw, true);
|
||||
}
|
||||
|
||||
thc_dma_unconfigure(qsdev->thc_hw);
|
||||
|
||||
ret = thc_dma_configure(qsdev->thc_hw);
|
||||
if (ret) {
|
||||
dev_err(qsdev->dev, "Re-configure THC DMA failed, ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
pm_runtime_put_autosuspend(qsdev->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,11 +336,10 @@ static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
end:
|
||||
thc_interrupt_enable(qsdev->thc_hw, true);
|
||||
|
||||
if (err_recover)
|
||||
if (try_recover(qsdev))
|
||||
qsdev->state = QUICKSPI_DISABLED;
|
||||
schedule_work(&qsdev->recover_work);
|
||||
else
|
||||
thc_interrupt_enable(qsdev->thc_hw, true);
|
||||
|
||||
pm_runtime_put_autosuspend(qsdev->dev);
|
||||
|
||||
@@ -385,6 +383,8 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
|
||||
init_waitqueue_head(&qsdev->report_desc_got_wq);
|
||||
init_waitqueue_head(&qsdev->get_report_cmpl_wq);
|
||||
init_waitqueue_head(&qsdev->set_report_cmpl_wq);
|
||||
WRITE_ONCE(qsdev->recovery_disabled, false);
|
||||
INIT_WORK(&qsdev->recover_work, try_recover);
|
||||
|
||||
/* thc hw init */
|
||||
qsdev->thc_hw = thc_dev_init(qsdev->dev, qsdev->mem_addr);
|
||||
@@ -461,6 +461,10 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
|
||||
*/
|
||||
static void quickspi_dev_deinit(struct quickspi_device *qsdev)
|
||||
{
|
||||
WRITE_ONCE(qsdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qsdev->recover_work);
|
||||
|
||||
thc_interrupt_quiesce(qsdev->thc_hw, true);
|
||||
thc_interrupt_enable(qsdev->thc_hw, false);
|
||||
thc_ltr_unconfig(qsdev->thc_hw);
|
||||
thc_wot_unconfig(qsdev->thc_hw);
|
||||
@@ -718,13 +722,14 @@ static void quickspi_remove(struct pci_dev *pdev)
|
||||
return;
|
||||
|
||||
quickspi_hid_remove(qsdev);
|
||||
|
||||
quickspi_dev_deinit(qsdev);
|
||||
|
||||
quickspi_dma_deinit(qsdev);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(qsdev->dev);
|
||||
pm_runtime_get_noresume(qsdev->dev);
|
||||
|
||||
quickspi_dev_deinit(qsdev);
|
||||
|
||||
pci_clear_master(pdev);
|
||||
}
|
||||
|
||||
@@ -745,10 +750,10 @@ static void quickspi_shutdown(struct pci_dev *pdev)
|
||||
if (!qsdev)
|
||||
return;
|
||||
|
||||
quickspi_dev_deinit(qsdev);
|
||||
|
||||
/* Must stop DMA before reboot to avoid DMA entering into unknown state */
|
||||
quickspi_dma_deinit(qsdev);
|
||||
|
||||
quickspi_dev_deinit(qsdev);
|
||||
}
|
||||
|
||||
static int quickspi_suspend(struct device *device)
|
||||
@@ -767,6 +772,9 @@ static int quickspi_suspend(struct device *device)
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRITE_ONCE(qsdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qsdev->recover_work);
|
||||
|
||||
ret = thc_interrupt_quiesce(qsdev->thc_hw, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -792,6 +800,8 @@ static int quickspi_resume(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(qsdev->recovery_disabled, false);
|
||||
|
||||
/*
|
||||
* A wake-enabled device keeps its power and state across suspend, so
|
||||
* only restore the THC context. Resetting it here would discard a
|
||||
@@ -872,6 +882,9 @@ static int quickspi_freeze(struct device *device)
|
||||
if (!qsdev)
|
||||
return -ENODEV;
|
||||
|
||||
WRITE_ONCE(qsdev->recovery_disabled, true);
|
||||
cancel_work_sync(&qsdev->recover_work);
|
||||
|
||||
ret = thc_interrupt_quiesce(qsdev->thc_hw, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -903,6 +916,8 @@ static int quickspi_thaw(struct device *device)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(qsdev->recovery_disabled, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -927,6 +942,8 @@ static int quickspi_poweroff(struct device *device)
|
||||
|
||||
thc_ltr_unconfig(qsdev->thc_hw);
|
||||
|
||||
quickspi_dev_deinit(qsdev);
|
||||
|
||||
quickspi_dma_deinit(qsdev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/hid-over-spi.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "quickspi-protocol.h"
|
||||
|
||||
@@ -126,6 +127,8 @@ struct acpi_device;
|
||||
* @get_feature_cmpl: indicate get feature received or not
|
||||
* @set_feature_cmpl_wq: workqueue for waiting set feature to device
|
||||
* @set_feature_cmpl: indicate set feature send complete or not
|
||||
* @recover_work: Work structure for recovery
|
||||
* @recovery_disabled: Whether recovery work is blocked during teardown
|
||||
*/
|
||||
struct quickspi_device {
|
||||
struct device *dev;
|
||||
@@ -174,6 +177,9 @@ struct quickspi_device {
|
||||
|
||||
wait_queue_head_t set_report_cmpl_wq;
|
||||
bool set_report_cmpl;
|
||||
|
||||
struct work_struct recover_work;
|
||||
bool recovery_disabled;
|
||||
};
|
||||
|
||||
#endif /* _QUICKSPI_DEV_H_ */
|
||||
|
||||
@@ -61,7 +61,7 @@ static int quickspi_hid_raw_request(struct hid_device *hid,
|
||||
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
ret = quickspi_get_report(qsdev, rtype, reportnum, buf);
|
||||
ret = quickspi_get_report(qsdev, rtype, reportnum, buf, len);
|
||||
break;
|
||||
case HID_REQ_SET_REPORT:
|
||||
ret = quickspi_set_report(qsdev, rtype, reportnum, buf, len);
|
||||
|
||||
@@ -345,10 +345,12 @@ int reset_tic(struct quickspi_device *qsdev)
|
||||
}
|
||||
|
||||
int quickspi_get_report(struct quickspi_device *qsdev,
|
||||
u8 report_type, unsigned int report_id, void *buf)
|
||||
u8 report_type, unsigned int report_id, void *buf,
|
||||
u32 buf_len)
|
||||
{
|
||||
int rep_type;
|
||||
int ret;
|
||||
u32 report_len;
|
||||
|
||||
if (report_type == HID_INPUT_REPORT) {
|
||||
rep_type = GET_INPUT_REPORT;
|
||||
@@ -375,9 +377,17 @@ int quickspi_get_report(struct quickspi_device *qsdev,
|
||||
}
|
||||
qsdev->get_report_cmpl = false;
|
||||
|
||||
memcpy(buf, qsdev->report_buf, qsdev->report_len);
|
||||
/* quickspi_handle_input_data() updates this from IRQ context. */
|
||||
report_len = READ_ONCE(qsdev->report_len);
|
||||
if (report_len > buf_len) {
|
||||
dev_err_once(qsdev->dev, "Get report response too big, %u vs %u\n",
|
||||
report_len, buf_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return qsdev->report_len;
|
||||
memcpy(buf, qsdev->report_buf, report_len);
|
||||
|
||||
return report_len;
|
||||
}
|
||||
|
||||
int quickspi_set_report(struct quickspi_device *qsdev,
|
||||
|
||||
@@ -12,7 +12,7 @@ struct quickspi_device;
|
||||
|
||||
void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len);
|
||||
int quickspi_get_report(struct quickspi_device *qsdev, u8 report_type,
|
||||
unsigned int report_id, void *buf);
|
||||
unsigned int report_id, void *buf, u32 buf_len);
|
||||
int quickspi_set_report(struct quickspi_device *qsdev, u8 report_type,
|
||||
unsigned int report_id, void *buf, u32 buf_len);
|
||||
int quickspi_get_report_descriptor(struct quickspi_device *qsdev);
|
||||
|
||||
@@ -1422,14 +1422,25 @@ static int thc_i2c_subip_pio_write(struct thc_device *dev, const u32 address,
|
||||
#define I2C_SUBIP_DMA_TDLR_DEFAULT 7
|
||||
#define I2C_SUBIP_DMA_RDLR_DEFAULT 7
|
||||
|
||||
static int thc_i2c_subip_set_speed(struct thc_device *dev, const u32 speed,
|
||||
const u32 hcnt, const u32 lcnt)
|
||||
static int thc_i2c_subip_bus_config(struct thc_device *dev, const struct thc_i2c_config *i2c_config)
|
||||
{
|
||||
u32 hcnt_offset, lcnt_offset;
|
||||
u32 val;
|
||||
u32 read_size = sizeof(u32);
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
switch (speed) {
|
||||
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_TAR_OFFSET, &read_size, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val &= ~(THC_I2C_IC_TAR_IC_TAR | THC_I2C_IC_TAR_IC_10BITADDR_MASTER);
|
||||
val |= FIELD_PREP(THC_I2C_IC_TAR_IC_10BITADDR_MASTER, i2c_config->addr_mode);
|
||||
val |= FIELD_PREP(THC_I2C_IC_TAR_IC_TAR, i2c_config->target_addr);
|
||||
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_TAR_OFFSET, sizeof(u32), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (i2c_config->speed) {
|
||||
case THC_I2C_STANDARD:
|
||||
hcnt_offset = THC_I2C_IC_SS_SCL_HCNT_OFFSET;
|
||||
lcnt_offset = THC_I2C_IC_SS_SCL_LCNT_OFFSET;
|
||||
@@ -1446,25 +1457,43 @@ static int thc_i2c_subip_set_speed(struct thc_device *dev, const u32 speed,
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err_once(dev->dev, "Unsupported i2c speed %d\n", speed);
|
||||
dev_err_once(dev->dev, "Unsupported i2c speed %d\n", i2c_config->speed);
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = thc_i2c_subip_pio_write(dev, hcnt_offset, sizeof(u32), &hcnt);
|
||||
ret = thc_i2c_subip_pio_write(dev, hcnt_offset, sizeof(u32), &i2c_config->scl_hcnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = thc_i2c_subip_pio_write(dev, lcnt_offset, sizeof(u32), &lcnt);
|
||||
ret = thc_i2c_subip_pio_write(dev, lcnt_offset, sizeof(u32), &i2c_config->scl_lcnt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = I2C_SUBIP_CON_DEFAULT & ~THC_I2C_IC_CON_SPEED;
|
||||
val |= FIELD_PREP(THC_I2C_IC_CON_SPEED, speed);
|
||||
val |= FIELD_PREP(THC_I2C_IC_CON_SPEED, i2c_config->speed);
|
||||
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_CON_OFFSET, sizeof(u32), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_SDA_HOLD_OFFSET, &read_size, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (i2c_config->sda_tx_hold) {
|
||||
val &= ~THC_I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD;
|
||||
val |= FIELD_PREP(THC_I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD, i2c_config->sda_tx_hold);
|
||||
}
|
||||
|
||||
if (i2c_config->sda_rx_hold) {
|
||||
val &= ~THC_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD;
|
||||
val |= FIELD_PREP(THC_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD, i2c_config->sda_rx_hold);
|
||||
}
|
||||
|
||||
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_SDA_HOLD_OFFSET, sizeof(u32), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1474,6 +1503,7 @@ static u32 i2c_subip_regs[] = {
|
||||
THC_I2C_IC_INTR_MASK_OFFSET,
|
||||
THC_I2C_IC_RX_TL_OFFSET,
|
||||
THC_I2C_IC_TX_TL_OFFSET,
|
||||
THC_I2C_IC_SDA_HOLD_OFFSET,
|
||||
THC_I2C_IC_DMA_CR_OFFSET,
|
||||
THC_I2C_IC_DMA_TDLR_OFFSET,
|
||||
THC_I2C_IC_DMA_RDLR_OFFSET,
|
||||
@@ -1490,20 +1520,19 @@ static u32 i2c_subip_regs[] = {
|
||||
* thc_i2c_subip_init - Initialize and configure THC I2C subsystem
|
||||
*
|
||||
* @dev: The pointer of THC private device context
|
||||
* @target_address: Slave address of touch device (TIC)
|
||||
* @speed: I2C bus frequency speed mode
|
||||
* @hcnt: I2C clock SCL high count
|
||||
* @lcnt: I2C clock SCL low count
|
||||
* @i2c_config: The pointer of THC I2C bus configure structure
|
||||
*
|
||||
* Return: 0 on success, other error codes on failed.
|
||||
*/
|
||||
int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
|
||||
const u32 speed, const u32 hcnt, const u32 lcnt)
|
||||
int thc_i2c_subip_init(struct thc_device *dev, const struct thc_i2c_config *i2c_config)
|
||||
{
|
||||
u32 read_size = sizeof(u32);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!dev || !i2c_config)
|
||||
return -EINVAL;
|
||||
|
||||
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_ENABLE_OFFSET, &read_size, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -1513,17 +1542,7 @@ int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_TAR_OFFSET, &read_size, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val &= ~THC_I2C_IC_TAR_IC_TAR;
|
||||
val |= FIELD_PREP(THC_I2C_IC_TAR_IC_TAR, target_address);
|
||||
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_TAR_OFFSET, sizeof(u32), &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = thc_i2c_subip_set_speed(dev, speed, hcnt, lcnt);
|
||||
ret = thc_i2c_subip_bus_config(dev, i2c_config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -49,6 +49,26 @@ enum thc_int_type {
|
||||
THC_UNKNOWN_INT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thc_i2c_config - THC I2C bus configuration
|
||||
* @target_addr: Slave address of touch device (TIC)
|
||||
* @addr_mode: Slave address mode of touch device (TIC), 7bit or 10bit
|
||||
* @speed: I2C bus frequency speed mode
|
||||
* @scl_hcnt: I2C clock SCL high count
|
||||
* @scl_lcnt: I2C clock SCL low count
|
||||
* @sda_tx_hold: I2C Data SDA transmit hold period
|
||||
* @sda_rx_hold: I2C Data SDA receive hold period
|
||||
*/
|
||||
struct thc_i2c_config {
|
||||
u16 target_addr;
|
||||
u8 addr_mode;
|
||||
u32 speed;
|
||||
u32 scl_hcnt;
|
||||
u32 scl_lcnt;
|
||||
u32 sda_tx_hold;
|
||||
u32 sda_rx_hold;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thc_device - THC private device struct
|
||||
* @thc_regmap: MMIO regmap structure for accessing THC registers
|
||||
@@ -121,8 +141,7 @@ int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val,
|
||||
u32 io_mode, u32 opcode, u32 spi_wr_mps, u32 perf_limit);
|
||||
void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr,
|
||||
u32 input_bdy_addr, u32 output_addr);
|
||||
int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
|
||||
const u32 speed, const u32 hcnt, const u32 lcnt);
|
||||
int thc_i2c_subip_init(struct thc_device *dev, const struct thc_i2c_config *i2c_config);
|
||||
int thc_i2c_subip_regs_save(struct thc_device *dev);
|
||||
int thc_i2c_subip_regs_restore(struct thc_device *dev);
|
||||
int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size);
|
||||
|
||||
@@ -561,6 +561,57 @@ static int thc_wait_for_dma_pause(struct thc_device *dev, enum thc_dma_channel c
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* thc_rxdma_reset - Reset all read DMA engines
|
||||
*
|
||||
* @dev: The pointer of THC private device context
|
||||
*
|
||||
* This is a helper function to reset RxDMA configure. It's typically used
|
||||
* for RxDMA recovery when fatal error happens.
|
||||
*
|
||||
* Return: 0 if successful or error code on failure.
|
||||
*/
|
||||
int thc_rxdma_reset(struct thc_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&dev->thc_bus_lock))
|
||||
return -EINTR;
|
||||
|
||||
ret = thc_interrupt_quiesce(dev, true);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "Quiesce interrupt failed during RxDMA reset\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = thc_wait_for_dma_pause(dev, THC_RXDMA1);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "Wait for RxDMA1 pause failed during RxDMA reset\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = thc_wait_for_dma_pause(dev, THC_RXDMA2);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "Wait for RxDMA2 pause failed during RxDMA reset\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
thc_dma_unconfigure(dev);
|
||||
|
||||
ret = thc_dma_configure(dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "Re-config DMA failed during RxDMA reset\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
thc_interrupt_quiesce(dev, false);
|
||||
|
||||
end:
|
||||
mutex_unlock(&dev->thc_bus_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(thc_rxdma_reset, "INTEL_THC");
|
||||
|
||||
static int read_dma_buffer(struct thc_device *dev,
|
||||
struct thc_dma_configuration *read_config,
|
||||
u8 prd_table_index, void *read_buff)
|
||||
|
||||
@@ -145,6 +145,7 @@ int thc_dma_allocate(struct thc_device *dev);
|
||||
int thc_dma_configure(struct thc_device *dev);
|
||||
void thc_dma_unconfigure(struct thc_device *dev);
|
||||
void thc_dma_release(struct thc_device *dev);
|
||||
int thc_rxdma_reset(struct thc_device *dev);
|
||||
int thc_rxdma_read(struct thc_device *dev, enum thc_dma_channel dma_channel,
|
||||
void *read_buff, size_t *read_len, int *read_finished);
|
||||
int thc_swdma_read(struct thc_device *dev, void *write_buff, size_t write_len,
|
||||
|
||||
@@ -887,4 +887,7 @@ enum THC_I2C_SPEED_MODE {
|
||||
#define THC_I2C_IC_DMA_CR_RDMAE BIT(0)
|
||||
#define THC_I2C_IC_DMA_CR_TDMAE BIT(1)
|
||||
|
||||
#define THC_I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD GENMASK(15, 0)
|
||||
#define THC_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD GENMASK(23, 16)
|
||||
|
||||
#endif /* _INTEL_THC_HW_H_ */
|
||||
|
||||
Reference in New Issue
Block a user