Skip to content

Commit 4138f21

Browse files
sunxinpengJiri Kosina
authored andcommitted
HID: intel-thc-hid: intel-quickspi: Complete THC QuickSPI driver
Fully implement QuickSPI driver probe/remove callbacks, interrupt handler, integrate HIDSPI protocol, enumerate HID device and register HID device. Co-developed-by: Even Xu <even.xu@intel.com> Signed-off-by: Even Xu <even.xu@intel.com> Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com> Tested-by: Rui Zhang <rui1.zhang@intel.com> Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca> Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca> Tested-by: Aaron Ma <aaron.ma@canonical.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 9d8d517 commit 4138f21

File tree

2 files changed

+268
-0
lines changed

2 files changed

+268
-0
lines changed

drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "intel-thc-hw.h"
1515

1616
#include "quickspi-dev.h"
17+
#include "quickspi-hid.h"
18+
#include "quickspi-protocol.h"
1719

1820
struct quickspi_driver_data mtl = {
1921
.max_packet_size_value = MAX_PACKET_SIZE_VALUE_MTL,
@@ -228,6 +230,37 @@ static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id)
228230
return IRQ_WAKE_THREAD;
229231
}
230232

233+
/**
234+
* try_recover - Try to recovery THC and Device
235+
* @qsdev: pointer to quickspi device
236+
*
237+
* This function is a error handler, called when fatal error happens.
238+
* It try to reset Touch Device and re-configure THC to recovery
239+
* transferring between Device and THC.
240+
*
241+
* Return: 0 if successful or error code on failed.
242+
*/
243+
static int try_recover(struct quickspi_device *qsdev)
244+
{
245+
int ret;
246+
247+
ret = reset_tic(qsdev);
248+
if (ret) {
249+
dev_err(qsdev->dev, "Reset touch device failed, ret = %d\n", ret);
250+
return ret;
251+
}
252+
253+
thc_dma_unconfigure(qsdev->thc_hw);
254+
255+
ret = thc_dma_configure(qsdev->thc_hw);
256+
if (ret) {
257+
dev_err(qsdev->dev, "Re-configure THC DMA failed, ret = %d\n", ret);
258+
return ret;
259+
}
260+
261+
return 0;
262+
}
263+
231264
/**
232265
* quickspi_irq_thread_handler - IRQ thread handler of quickspi driver
233266
*
@@ -239,15 +272,52 @@ static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id)
239272
static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
240273
{
241274
struct quickspi_device *qsdev = dev_id;
275+
size_t input_len;
276+
int read_finished = 0;
277+
int err_recover = 0;
242278
int int_mask;
279+
int ret;
243280

244281
if (qsdev->state == QUICKSPI_DISABLED)
245282
return IRQ_HANDLED;
246283

247284
int_mask = thc_interrupt_handler(qsdev->thc_hw);
248285

286+
if (int_mask & BIT(THC_FATAL_ERR_INT) || int_mask & BIT(THC_TXN_ERR_INT)) {
287+
err_recover = 1;
288+
goto end;
289+
}
290+
291+
if (int_mask & BIT(THC_NONDMA_INT)) {
292+
if (qsdev->state == QUICKSPI_RESETING) {
293+
qsdev->reset_ack = true;
294+
wake_up_interruptible(&qsdev->reset_ack_wq);
295+
} else {
296+
qsdev->nondma_int_received = true;
297+
wake_up_interruptible(&qsdev->nondma_int_received_wq);
298+
}
299+
}
300+
301+
if (int_mask & BIT(THC_RXDMA2_INT)) {
302+
while (!read_finished) {
303+
ret = thc_rxdma_read(qsdev->thc_hw, THC_RXDMA2, qsdev->input_buf,
304+
&input_len, &read_finished);
305+
if (ret) {
306+
err_recover = 1;
307+
goto end;
308+
}
309+
310+
quickspi_handle_input_data(qsdev, input_len);
311+
}
312+
}
313+
314+
end:
249315
thc_interrupt_enable(qsdev->thc_hw, true);
250316

317+
if (err_recover)
318+
if (try_recover(qsdev))
319+
qsdev->state = QUICKSPI_DISABLED;
320+
251321
return IRQ_HANDLED;
252322
}
253323

@@ -280,8 +350,15 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
280350
qsdev->pdev = pdev;
281351
qsdev->dev = dev;
282352
qsdev->mem_addr = mem_addr;
353+
qsdev->state = QUICKSPI_DISABLED;
283354
qsdev->driver_data = (struct quickspi_driver_data *)id->driver_data;
284355

356+
init_waitqueue_head(&qsdev->reset_ack_wq);
357+
init_waitqueue_head(&qsdev->nondma_int_received_wq);
358+
init_waitqueue_head(&qsdev->report_desc_got_wq);
359+
init_waitqueue_head(&qsdev->get_report_cmpl_wq);
360+
init_waitqueue_head(&qsdev->set_report_cmpl_wq);
361+
285362
/* thc hw init */
286363
qsdev->thc_hw = thc_dev_init(qsdev->dev, qsdev->mem_addr);
287364
if (IS_ERR(qsdev->thc_hw)) {
@@ -290,6 +367,10 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
290367
return ERR_PTR(ret);
291368
}
292369

