Skip to content

Commit f02bcab

Browse files
sunxinpengJiri Kosina
authored andcommitted
HID: intel-thc-hid: intel-thc: Add THC SPI config interfaces
Add SPI bus related APIs to configure SPI operation parameters, such as port type, bus frequency, bus IO mode, read/write OPcode, and slave register addresses. 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 4e682ea commit f02bcab

File tree

3 files changed

+288
-0
lines changed

3 files changed

+288
-0
lines changed

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,235 @@ int thc_interrupt_handler(struct thc_device *dev)
10611061
}
10621062
EXPORT_SYMBOL_NS_GPL(thc_interrupt_handler, "INTEL_THC");
10631063

1064+
/**
1065+
* thc_port_select - Set THC port type
1066+
*
1067+
* @dev: The pointer of THC private device context
1068+
* @port_type: THC port type to use for current device
1069+
*
1070+
* Return: 0 on success, other error codes on failed.
1071+
*/
1072+
int thc_port_select(struct thc_device *dev, enum thc_port_type port_type)
1073+
{
1074+
u32 ctrl, mask;
1075+
1076+
if (port_type == THC_PORT_TYPE_SPI) {
1077+
dev_dbg(dev->dev, "Set THC port type to SPI\n");
1078+
dev->port_type = THC_PORT_TYPE_SPI;
1079+
1080+
/* Enable delay of CS assertion and set to default value */
1081+
ctrl = THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN |
1082+
FIELD_PREP(THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL,
1083+
THC_CSA_CK_DELAY_VAL_DEFAULT);
1084+
mask = THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN |
1085+
THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL;
1086+
regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_DUTYC_CFG_OFFSET,
1087+
mask, ctrl);
1088+
} else if (port_type == THC_PORT_TYPE_I2C) {
1089+
dev_dbg(dev->dev, "Set THC port type to I2C\n");
1090+
dev->port_type = THC_PORT_TYPE_I2C;
1091+
1092+
/* Set THC transition arbitration policy to frame boundary for I2C */
1093+
ctrl = FIELD_PREP(THC_M_PRT_CONTROL_THC_ARB_POLICY,
1094+
THC_ARB_POLICY_FRAME_BOUNDARY);
1095+
mask = THC_M_PRT_CONTROL_THC_ARB_POLICY;
1096+
1097+
regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, mask, ctrl);
1098+
} else {
1099+
dev_err(dev->dev, "unsupported THC port type: %d\n", port_type);
1100+
return -EINVAL;
1101+
}
1102+
1103+
ctrl = FIELD_PREP(THC_M_PRT_CONTROL_PORT_TYPE, port_type);
1104+
mask = THC_M_PRT_CONTROL_PORT_TYPE;
1105+
1106+
regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, mask, ctrl);
1107+
1108+
return 0;
1109+
}
1110+
EXPORT_SYMBOL_NS_GPL(thc_port_select, "INTEL_THC");
1111+
1112+
#define THC_SPI_FREQUENCY_7M 7812500
1113+
#define THC_SPI_FREQUENCY_15M 15625000
1114+
#define THC_SPI_FREQUENCY_17M 17857100
1115+
#define THC_SPI_FREQUENCY_20M 20833000
1116+
#define THC_SPI_FREQUENCY_25M 25000000
1117+
#define THC_SPI_FREQUENCY_31M 31250000
1118+
#define THC_SPI_FREQUENCY_41M 41666700
1119+
1120+
#define THC_SPI_LOW_FREQUENCY THC_SPI_FREQUENCY_17M
1121+
1122+
static u8 thc_get_spi_freq_div_val(struct thc_device *dev, u32 spi_freq_val)
1123+
{
1124+
int frequency[] = {
1125+
THC_SPI_FREQUENCY_7M,
1126+
THC_SPI_FREQUENCY_15M,
1127+
THC_SPI_FREQUENCY_17M,
1128+
THC_SPI_FREQUENCY_20M,
1129+
THC_SPI_FREQUENCY_25M,
1130+
THC_SPI_FREQUENCY_31M,
1131+
THC_SPI_FREQUENCY_41M,
1132+
};
1133+
u8 frequency_div[] = {
1134+
THC_SPI_FRQ_DIV_2,
1135+
THC_SPI_FRQ_DIV_1,
1136+
THC_SPI_FRQ_DIV_7,
1137+
THC_SPI_FRQ_DIV_6,
1138+
THC_SPI_FRQ_DIV_5,
1139+
THC_SPI_FRQ_DIV_4,
1140+
THC_SPI_FRQ_DIV_3,
1141+
};
1142+
int size = ARRAY_SIZE(frequency);
1143+
u32 closest_freq;
1144+
u8 freq_div;
1145+
int i;
1146+
1147+
for (i = size - 1; i >= 0; i--)
1148+
if ((int)spi_freq_val - frequency[i] >= 0)
1149+
break;
1150+
1151+
if (i < 0) {
1152+
dev_err_once(dev->dev, "Not supported SPI frequency %d\n", spi_freq_val);
1153+
return THC_SPI_FRQ_RESERVED;
1154+
}
1155+
1156+
closest_freq = frequency[i];
1157+
freq_div = frequency_div[i];
1158+
1159+
dev_dbg(dev->dev,
1160+
"Setting SPI frequency: spi_freq_val = %u, Closest freq = %u\n",
1161+
spi_freq_val, closest_freq);
1162+
1163+
return freq_div;
1164+
}
1165+
1166+
/**
1167+
* thc_spi_read_config - Configure SPI bus read attributes
1168+
*
1169+
* @dev: The pointer of THC private device context
1170+
* @spi_freq_val: SPI read frequecy value
1171+
* @io_mode: SPI read IO mode
1172+
* @opcode: Read opcode
1173+
* @spi_rd_mps: SPI read max packet size
1174+
*
1175+
* Return: 0 on success, other error codes on failed.
1176+
*/
1177+
int thc_spi_read_config(struct thc_device *dev, u32 spi_freq_val,
1178+
u32 io_mode, u32 opcode, u32 spi_rd_mps)
1179+
{
1180+
bool is_low_freq = false;
1181+
u32 cfg, mask;
1182+
u8 freq_div;
1183+
1184+
freq_div = thc_get_spi_freq_div_val(dev, spi_freq_val);
1185+
if (freq_div == THC_SPI_FRQ_RESERVED)
1186+
return -EINVAL;
1187+
1188+
if (spi_freq_val < THC_SPI_LOW_FREQUENCY)
1189+
is_low_freq = true;
1190+
1191+
cfg = FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TCRF, freq_div) |
1192+
FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TRMODE, io_mode) |
1193+
(is_low_freq ? THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN : 0) |
1194+
FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_RD_MPS, spi_rd_mps);
1195+
mask = THC_M_PRT_SPI_CFG_SPI_TCRF |
1196+
THC_M_PRT_SPI_CFG_SPI_TRMODE |
1197+
THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN |
1198+
THC_M_PRT_SPI_CFG_SPI_RD_MPS;
1199+
1200+
regmap_write_bits(dev->thc_regmap,
1201+
THC_M_PRT_SPI_CFG_OFFSET, mask, cfg);
1202+
1203+
if (io_mode == THC_QUAD_IO)
1204+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO, opcode);
1205+
else if (io_mode == THC_DUAL_IO)
1206+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO, opcode);
1207+
else
1208+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_SIO, opcode);
1209+
1210+
regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, opcode);
1211+
regmap_write(dev->thc_regmap, THC_M_PRT_SPI_DMARD_OPCODE_OFFSET, opcode);
1212+
1213+
return 0;
1214+
}
1215+
EXPORT_SYMBOL_NS_GPL(thc_spi_read_config, "INTEL_THC");
1216+
1217+
/**
1218+
* thc_spi_write_config - Configure SPI bus write attributes
1219+
*
1220+
* @dev: The pointer of THC private device context
1221+
* @spi_freq_val: SPI write frequecy value
1222+
* @io_mode: SPI write IO mode
1223+
* @opcode: Write opcode
1224+
* @spi_wr_mps: SPI write max packet size
1225+
* @perf_limit: Performance limitation in unit of 10us
1226+
*
1227+
* Return: 0 on success, other error codes on failed.
1228+
*/
1229+
int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val,
1230+
u32 io_mode, u32 opcode, u32 spi_wr_mps,
1231+
u32 perf_limit)
1232+
{
1233+
bool is_low_freq = false;
1234+
u32 cfg, mask;
1235+
u8 freq_div;
1236+
1237+
freq_div = thc_get_spi_freq_div_val(dev, spi_freq_val);
1238+
if (freq_div == THC_SPI_FRQ_RESERVED)
1239+
return -EINVAL;
1240+
1241+
if (spi_freq_val < THC_SPI_LOW_FREQUENCY)
1242+
is_low_freq = true;
1243+
1244+
cfg = FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TCWF, freq_div) |
1245+
FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TWMODE, io_mode) |
1246+
(is_low_freq ? THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN : 0) |
1247+
FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_WR_MPS, spi_wr_mps);
1248+
mask = THC_M_PRT_SPI_CFG_SPI_TCWF |
1249+
THC_M_PRT_SPI_CFG_SPI_TWMODE |
1250+
THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN |
1251+
THC_M_PRT_SPI_CFG_SPI_WR_MPS;
1252+
1253+
regmap_write_bits(dev->thc_regmap,
1254+
THC_M_PRT_SPI_CFG_OFFSET, mask, cfg);
1255+
1256+
if (io_mode == THC_QUAD_IO)
1257+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO, opcode);
1258+
else if (io_mode == THC_DUAL_IO)
1259+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO, opcode);
1260+
else
1261+
opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_SIO, opcode);
1262+
1263+
regmap_write(dev->thc_regmap, THC_M_PRT_SPI_WR_OPCODE_OFFSET, opcode);
1264+
1265+
dev->perf_limit = perf_limit;
1266+
1267+
return 0;
1268+
}
1269+
EXPORT_SYMBOL_NS_GPL(thc_spi_write_config, "INTEL_THC");
1270+
1271+
/**
1272+
* thc_spi_input_output_address_config - Configure SPI input and output addresses
1273+
*
1274+
* @dev: the pointer of THC private device context
1275+
* @input_hdr_addr: input report header address
1276+
* @input_bdy_addr: input report body address
1277+
* @output_addr: output report address
1278+
*/
1279+
void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr,
1280+
u32 input_bdy_addr, u32 output_addr)
1281+
{
1282+
regmap_write(dev->thc_regmap,
1283+
THC_M_PRT_DEV_INT_CAUSE_ADDR_OFFSET, input_hdr_addr);
1284+
regmap_write(dev->thc_regmap,
1285+
THC_M_PRT_RD_BULK_ADDR_1_OFFSET, input_bdy_addr);
1286+
regmap_write(dev->thc_regmap,
1287+
THC_M_PRT_RD_BULK_ADDR_2_OFFSET, input_bdy_addr);
1288+
regmap_write(dev->thc_regmap,
1289+
THC_M_PRT_WR_BULK_ADDR_OFFSET, output_addr);
1290+
}
1291+
EXPORT_SYMBOL_NS_GPL(thc_spi_input_output_address_config, "INTEL_THC");
1292+
10641293
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
10651294
MODULE_AUTHOR("Even Xu <[email protected]>");
10661295

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,12 @@ void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode);
9898
void thc_ltr_unconfig(struct thc_device *dev);
9999
u32 thc_int_cause_read(struct thc_device *dev);
100100
int thc_interrupt_handler(struct thc_device *dev);
101+
int thc_port_select(struct thc_device *dev, enum thc_port_type port_type);
102+
int thc_spi_read_config(struct thc_device *dev, u32 spi_freq_val,
103+
u32 io_mode, u32 opcode, u32 spi_rd_mps);
104+
int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val,
105+
u32 io_mode, u32 opcode, u32 spi_wr_mps, u32 perf_limit);
106+
void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr,
107+
u32 input_bdy_addr, u32 output_addr);
101108

