Skip to content

Commit c8f3027

Browse files
sunxinpengJiri Kosina
authored andcommitted
HID: intel-thc-hid: intel-quickspi: Add THC QuickSPI driver skeleton
Create intel-quickspi folder and add Kconfig and Makefile for THC QuickSPI driver. Add basic device structure, definitions and probe/remove functions for QuickSPI driver. Co-developed-by: Even Xu <[email protected]> Signed-off-by: Even Xu <[email protected]> Signed-off-by: Xinpeng Sun <[email protected]> Tested-by: Rui Zhang <[email protected]> Tested-by: Mark Pearson <[email protected]> Reviewed-by: Srinivas Pandruvada <[email protected]> Reviewed-by: Mark Pearson <[email protected]> Tested-by: Aaron Ma <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 4228966 commit c8f3027

File tree

4 files changed

+362
-0
lines changed

4 files changed

+362
-0
lines changed

drivers/hid/intel-thc-hid/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ config INTEL_THC_HID
1717

1818
Say Y/M here if you want to support Intel THC. If unsure, say N.
1919

20+
config INTEL_QUICKSPI
21+
tristate "Intel QuickSPI driver based on Intel Touch Host Controller"
22+
depends on INTEL_THC_HID
23+
help
24+
Intel QuickSPI, based on Touch Host Controller (THC), implements
25+
HIDSPI (HID over SPI) protocol. It configures THC to work at SPI
26+
mode, and controls THC hardware sequencer to accelerate HIDSPI
27+
transaction flow.
28+
29+
Say Y/M here if you want to support Intel QuickSPI. If unsure, say N.
30+
2031
endmenu

drivers/hid/intel-thc-hid/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o
99
intel-thc-objs += intel-thc/intel-thc-dev.o
1010
intel-thc-objs += intel-thc/intel-thc-dma.o
1111