370+
ret = thc_interrupt_quiesce(qsdev->thc_hw, true);
371+
if (ret)
372+
return ERR_PTR(ret);
373+
293374
ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI);
294375
if (ret) {
295376
dev_err(dev, "Failed to select THC port, ret = %d.\n", ret);
@@ -302,10 +383,43 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
302383
return ERR_PTR(ret);
303384
}
304385

386+
/* THC config for input/output address */
387+
thc_spi_input_output_address_config(qsdev->thc_hw,
388+
qsdev->input_report_hdr_addr,
389+
qsdev->input_report_bdy_addr,
390+
qsdev->output_report_addr);
391+
392+
/* THC config for spi read operation */
393+
ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val,
394+
qsdev->spi_read_io_mode,
395+
qsdev->spi_read_opcode,
396+
qsdev->spi_packet_size);
397+
if (ret) {
398+
dev_err(dev, "thc_spi_read_config failed, ret = %d\n", ret);
399+
return ERR_PTR(ret);
400+
}
401+
402+
/* THC config for spi write operation */
403+
ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val,
404+
qsdev->spi_write_io_mode,
405+
qsdev->spi_write_opcode,
406+
qsdev->spi_packet_size,
407+
qsdev->performance_limit);
408+
if (ret) {
409+
dev_err(dev, "thc_spi_write_config failed, ret = %d\n", ret);
410+
return ERR_PTR(ret);
411+
}
412+
413+
thc_ltr_config(qsdev->thc_hw,
414+
qsdev->active_ltr_val,
415+
qsdev->low_power_ltr_val);
416+
305417
thc_interrupt_config(qsdev->thc_hw);
306418

307419
thc_interrupt_enable(qsdev->thc_hw, true);
308420

421+
qsdev->state = QUICKSPI_INITED;
422+
309423
return qsdev;
310424
}
311425

@@ -319,6 +433,103 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
319433
static void quickspi_dev_deinit(struct quickspi_device *qsdev)
320434
{
321435
thc_interrupt_enable(qsdev->thc_hw, false);
436+
thc_ltr_unconfig(qsdev->thc_hw);
437+
438+
qsdev->state = QUICKSPI_DISABLED;
439+
}
440+
441+
/**
442+
* quickspi_dma_init - Configure THC DMA for quickspi device
443+
* @qsdev: pointer to the quickspi device structure
444+
*
445+
* This function uses TIC's parameters(such as max input length, max output
446+
* length) to allocate THC DMA buffers and configure THC DMA engines.
447+
*
448+
* Return: 0 if successful or error code on failed.
449+
*/
450+
static int quickspi_dma_init(struct quickspi_device *qsdev)
451+
{
452+
int ret;
453+
454+
ret = thc_dma_set_max_packet_sizes(qsdev->thc_hw, 0,
455+
le16_to_cpu(qsdev->dev_desc.max_input_len),
456+
le16_to_cpu(qsdev->dev_desc.max_output_len),
457+
0);
458+
if (ret)
459+
return ret;
460+
461+
ret = thc_dma_allocate(qsdev->thc_hw);
462+
if (ret) {
463+
dev_err(qsdev->dev, "Allocate THC DMA buffer failed, ret = %d\n", ret);
464+
return ret;
465+
}
466+
467+
/* Enable RxDMA */
468+
ret = thc_dma_configure(qsdev->thc_hw);
469+
if (ret) {
470+
dev_err(qsdev->dev, "Configure THC DMA failed, ret = %d\n", ret);
471+
thc_dma_unconfigure(qsdev->thc_hw);
472+
thc_dma_release(qsdev->thc_hw);
473+
return ret;
474+
}
475+
476+
return ret;
477+
}
478+
479+
/**
480+
* quickspi_dma_deinit - Release THC DMA for quickspi device
481+
* @qsdev: pointer to the quickspi device structure
482+
*
483+
* Stop THC DMA engines and release all DMA buffers.
484+
*
485+
*/
486+
static void quickspi_dma_deinit(struct quickspi_device *qsdev)
487+
{
488+
thc_dma_unconfigure(qsdev->thc_hw);
489+
thc_dma_release(qsdev->thc_hw);
490+
}
491+
492+
/**
493+
* quickspi_alloc_report_buf - Alloc report buffers
494+
* @qsdev: pointer to the quickspi device structure
495+
*
496+
* Allocate report descriptor buffer, it will be used for restore TIC HID
497+
* report descriptor.
498+
*
499+
* Allocate input report buffer, it will be used for receive HID input report
500+
* data from TIC.
501+
*
502+
* Allocate output report buffer, it will be used for store HID output report,
503+
* such as set feature.
504+
*
505+
* Return: 0 if successful or error code on failed.
506+
*/
507+
static int quickspi_alloc_report_buf(struct quickspi_device *qsdev)
508+
{
509+
size_t max_report_len;
510+
size_t max_input_len;
511+
512+
qsdev->report_descriptor = devm_kzalloc(qsdev->dev,
513+
le16_to_cpu(qsdev->dev_desc.rep_desc_len),
514+
GFP_KERNEL);
515+
if (!qsdev->report_descriptor)
516+
return -ENOMEM;
517+
518+
max_input_len = max(le16_to_cpu(qsdev->dev_desc.rep_desc_len),
519+
le16_to_cpu(qsdev->dev_desc.max_input_len));
520+
521+
qsdev->input_buf = devm_kzalloc(qsdev->dev, max_input_len, GFP_KERNEL);
522+
if (!qsdev->input_buf)
523+
return -ENOMEM;
524+
525+
max_report_len = max(le16_to_cpu(qsdev->dev_desc.max_output_len),
526+
le16_to_cpu(qsdev->dev_desc.max_input_len));
527+
528+
qsdev->report_buf = devm_kzalloc(qsdev->dev, max_report_len, GFP_KERNEL);
529+
if (!qsdev->report_buf)
530+
return -ENOMEM;
531+
532+
return 0;
322533
}
323534