102109
#endif /* _INTEL_THC_DEV_H_ */

drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,20 @@
636636

637637
#define THC_M_PRT_SW_DMA_PRD_TABLE_LEN_THC_M_PRT_SW_DMA_PRD_TABLE_LEN GENMASK(23, 0)
638638

639+
#define THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL GENMASK(3, 0)
640+
#define THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN BIT(25)
641+
642+
/* CS Assertion delay default value */
643+
#define THC_CSA_CK_DELAY_VAL_DEFAULT 4
644+
645+
/* ARB policy definition */
646+
/* Arbiter switches on packet boundary */
647+
#define THC_ARB_POLICY_PACKET_BOUNDARY 0
648+
/* Arbiter switches on Micro Frame boundary */
649+
#define THC_ARB_POLICY_UFRAME_BOUNDARY 1
650+
/* Arbiter switches on Frame boundary */
651+
#define THC_ARB_POLICY_FRAME_BOUNDARY 2
652+
639653
#define THC_REGMAP_POLLING_INTERVAL_US 10 /* 10us */
640654
#define THC_PIO_DONE_TIMEOUT_US USEC_PER_SEC /* 1s */
641655

@@ -697,4 +711,42 @@ enum thc_pio_opcode {
697711
THC_PIO_OP_I2C_TIC_WRITE_AND_READ = 0x1C,
698712
};
699713

