1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * AMD MP2 PCIe communication driver
4 * Copyright 2020 Advanced Micro Devices, Inc.
6 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
7 * Sandeep Singh <Sandeep.singh@amd.com>
10 #include <linux/bitops.h>
11 #include <linux/delay.h>
12 #include <linux/dma-mapping.h>
13 #include <linux/interrupt.h>
14 #include <linux/io-64-nonatomic-lo-hi.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
18 #include "amd_sfh_pcie.h"
20 #define DRIVER_NAME "pcie_mp2_amd"
21 #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
23 #define ACEL_EN BIT(0)
24 #define GYRO_EN BIT(1)
25 #define MAGNO_EN BIT(2)
26 #define ALS_EN BIT(19)
28 void amd_start_sensor(struct amd_mp2_dev
*privdata
, struct amd_mp2_sensor_info info
)
30 union sfh_cmd_param cmd_param
;
31 union sfh_cmd_base cmd_base
;
33 /* fill up command register */
34 memset(&cmd_base
, 0, sizeof(cmd_base
));
35 cmd_base
.s
.cmd_id
= ENABLE_SENSOR
;
36 cmd_base
.s
.period
= info
.period
;
37 cmd_base
.s
.sensor_id
= info
.sensor_idx
;
39 /* fill up command param register */
40 memset(&cmd_param
, 0, sizeof(cmd_param
));
41 cmd_param
.s
.buf_layout
= 1;
42 cmd_param
.s
.buf_length
= 16;
44 writeq(info
.phys_address
, privdata
->mmio
+ AMD_C2P_MSG2
);
45 writel(cmd_param
.ul
, privdata
->mmio
+ AMD_C2P_MSG1
);
46 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
49 void amd_stop_sensor(struct amd_mp2_dev
*privdata
, u16 sensor_idx
)
51 union sfh_cmd_base cmd_base
;
53 /* fill up command register */
54 memset(&cmd_base
, 0, sizeof(cmd_base
));
55 cmd_base
.s
.cmd_id
= DISABLE_SENSOR
;
56 cmd_base
.s
.period
= 0;
57 cmd_base
.s
.sensor_id
= sensor_idx
;
59 writeq(0x0, privdata
->mmio
+ AMD_C2P_MSG2
);
60 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
63 void amd_stop_all_sensors(struct amd_mp2_dev
*privdata
)
65 union sfh_cmd_base cmd_base
;
67 /* fill up command register */
68 memset(&cmd_base
, 0, sizeof(cmd_base
));
69 cmd_base
.s
.cmd_id
= STOP_ALL_SENSORS
;
70 cmd_base
.s
.period
= 0;
71 cmd_base
.s
.sensor_id
= 0;
73 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
76 int amd_mp2_get_sensor_num(struct amd_mp2_dev
*privdata
, u8
*sensor_id
)
78 int activestatus
, num_of_sensors
= 0;
80 privdata
->activecontrolstatus
= readl(privdata
->mmio
+ AMD_P2C_MSG3
);
81 activestatus
= privdata
->activecontrolstatus
>> 4;
82 if (ACEL_EN
& activestatus
)
83 sensor_id
[num_of_sensors
++] = accel_idx
;
85 if (GYRO_EN
& activestatus
)
86 sensor_id
[num_of_sensors
++] = gyro_idx
;
88 if (MAGNO_EN
& activestatus
)
89 sensor_id
[num_of_sensors
++] = mag_idx
;
91 if (ALS_EN
& activestatus
)
92 sensor_id
[num_of_sensors
++] = als_idx
;
94 return num_of_sensors
;
97 static void amd_mp2_pci_remove(void *privdata
)
99 amd_sfh_hid_client_deinit(privdata
);
100 amd_stop_all_sensors(privdata
);
103 static int amd_mp2_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
105 struct amd_mp2_dev
*privdata
;
108 privdata
= devm_kzalloc(&pdev
->dev
, sizeof(*privdata
), GFP_KERNEL
);
112 privdata
->pdev
= pdev
;
113 pci_set_drvdata(pdev
, privdata
);
114 rc
= pcim_enable_device(pdev
);
118 rc
= pcim_iomap_regions(pdev
, BIT(2), DRIVER_NAME
);
122 privdata
->mmio
= pcim_iomap_table(pdev
)[2];
123 pci_set_master(pdev
);
124 rc
= pci_set_dma_mask(pdev
, DMA_BIT_MASK(64));
126 rc
= pci_set_dma_mask(pdev
, DMA_BIT_MASK(32));
129 rc
= devm_add_action_or_reset(&pdev
->dev
, amd_mp2_pci_remove
, privdata
);
133 return amd_sfh_hid_client_init(privdata
);
136 static const struct pci_device_id amd_mp2_pci_tbl
[] = {
137 { PCI_VDEVICE(AMD
, PCI_DEVICE_ID_AMD_MP2
) },
140 MODULE_DEVICE_TABLE(pci
, amd_mp2_pci_tbl
);
142 static struct pci_driver amd_mp2_pci_driver
= {
144 .id_table
= amd_mp2_pci_tbl
,
145 .probe
= amd_mp2_pci_probe
,
147 module_pci_driver(amd_mp2_pci_driver
);
149 MODULE_DESCRIPTION(DRIVER_DESC
);
150 MODULE_LICENSE("Dual BSD/GPL");
151 MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
152 MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");