324535
/*
@@ -327,6 +538,18 @@ static void quickspi_dev_deinit(struct quickspi_device *qsdev)
327538
* @pdev: point to pci device
328539
* @id: point to pci_device_id structure
329540
*
541+
* This function initializes THC and HIDSPI device, the flow is:
542+
* - do THC pci device initialization
543+
* - query HIDSPI ACPI parameters
544+
* - configure THC to HIDSPI mode
545+
* - go through HIDSPI enumeration flow
546+
* |- reset HIDSPI device
547+
* |- read device descriptor
548+
* - enable THC interrupt and DMA
549+
* - read report descriptor
550+
* - register HID device
551+
* - enable runtime power management
552+
*
330553
* Return 0 if success or error code on failure.
331554
*/
332555
static int quickspi_probe(struct pci_dev *pdev,
@@ -390,8 +613,44 @@ static int quickspi_probe(struct pci_dev *pdev,
390613
goto dev_deinit;
391614
}
392615

616+
ret = reset_tic(qsdev);
617+
if (ret) {
618+
dev_err(&pdev->dev, "Reset Touch Device failed, ret = %d\n", ret);
619+
goto dev_deinit;
620+
}
621+
622+
ret = quickspi_alloc_report_buf(qsdev);
623+
if (ret) {
624+
dev_err(&pdev->dev, "Alloc report buffers failed, ret= %d\n", ret);
625+
goto dev_deinit;
626+
}
627+
628+
ret = quickspi_dma_init(qsdev);
629+
if (ret) {
630+
dev_err(&pdev->dev, "Setup THC DMA failed, ret= %d\n", ret);
631+
goto dev_deinit;
632+
}
633+
634+
ret = quickspi_get_report_descriptor(qsdev);
635+
if (ret) {
636+
dev_err(&pdev->dev, "Get report descriptor failed, ret = %d\n", ret);
637+
goto dma_deinit;
638+
}
639+
640+
ret = quickspi_hid_probe(qsdev);
641+
if (ret) {
642+
dev_err(&pdev->dev, "Failed to register HID device, ret = %d\n", ret);
643+
goto dma_deinit;
644+
}
645+
646+
qsdev->state = QUICKSPI_ENABLED;
647+
648+
dev_dbg(&pdev->dev, "QuickSPI probe success\n");
649+
393650
return 0;
394651

652+
dma_deinit:
653+
quickspi_dma_deinit(qsdev);
395654
dev_deinit:
396655
quickspi_dev_deinit(qsdev);
397656
unmap_io_region:
@@ -418,6 +677,9 @@ static void quickspi_remove(struct pci_dev *pdev)
418677
if (!qsdev)
419678
return;
420679

680+
quickspi_hid_remove(qsdev);
681+
quickspi_dma_deinit(qsdev);
682+
421683
quickspi_dev_deinit(qsdev);
422684

423685
pcim_iounmap_regions(pdev, BIT(0));
@@ -441,6 +703,9 @@ static void quickspi_shutdown(struct pci_dev *pdev)
441703
if (!qsdev)
442704
return;
443705

706+
/* Must stop DMA before reboot to avoid DMA entering into unknown state */
707+
quickspi_dma_deinit(qsdev);
708+
444709
quickspi_dev_deinit(qsdev);
445710
}
446711

drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len)
225225
break;
226226

227227
case DATA:
228+
if (qsdev->state != QUICKSPI_ENABLED)
229+
return;
230+
228231
if (input_len > le16_to_cpu(qsdev->dev_desc.max_input_len)) {
229232
dev_err_once(qsdev->dev, "Unexpected too large input report length: %u\n",
230233
input_len);

0 commit comments

Comments
 (0)