Skip to content

Commit 4228966

Browse files
EvenxfJiri Kosina
authored andcommitted
HID: intel-thc-hid: intel-thc: Add THC I2C config interfaces
Add I2C bus related APIs to initialize I2C sub-system parameters, such as bus speed, slave address, address bit. As I2C sub-system hasn't auto register save and restore support, provide APIs to do it manually. Co-developed-by: Xinpeng Sun <[email protected]> Signed-off-by: Xinpeng Sun <[email protected]> Signed-off-by: Even Xu <[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 f02bcab commit 4228966

File tree

3 files changed

+417
-0
lines changed

3 files changed

+417
-0
lines changed

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

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,287 @@ void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_a
12901290
}
12911291
EXPORT_SYMBOL_NS_GPL(thc_spi_input_output_address_config, "INTEL_THC");
12921292

1293+
static int thc_i2c_subip_pio_read(struct thc_device *dev, const u32 address,
1294+
u32 *size, u32 *buffer)
1295+
{
1296+
int ret;
1297+
1298+
if (!size || *size == 0 || !buffer) {
1299+
dev_err(dev->dev, "Invalid input parameters, size %p, buffer %p\n",
1300+
size, buffer);
1301+
return -EINVAL;
1302+
}
1303+
1304+
if (mutex_lock_interruptible(&dev->thc_bus_lock))
1305+
return -EINTR;
1306+
1307+
ret = prepare_pio(dev, THC_PIO_OP_I2C_SUBSYSTEM_READ, address, *size);
1308+
if (ret < 0)
1309+
goto end;
1310+
1311+
pio_start(dev, 0, NULL);
1312+
1313+
ret = pio_wait(dev);
1314+
if (ret < 0)
1315+
goto end;
1316+
1317+
ret = pio_complete(dev, buffer, size);
1318+
if (ret < 0)
1319+
goto end;
1320+
1321+
end:
1322+
mutex_unlock(&dev->thc_bus_lock);
1323+
1324+
if (ret)
1325+
dev_err_once(dev->dev, "Read THC I2C SubIP register failed %d, offset %u\n",
1326+
ret, address);
1327+
1328+
return ret;
1329+
}
1330+
1331+
static int thc_i2c_subip_pio_write(struct thc_device *dev, const u32 address,
1332+
const u32 size, const u32 *buffer)
1333+
{
1334+
int ret;
1335+
1336+
if (size == 0 || !buffer) {
1337+
dev_err(dev->dev, "Invalid input parameters, size %u, buffer %p\n",
1338+
size, buffer);
1339+
return -EINVAL;
1340+
}
1341+
1342+
if (mutex_lock_interruptible(&dev->thc_bus_lock))
1343+
return -EINTR;
1344+
1345+
ret = prepare_pio(dev, THC_PIO_OP_I2C_SUBSYSTEM_WRITE, address, size);
1346+
if (ret < 0)
1347+
goto end;
1348+
1349+
pio_start(dev, size, buffer);
1350+
1351+
ret = pio_wait(dev);
1352+
if (ret < 0)
1353+
goto end;
1354+
1355+
ret = pio_complete(dev, NULL, NULL);
1356+
if (ret < 0)
1357+
goto end;
1358+
1359+
end:
1360+
mutex_unlock(&dev->thc_bus_lock);
1361+
1362+
if (ret)
1363+
dev_err_once(dev->dev, "Write THC I2C SubIP register failed %d, offset %u\n",
1364+
ret, address);
1365+
1366+
return ret;
1367+
}
1368+
1369+
#define I2C_SUBIP_CON_DEFAULT 0x663
1370+
#define I2C_SUBIP_INT_MASK_DEFAULT 0x7FFF
1371+
#define I2C_SUBIP_RX_TL_DEFAULT 62
1372+
#define I2C_SUBIP_TX_TL_DEFAULT 0
1373+
#define I2C_SUBIP_DMA_TDLR_DEFAULT 7
1374+
#define I2C_SUBIP_DMA_RDLR_DEFAULT 7
1375+
1376+
static int thc_i2c_subip_set_speed(struct thc_device *dev, const u32 speed,
1377+
const u32 hcnt, const u32 lcnt)
1378+
{
1379+
u32 hcnt_offset, lcnt_offset;
1380+
u32 val;
1381+
int ret;
1382+
1383+
switch (speed) {
1384+
case THC_I2C_STANDARD:
1385+
hcnt_offset = THC_I2C_IC_SS_SCL_HCNT_OFFSET;
1386+
lcnt_offset = THC_I2C_IC_SS_SCL_LCNT_OFFSET;
1387+
break;
1388+
1389+
case THC_I2C_FAST_AND_PLUS:
1390+
hcnt_offset = THC_I2C_IC_FS_SCL_HCNT_OFFSET;
1391+
lcnt_offset = THC_I2C_IC_FS_SCL_LCNT_OFFSET;
1392+
break;
1393+
1394+
case THC_I2C_HIGH_SPEED:
1395+
hcnt_offset = THC_I2C_IC_HS_SCL_HCNT_OFFSET;
1396+
lcnt_offset = THC_I2C_IC_HS_SCL_LCNT_OFFSET;
1397+
break;
1398+
1399+
default:
1400+
dev_err_once(dev->dev, "Unsupported i2c speed %d\n", speed);
1401+
ret = -EINVAL;
1402+
return ret;
1403+
}
1404+
1405+
ret = thc_i2c_subip_pio_write(dev, hcnt_offset, sizeof(u32), &hcnt);
1406+
if (ret < 0)
1407+
return ret;
1408+
1409+
ret = thc_i2c_subip_pio_write(dev, lcnt_offset, sizeof(u32), &lcnt);
1410+
if (ret < 0)
1411+
return ret;
1412+
1413+
val = I2C_SUBIP_CON_DEFAULT & ~THC_I2C_IC_CON_SPEED;
1414+
val |= FIELD_PREP(THC_I2C_IC_CON_SPEED, speed);
1415+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_CON_OFFSET, sizeof(u32), &val);
1416+
if (ret < 0)
1417+
return ret;
1418+
1419+
return 0;
1420+
}
1421+
1422+
static u32 i2c_subip_regs[] = {
1423+
THC_I2C_IC_CON_OFFSET,
1424+
THC_I2C_IC_TAR_OFFSET,
1425+
THC_I2C_IC_INTR_MASK_OFFSET,
1426+
THC_I2C_IC_RX_TL_OFFSET,
1427+
THC_I2C_IC_TX_TL_OFFSET,
1428+
THC_I2C_IC_DMA_CR_OFFSET,
1429+
THC_I2C_IC_DMA_TDLR_OFFSET,
1430+
THC_I2C_IC_DMA_RDLR_OFFSET,
1431+
THC_I2C_IC_SS_SCL_HCNT_OFFSET,
1432+
THC_I2C_IC_SS_SCL_LCNT_OFFSET,
1433+
THC_I2C_IC_FS_SCL_HCNT_OFFSET,
1434+
THC_I2C_IC_FS_SCL_LCNT_OFFSET,
1435+
THC_I2C_IC_HS_SCL_HCNT_OFFSET,
1436+
THC_I2C_IC_HS_SCL_LCNT_OFFSET,
1437+
THC_I2C_IC_ENABLE_OFFSET,
1438+
};
1439+
1440+
/**
1441+
* thc_i2c_subip_init - Initialize and configure THC I2C subsystem
1442+
*
1443+
* @dev: The pointer of THC private device context
1444+
* @target_address: Slave address of touch device (TIC)
1445+
* @speed: I2C bus frequency speed mode
1446+
* @hcnt: I2C clock SCL high count
1447+
* @lcnt: I2C clock SCL low count
1448+
*
1449+
* Return: 0 on success, other error codes on failed.
1450+
*/
1451+
int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
1452+
const u32 speed, const u32 hcnt, const u32 lcnt)
1453+
{
1454+
u32 read_size = sizeof(u32);
1455+
u32 val;
1456+
int ret;
1457+
1458+
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_ENABLE_OFFSET, &read_size, &val);
1459+
if (ret < 0)
1460+
return ret;
1461+
1462+
val &= ~THC_I2C_IC_ENABLE_ENABLE;
1463+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_ENABLE_OFFSET, sizeof(u32), &val);
1464+
if (ret < 0)
1465+
return ret;
1466+
1467+
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_TAR_OFFSET, &read_size, &val);
1468+
if (ret < 0)
1469+
return ret;
1470+
1471+
val &= ~THC_I2C_IC_TAR_IC_TAR;
1472+
val |= FIELD_PREP(THC_I2C_IC_TAR_IC_TAR, target_address);
1473+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_TAR_OFFSET, sizeof(u32), &val);
1474+
if (ret < 0)
1475+
return ret;
1476+
1477+
ret = thc_i2c_subip_set_speed(dev, speed, hcnt, lcnt);
1478+
if (ret < 0)
1479+
return ret;
1480+
1481+
val = I2C_SUBIP_INT_MASK_DEFAULT;
1482+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_INTR_MASK_OFFSET, sizeof(u32), &val);
1483+
if (ret < 0)
1484+
return ret;
1485+
1486+
val = I2C_SUBIP_RX_TL_DEFAULT;
1487+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_RX_TL_OFFSET, sizeof(u32), &val);
1488+
if (ret < 0)
1489+
return ret;
1490+
1491+
val = I2C_SUBIP_TX_TL_DEFAULT;
1492+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_TX_TL_OFFSET, sizeof(u32), &val);
1493+
if (ret < 0)
1494+
return ret;
1495+
1496+
val = THC_I2C_IC_DMA_CR_RDMAE | THC_I2C_IC_DMA_CR_TDMAE;
1497+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_DMA_CR_OFFSET, sizeof(u32), &val);
1498+
if (ret < 0)
1499+
return ret;
1500+
1501+
val = I2C_SUBIP_DMA_TDLR_DEFAULT;
1502+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_DMA_TDLR_OFFSET, sizeof(u32), &val);
1503+
if (ret < 0)
1504+
return ret;
1505+
1506+
val = I2C_SUBIP_DMA_RDLR_DEFAULT;
1507+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_DMA_RDLR_OFFSET, sizeof(u32), &val);
1508+
if (ret < 0)
1509+
return ret;
1510+
1511+
ret = thc_i2c_subip_pio_read(dev, THC_I2C_IC_ENABLE_OFFSET, &read_size, &val);
1512+
if (ret < 0)
1513+
return ret;
1514+
1515+
val |= THC_I2C_IC_ENABLE_ENABLE;
1516+
ret = thc_i2c_subip_pio_write(dev, THC_I2C_IC_ENABLE_OFFSET, sizeof(u32), &val);
1517+
if (ret < 0)
1518+
return ret;
1519+
1520+
dev->i2c_subip_regs = devm_kzalloc(dev->dev, sizeof(i2c_subip_regs), GFP_KERNEL);
1521+
if (!dev->i2c_subip_regs)
1522+
return PTR_ERR(dev->i2c_subip_regs);
1523+
1524+
return 0;
1525+
}
1526+
EXPORT_SYMBOL_NS_GPL(thc_i2c_subip_init, "INTEL_THC");
1527+
1528+
/**
1529+
* thc_i2c_subip_regs_save - Save THC I2C sub-subsystem register values to THC device context
1530+
*
1531+
* @dev: The pointer of THC private device context
1532+
*
1533+
* Return: 0 on success, other error codes on failed.
1534+
*/
1535+
int thc_i2c_subip_regs_save(struct thc_device *dev)
1536+
{
1537+
int ret;
1538+
u32 read_size = sizeof(u32);
1539+
1540+
for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) {
1541+
ret = thc_i2c_subip_pio_read(dev, i2c_subip_regs[i],
1542+
&read_size, (u32 *)&dev->i2c_subip_regs + i);
1543+
if (ret < 0)
1544+
return ret;
1545+
}
1546+
1547+
return 0;
1548+
}
1549+
EXPORT_SYMBOL_NS_GPL(thc_i2c_subip_regs_save, "INTEL_THC");
1550+
1551+
/**
1552+
* thc_i2c_subip_regs_restore - Restore THC I2C subsystem registers from THC device context
1553+
*
1554+
* @dev: The pointer of THC private device context
1555+
*
1556+
* Return: 0 on success, other error codes on failed.
1557+
*/
1558+
int thc_i2c_subip_regs_restore(struct thc_device *dev)
1559+
{
1560+
int ret;
1561+
u32 write_size = sizeof(u32);
1562+
1563+
for (int i = 0; i < ARRAY_SIZE(i2c_subip_regs); i++) {
1564+
ret = thc_i2c_subip_pio_write(dev, i2c_subip_regs[i],
1565+
write_size, (u32 *)&dev->i2c_subip_regs + i);
1566+
if (ret < 0)
1567+
return ret;
1568+
}
1569+
1570+
return 0;
1571+
}
1572+
EXPORT_SYMBOL_NS_GPL(thc_i2c_subip_regs_restore, "INTEL_THC");
1573+
12931574
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
12941575
MODULE_AUTHOR("Even Xu <[email protected]>");
12951576

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
@@ -61,6 +61,7 @@ enum thc_int_type {
6161
* @write_done: bool value that indicates if DMA write is done
6262
* @swdma_done: bool value that indicates if SWDMA swquence is done
6363
* @perf_limit: the delay between read operation and write operation
64+
* @i2c_subip_regs: the copy of THC I2C sub-system registers for resuming restore
6465
*/
6566
struct thc_device {
6667
struct device *dev;
@@ -78,6 +79,8 @@ struct thc_device {
7879
bool swdma_done;
7980

8081
u32 perf_limit;
82+
83+
u32 *i2c_subip_regs;
8184
};
8285

8386
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr);
@@ -105,5 +108,9 @@ int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val,
105108
u32 io_mode, u32 opcode, u32 spi_wr_mps, u32 perf_limit);
106109
void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr,
107110
u32 input_bdy_addr, u32 output_addr);
111+
int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
112+
const u32 speed, const u32 hcnt, const u32 lcnt);
113+
int thc_i2c_subip_regs_save(struct thc_device *dev);
114+
int thc_i2c_subip_regs_restore(struct thc_device *dev);
108115

109116
#endif /* _INTEL_THC_DEV_H_ */

0 commit comments

Comments
 (0)