12+
obj-$(CONFIG_INTEL_QUICKSPI) += intel-quickspi.o
13+
intel-quickspi-objs += intel-quickspi/pci-quickspi.o
14+
1215
ccflags-y += -I $(src)/intel-thc
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (c) 2024 Intel Corporation */
3+
4+
#include <linux/device.h>
5+
#include <linux/dma-mapping.h>
6+
#include <linux/err.h>
7+
#include <linux/interrupt.h>
8+
#include <linux/irqreturn.h>
9+
#include <linux/pci.h>
10+
11+
#include "intel-thc-dev.h"
12+
13+
#include "quickspi-dev.h"
14+
15+
struct quickspi_driver_data mtl = {
16+
.max_packet_size_value = MAX_PACKET_SIZE_VALUE_MTL,
17+
};
18+
19+
struct quickspi_driver_data lnl = {
20+
.max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL,
21+
};
22+
23+
struct quickspi_driver_data ptl = {
24+
.max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL,
25+
};
26+
27+
/**
28+
* quickspi_irq_quick_handler - The ISR of the quickspi driver
29+
*
30+
* @irq: The irq number
31+
* @dev_id: pointer to the device structure
32+
*
33+
* Return: IRQ_WAKE_THREAD if further process needed.
34+
*/
35+
static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id)
36+
{
37+
struct quickspi_device *qsdev = dev_id;
38+
39+
if (qsdev->state == QUICKSPI_DISABLED)
40+
return IRQ_HANDLED;
41+
42+
/* Disable THC interrupt before current interrupt be handled */
43+
thc_interrupt_enable(qsdev->thc_hw, false);
44+
45+
return IRQ_WAKE_THREAD;
46+
}
47+
48+
/**
49+
* quickspi_irq_thread_handler - IRQ thread handler of quickspi driver
50+
*
51+
* @irq: The IRQ number
52+
* @dev_id: pointer to the quickspi device structure
53+
*
54+
* Return: IRQ_HANDLED to finish this handler.
55+
*/
56+
static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
57+
{
58+
struct quickspi_device *qsdev = dev_id;
59+
int int_mask;
60+
61+
if (qsdev->state == QUICKSPI_DISABLED)
62+
return IRQ_HANDLED;
63+
64+
int_mask = thc_interrupt_handler(qsdev->thc_hw);
65+
66+
thc_interrupt_enable(qsdev->thc_hw, true);
67+
68+
return IRQ_HANDLED;
69+
}
70+
71+
/**
72+
* quickspi_dev_init - Initialize quickspi device
73+
*
74+
* @pdev: pointer to the thc pci device
75+
* @mem_addr: The pointer of MMIO memory address
76+
* @id: point to pci_device_id structure
77+
*
78+
* Alloc quickspi device structure and initialized THC device,
79+
* then configure THC to HIDSPI mode.
80+
*
81+
* If success, enable THC hardware interrupt.
82+
*
83+
* Return: pointer to the quickspi device structure if success
84+
* or NULL on failed.
85+
*/
86+
static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __iomem *mem_addr,
87+
const struct pci_device_id *id)
88+
{
89+
struct device *dev = &pdev->dev;
90+
struct quickspi_device *qsdev;
91+
int ret;
92+
93+
qsdev = devm_kzalloc(dev, sizeof(struct quickspi_device), GFP_KERNEL);
94+
if (!qsdev)
95+
return ERR_PTR(-ENOMEM);
96+
97+
qsdev->pdev = pdev;
98+
qsdev->dev = dev;
99+
qsdev->mem_addr = mem_addr;
100+
qsdev->driver_data = (struct quickspi_driver_data *)id->driver_data;
101+
102+
/* thc hw init */
103+
qsdev->thc_hw = thc_dev_init(qsdev->dev, qsdev->mem_addr);
104+
if (IS_ERR(qsdev->thc_hw)) {
105+
ret = PTR_ERR(qsdev->thc_hw);
106+
dev_err(dev, "Failed to initialize THC device context, ret = %d.\n", ret);
107+
return ERR_PTR(ret);
108+
}
109+
110+
ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI);
111+
if (ret) {
112+
dev_err(dev, "Failed to select THC port, ret = %d.\n", ret);
113+
return ERR_PTR(ret);
114+
}
115+
116+
thc_interrupt_config(qsdev->thc_hw);
117+
118+
thc_interrupt_enable(qsdev->thc_hw, true);
119+
120+
return qsdev;
121+
}
122+
123+
/**
124+
* quickspi_dev_deinit - De-initialize quickspi device
125+
*
126+
* @qsdev: pointer to the quickspi device structure
127+
*
128+
* Disable THC interrupt and deinitilize THC.
129+
*/
130+
static void quickspi_dev_deinit(struct quickspi_device *qsdev)
131+
{
132+
thc_interrupt_enable(qsdev->thc_hw, false);
133+
}
134+
135+
/*
136+
* quickspi_probe: Quickspi driver probe function
137+
*
138+
* @pdev: point to pci device
139+
* @id: point to pci_device_id structure
140+
*
141+
* Return 0 if success or error code on failure.
142+
*/
143+
static int quickspi_probe(struct pci_dev *pdev,
144+
const struct pci_device_id *id)
145+
{
146+
struct quickspi_device *qsdev;
147+
void __iomem *mem_addr;
148+
int ret;
149+
150+
ret = pcim_enable_device(pdev);
151+
if (ret) {
152+
dev_err(&pdev->dev, "Failed to enable PCI device, ret = %d.\n", ret);
153+
return ret;
154+
}
155+
156+
pci_set_master(pdev);
157+
158+
ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
159+
if (ret) {
160+
dev_err(&pdev->dev, "Failed to get PCI regions, ret = %d.\n", ret);
161+
goto disable_pci_device;
162+
}
163+
164+
mem_addr = pcim_iomap_table(pdev)[0];
165+
166+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
167+
if (ret) {
168+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
169+
if (ret) {
170+
dev_err(&pdev->dev, "No usable DMA configuration %d\n", ret);
171+
goto unmap_io_region;
172+
}
173+
}
174+
175+
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
176+
if (ret < 0) {
177+
dev_err(&pdev->dev,
178+
"Failed to allocate IRQ vectors. ret = %d\n", ret);
179+
goto unmap_io_region;
180+
}
181+
182+
pdev->irq = pci_irq_vector(pdev, 0);
183+
184+
qsdev = quickspi_dev_init(pdev, mem_addr, id);
185+
if (IS_ERR(qsdev)) {
186+
dev_err(&pdev->dev, "QuickSPI device init failed\n");
187+
ret = PTR_ERR(qsdev);
188+
goto unmap_io_region;
189+
}
190+
191+
pci_set_drvdata(pdev, qsdev);
192+
193+
ret = devm_request_threaded_irq(&pdev->dev, pdev->irq,
194+
quickspi_irq_quick_handler,
195+
quickspi_irq_thread_handler,
196+
IRQF_ONESHOT, KBUILD_MODNAME,
197+
qsdev);
198+
if (ret) {
199+
dev_err(&pdev->dev,
200+
"Failed to request threaded IRQ, irq = %d.\n", pdev->irq);
201+
goto dev_deinit;
202+
}
203+
204+
return 0;
205+
206+
dev_deinit:
207+
quickspi_dev_deinit(qsdev);
208+
unmap_io_region:
209+
pcim_iounmap_regions(pdev, BIT(0));
210+
disable_pci_device:
211+
pci_clear_master(pdev);
212+
213+
return ret;
214+
}
215+
216+
/**
217+
* quickspi_remove - Device Removal Routine
218+
*
219+
* @pdev: PCI device structure
220+
*
221+
* This is called by the PCI subsystem to alert the driver
222+
* that it should release a PCI device.
223+
*/
224+
static void quickspi_remove(struct pci_dev *pdev)
225+
{
226+
struct quickspi_device *qsdev;
227+
228+
qsdev = pci_get_drvdata(pdev);
229+
if (!qsdev)
230+
return;
231+
232+
quickspi_dev_deinit(qsdev);
233+
234+
pcim_iounmap_regions(pdev, BIT(0));
235+
pci_clear_master(pdev);
236+
}
237+
238+
/**
239+
* quickspi_shutdown - Device Shutdown Routine
240+
*
241+
* @pdev: PCI device structure
242+
*
243+
* This is called from the reboot notifier
244+
* it's a simplified version of remove so we go down
245+
* faster.
246+
*/
247+
static void quickspi_shutdown(struct pci_dev *pdev)
248+
{
249+
struct quickspi_device *qsdev;
250+
251+
qsdev = pci_get_drvdata(pdev);
252+
if (!qsdev)
253+
return;
254+
255+
quickspi_dev_deinit(qsdev);
256+
}
257+
258+
static const struct pci_device_id quickspi_pci_tbl[] = {
259+
{PCI_DEVICE_DATA(INTEL, THC_MTL_DEVICE_ID_SPI_PORT1, &mtl), },
260+
{PCI_DEVICE_DATA(INTEL, THC_MTL_DEVICE_ID_SPI_PORT2, &mtl), },
261+
{PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_SPI_PORT1, &lnl), },
262+
{PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_SPI_PORT2, &lnl), },
263+
{PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_SPI_PORT1, &ptl), },
264+
{PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_SPI_PORT2, &ptl), },
265+
{PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT1, &ptl), },
266+
{PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT2, &ptl), },
267+
{}
268+
};
269+
MODULE_DEVICE_TABLE(pci, quickspi_pci_tbl);
270+
271+
static struct pci_driver quickspi_driver = {
272+
.name = KBUILD_MODNAME,
273+
.id_table = quickspi_pci_tbl,
274+
.probe = quickspi_probe,
275+
.remove = quickspi_remove,
276+
.shutdown = quickspi_shutdown,
277+
.driver.probe_type = PROBE_PREFER_ASYNCHRONOUS,
278+
};
279+
280+
module_pci_driver(quickspi_driver);
281+
282+
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
283+
MODULE_AUTHOR("Even Xu <[email protected]>");
284+
285+
MODULE_DESCRIPTION("Intel(R) QuickSPI Driver");
286+
MODULE_LICENSE("GPL");
287+
MODULE_IMPORT_NS("INTEL_THC");
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (c) 2024 Intel Corporation */
3+
4+
#ifndef _QUICKSPI_DEV_H_
5+
#define _QUICKSPI_DEV_H_
6+
7+
#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT1 0x7E49
8+
#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT2 0x7E4B
9+
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT1 0xA849
10+
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT2 0xA84B
11+
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT1 0xE349
12+
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT2 0xE34B
13+
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT1 0xE449
14+
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT2 0xE44B
15+
16+
/* Packet size value, the unit is 16 bytes */
17+
#define DEFAULT_MIN_PACKET_SIZE_VALUE 4
18+
#define MAX_PACKET_SIZE_VALUE_MTL 128
19+
#define MAX_PACKET_SIZE_VALUE_LNL 256
20+
21+
enum quickspi_dev_state {
22+
QUICKSPI_NONE,
23+
QUICKSPI_RESETING,
24+
QUICKSPI_RESETED,
25+
QUICKSPI_INITED,
26+
QUICKSPI_ENABLED,
27+
QUICKSPI_DISABLED,
28+
};
29+
30+
/**
31+
* struct quickspi_driver_data - Driver specific data for quickspi device
32+
* @max_packet_size_value: identify max packet size, unit is 16 bytes
33+
*/
34+
struct quickspi_driver_data {
35+
u32 max_packet_size_value;
36+
};
37+
38+
struct device;
39+
struct pci_dev;
40+
struct thc_device;
41+
42+
/**
43+
* struct quickspi_device - THC QuickSpi device struct
44+
* @dev: point to kernel device
45+
* @pdev: point to PCI device
46+
* @thc_hw: point to THC device
47+
* @driver_data: point to quickspi specific driver data
48+
* @state: THC SPI device state
49+
* @mem_addr: MMIO memory address
50+
*/
51+
struct quickspi_device {
52+
struct device *dev;
53+
struct pci_dev *pdev;
54+
struct thc_device *thc_hw;
55+
struct quickspi_driver_data *driver_data;
56+
enum quickspi_dev_state state;
57+
58+
void __iomem *mem_addr;
59+
};
60+
61+
#endif /* _QUICKSPI_DEV_H_ */

0 commit comments

Comments
 (0)