714+
/**
715+
* THC SPI IO mode
716+
* @THC_SINGLE_IO: single IO mode, 1(opcode) - 1(address) - 1(data)
717+
* @THC_DUAL_IO: dual IO mode, 1(opcode) - 2(address) - 2(data)
718+
* @THC_QUAD_IO: quad IO mode, 1(opcode) - 4(address) - 4(data)
719+
* @THC_QUAD_PARALLEL_IO: parallel quad IO mode, 4(opcode) - 4(address) - 4(data)
720+
*/
721+
enum thc_spi_iomode {
722+
THC_SINGLE_IO = 0,
723+
THC_DUAL_IO = 1,
724+
THC_QUAD_IO = 2,
725+
THC_QUAD_PARALLEL_IO = 3,
726+
};
727+
728+
/**
729+
* THC SPI frequency divider
730+
*
731+
* This DIV final value is determined by THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN bit.
732+
* If THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN isn't be set, THC takes the DIV value directly;
733+
* If THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN is set, THC takes the DIV value multiply by 8.
734+
*
735+
* For example, if THC input clock is 125MHz:
736+
* When THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN isn't set, THC_SPI_FRQ_DIV_3 means DIV is 3,
737+
* THC final clock is 125 / 3 = 41.667MHz;
738+
* When THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN is set, THC_SPI_FRQ_DIV_3 means DIV is 3 * 8,
739+
* THC final clock is 125 / (3 * 8) = 5.208MHz;
740+
*/
741+
enum thc_spi_frq_div {
742+
THC_SPI_FRQ_RESERVED = 0,
743+
THC_SPI_FRQ_DIV_1 = 1,
744+
THC_SPI_FRQ_DIV_2 = 2,
745+
THC_SPI_FRQ_DIV_3 = 3,
746+
THC_SPI_FRQ_DIV_4 = 4,
747+
THC_SPI_FRQ_DIV_5 = 5,
748+
THC_SPI_FRQ_DIV_6 = 6,
749+
THC_SPI_FRQ_DIV_7 = 7,
750+
};
751+
700752
#endif /* _INTEL_THC_HW_H_ */

0 commit comments

Comments
 (0)