|
1 | 1 | /* SPDX-License-Identifier: GPL-2.0 */
|
2 | 2 | /* Copyright (c) 2024 Intel Corporation */
|
3 | 3 |
|
| 4 | +#include <linux/bitfield.h> |
4 | 5 | #include <linux/regmap.h>
|
5 | 6 |
|
6 | 7 | #include "intel-thc-dev.h"
|
| 8 | +#include "intel-thc-hw.h" |
7 | 9 |
|
8 | 10 | static int thc_regmap_read(void *context, unsigned int reg,
|
9 | 11 | unsigned int *val)
|
@@ -208,10 +210,253 @@ struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr)
|
208 | 210 |
|
209 | 211 | thc_clear_state(thc_dev);
|
210 | 212 |
|
| 213 | + mutex_init(&thc_dev->thc_bus_lock); |
| 214 | + |
211 | 215 | return thc_dev;
|
212 | 216 | }
|
213 | 217 | EXPORT_SYMBOL_NS_GPL(thc_dev_init, "INTEL_THC");
|
214 | 218 |
|
| 219 | +static int prepare_pio(const struct thc_device *dev, const u8 pio_op, |
| 220 | + const u32 address, const u32 size) |
| 221 | +{ |
| 222 | + u32 sts, ctrl, addr, mask; |
| 223 | + |
| 224 | + regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &sts); |
| 225 | + |
| 226 | + /* Check if THC previous PIO still in progress */ |
| 227 | + if (sts & THC_M_PRT_SW_SEQ_STS_THC_SS_CIP) { |
| 228 | + dev_err_once(dev->dev, "THC PIO is still busy!\n"); |
| 229 | + return -EBUSY; |
| 230 | + } |
| 231 | + |
| 232 | + /* Clear error bit and complete bit in state register */ |
| 233 | + sts |= THC_M_PRT_SW_SEQ_STS_THC_SS_ERR | |
| 234 | + THC_M_PRT_SW_SEQ_STS_TSSDONE; |
| 235 | + regmap_write(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, sts); |
| 236 | + |
| 237 | + /* Set PIO data size, opcode and interrupt capability */ |
| 238 | + ctrl = FIELD_PREP(THC_M_PRT_SW_SEQ_CNTRL_THC_SS_BC, size) | |
| 239 | + FIELD_PREP(THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CMD, pio_op); |
| 240 | + if (dev->pio_int_supported) |
| 241 | + ctrl |= THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CD_IE; |
| 242 | + |
| 243 | + mask = THC_M_PRT_SW_SEQ_CNTRL_THC_SS_BC | |
| 244 | + THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CMD | |
| 245 | + THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CD_IE; |
| 246 | + regmap_write_bits(dev->thc_regmap, |
| 247 | + THC_M_PRT_SW_SEQ_CNTRL_OFFSET, mask, ctrl); |
| 248 | + |
| 249 | + /* Set PIO target address */ |
| 250 | + addr = FIELD_PREP(THC_M_PRT_SW_SEQ_DATA0_ADDR_THC_SW_SEQ_DATA0_ADDR, address); |
| 251 | + mask = THC_M_PRT_SW_SEQ_DATA0_ADDR_THC_SW_SEQ_DATA0_ADDR; |
| 252 | + regmap_write_bits(dev->thc_regmap, |
| 253 | + THC_M_PRT_SW_SEQ_DATA0_ADDR_OFFSET, mask, addr); |
| 254 | + return 0; |
| 255 | +} |
| 256 | + |
| 257 | +static void pio_start(const struct thc_device *dev, |
| 258 | + u32 size_in_bytes, const u32 *buffer) |
| 259 | +{ |
| 260 | + if (size_in_bytes && buffer) |
| 261 | + regmap_bulk_write(dev->thc_regmap, THC_M_PRT_SW_SEQ_DATA1_OFFSET, |
| 262 | + buffer, size_in_bytes / sizeof(u32)); |
| 263 | + |
| 264 | + /* Enable Start bit */ |
| 265 | + regmap_write_bits(dev->thc_regmap, |
| 266 | + THC_M_PRT_SW_SEQ_CNTRL_OFFSET, |
| 267 | + THC_M_PRT_SW_SEQ_CNTRL_TSSGO, |
| 268 | + THC_M_PRT_SW_SEQ_CNTRL_TSSGO); |
| 269 | +} |
| 270 | + |
| 271 | +static int pio_complete(const struct thc_device *dev, |
| 272 | + u32 *buffer, u32 *size) |
| 273 | +{ |
| 274 | + u32 sts, ctrl; |
| 275 | + |
| 276 | + regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &sts); |
| 277 | + if (sts & THC_M_PRT_SW_SEQ_STS_THC_SS_ERR) { |
| 278 | + dev_err_once(dev->dev, "PIO operation error\n"); |
| 279 | + return -EBUSY; |
| 280 | + } |
| 281 | + |
| 282 | + if (buffer && size) { |
| 283 | + regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_CNTRL_OFFSET, &ctrl); |
| 284 | + *size = FIELD_GET(THC_M_PRT_SW_SEQ_CNTRL_THC_SS_BC, ctrl); |
| 285 | + |
| 286 | + regmap_bulk_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_DATA1_OFFSET, |
| 287 | + buffer, *size / sizeof(u32)); |
| 288 | + } |
| 289 | + |
| 290 | + sts |= THC_M_PRT_SW_SEQ_STS_THC_SS_ERR | THC_M_PRT_SW_SEQ_STS_TSSDONE; |
| 291 | + regmap_write(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, sts); |
| 292 | + return 0; |
| 293 | +} |
| 294 | + |
| 295 | +static int pio_wait(const struct thc_device *dev) |
| 296 | +{ |
| 297 | + u32 sts = 0; |
| 298 | + int ret; |
| 299 | + |
| 300 | + ret = regmap_read_poll_timeout(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, sts, |
| 301 | + !(sts & THC_M_PRT_SW_SEQ_STS_THC_SS_CIP || |
| 302 | + !(sts & THC_M_PRT_SW_SEQ_STS_TSSDONE)), |
| 303 | + THC_REGMAP_POLLING_INTERVAL_US, THC_PIO_DONE_TIMEOUT_US); |
| 304 | + if (ret) |
| 305 | + dev_err_once(dev->dev, "Timeout while polling PIO operation done\n"); |
| 306 | + |
| 307 | + return ret; |
| 308 | +} |
| 309 | + |
| 310 | +/** |
| 311 | + * thc_tic_pio_read - Read data from touch device by PIO |
| 312 | + * |
| 313 | + * @dev: The pointer of THC private device context |
| 314 | + * @address: Slave address for the PIO operation |
| 315 | + * @size: Expected read data size |
| 316 | + * @actual_size: The pointer of the actual data size read from touch device |
| 317 | + * @buffer: The pointer of data buffer to store the data read from touch device |
| 318 | + * |
| 319 | + * Return: 0 on success, other error codes on failed. |
| 320 | + */ |
| 321 | +int thc_tic_pio_read(struct thc_device *dev, const u32 address, |
| 322 | + const u32 size, u32 *actual_size, u32 *buffer) |
| 323 | +{ |
| 324 | + u8 opcode; |
| 325 | + int ret; |
| 326 | + |
| 327 | + if (size <= 0 || !actual_size || !buffer) { |
| 328 | + dev_err(dev->dev, "Invalid input parameters, size %u, actual_size %p, buffer %p\n", |
| 329 | + size, actual_size, buffer); |
| 330 | + return -EINVAL; |
| 331 | + } |
| 332 | + |
| 333 | + if (mutex_lock_interruptible(&dev->thc_bus_lock)) |
| 334 | + return -EINTR; |
| 335 | + |
| 336 | + opcode = (dev->port_type == THC_PORT_TYPE_SPI) ? |
| 337 | + THC_PIO_OP_SPI_TIC_READ : THC_PIO_OP_I2C_TIC_READ; |
| 338 | + |
| 339 | + ret = prepare_pio(dev, opcode, address, size); |
| 340 | + if (ret < 0) |
| 341 | + goto end; |
| 342 | + |
| 343 | + pio_start(dev, 0, NULL); |
| 344 | + |
| 345 | + ret = pio_wait(dev); |
| 346 | + if (ret < 0) |
| 347 | + goto end; |
| 348 | + |
| 349 | + ret = pio_complete(dev, buffer, actual_size); |
| 350 | + |
| 351 | +end: |
| 352 | + mutex_unlock(&dev->thc_bus_lock); |
| 353 | + return ret; |
| 354 | +} |
| 355 | +EXPORT_SYMBOL_NS_GPL(thc_tic_pio_read, "INTEL_THC"); |
| 356 | + |
| 357 | +/** |
| 358 | + * thc_tic_pio_write - Write data to touch device by PIO |
| 359 | + * |
| 360 | + * @dev: The pointer of THC private device context |
| 361 | + * @address: Slave address for the PIO operation |
| 362 | + * @size: PIO write data size |
| 363 | + * @buffer: The pointer of the write data buffer |
| 364 | + * |
| 365 | + * Return: 0 on success, other error codes on failed. |
| 366 | + */ |
| 367 | +int thc_tic_pio_write(struct thc_device *dev, const u32 address, |
| 368 | + const u32 size, const u32 *buffer) |
| 369 | +{ |
| 370 | + u8 opcode; |
| 371 | + int ret; |
| 372 | + |
| 373 | + if (size <= 0 || !buffer) { |
| 374 | + dev_err(dev->dev, "Invalid input parameters, size %u, buffer %p\n", |
| 375 | + size, buffer); |
| 376 | + return -EINVAL; |
| 377 | + } |
| 378 | + |
| 379 | + if (mutex_lock_interruptible(&dev->thc_bus_lock)) |
| 380 | + return -EINTR; |
| 381 | + |
| 382 | + opcode = (dev->port_type == THC_PORT_TYPE_SPI) ? |
| 383 | + THC_PIO_OP_SPI_TIC_WRITE : THC_PIO_OP_I2C_TIC_WRITE; |
| 384 | + |
| 385 | + ret = prepare_pio(dev, opcode, address, size); |
| 386 | + if (ret < 0) |
| 387 | + goto end; |
| 388 | + |
| 389 | + pio_start(dev, size, buffer); |
| 390 | + |
| 391 | + ret = pio_wait(dev); |
| 392 | + if (ret < 0) |
| 393 | + goto end; |
| 394 | + |
| 395 | + ret = pio_complete(dev, NULL, NULL); |
| 396 | + |
| 397 | +end: |
| 398 | + mutex_unlock(&dev->thc_bus_lock); |
| 399 | + return ret; |
| 400 | +} |
| 401 | +EXPORT_SYMBOL_NS_GPL(thc_tic_pio_write, "INTEL_THC"); |
| 402 | + |
| 403 | +/** |
| 404 | + * thc_tic_pio_write_and_read - Write data followed by read data by PIO |
| 405 | + * |
| 406 | + * @dev: The pointer of THC private device context |
| 407 | + * @address: Slave address for the PIO operation |
| 408 | + * @write_size: PIO write data size |
| 409 | + * @write_buffer: The pointer of the write data buffer |
| 410 | + * @read_size: Expected PIO read data size |
| 411 | + * @actual_size: The pointer of the actual read data size |
| 412 | + * @read_buffer: The pointer of PIO read data buffer |
| 413 | + * |
| 414 | + * Return: 0 on success, other error codes on failed. |
| 415 | + */ |
| 416 | +int thc_tic_pio_write_and_read(struct thc_device *dev, const u32 address, |
| 417 | + const u32 write_size, const u32 *write_buffer, |
| 418 | + const u32 read_size, u32 *actual_size, u32 *read_buffer) |
| 419 | +{ |
| 420 | + u32 i2c_ctrl, mask; |
| 421 | + int ret; |
| 422 | + |
| 423 | + if (dev->port_type == THC_PORT_TYPE_SPI) { |
| 424 | + dev_err(dev->dev, "SPI port type doesn't support pio write and read!"); |
| 425 | + return -EINVAL; |
| 426 | + } |
| 427 | + |
| 428 | + if (mutex_lock_interruptible(&dev->thc_bus_lock)) |
| 429 | + return -EINTR; |
| 430 | + |
| 431 | + /* Config i2c PIO write and read sequence */ |
| 432 | + i2c_ctrl = FIELD_PREP(THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_PIO_I2C_WBC, write_size); |
| 433 | + mask = THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_PIO_I2C_WBC; |
| 434 | + |
| 435 | + regmap_write_bits(dev->thc_regmap, THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_OFFSET, |
| 436 | + mask, i2c_ctrl); |
| 437 | + |
| 438 | + regmap_write_bits(dev->thc_regmap, THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_OFFSET, |
| 439 | + THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_I2C_RW_PIO_EN, |
| 440 | + THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_I2C_RW_PIO_EN); |
| 441 | + |
| 442 | + ret = prepare_pio(dev, THC_PIO_OP_I2C_TIC_WRITE_AND_READ, address, read_size); |
| 443 | + if (ret < 0) |
| 444 | + goto end; |
| 445 | + |
| 446 | + pio_start(dev, write_size, write_buffer); |
| 447 | + |
| 448 | + ret = pio_wait(dev); |
| 449 | + if (ret < 0) |
| 450 | + goto end; |
| 451 | + |
| 452 | + ret = pio_complete(dev, read_buffer, actual_size); |
| 453 | + |
| 454 | +end: |
| 455 | + mutex_unlock(&dev->thc_bus_lock); |
| 456 | + return ret; |
| 457 | +} |
| 458 | +EXPORT_SYMBOL_NS_GPL(thc_tic_pio_write_and_read, "INTEL_THC"); |
| 459 | + |
215 | 460 | MODULE_AUTHOR( "Xinpeng Sun <[email protected]>");
|
216 | 461 | MODULE_AUTHOR( "Even Xu <[email protected]>");
|
217 | 462 |
|
|
0 commit comments