stmpe811_base.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /****************************************************************************
  2. * drivers/input/stmpe811_base.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /* References:
  21. * "STMPE811 S-Touch advanced resistive touchscreen controller with 8-bit
  22. * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics"
  23. */
  24. /****************************************************************************
  25. * Included Files
  26. ****************************************************************************/
  27. #include <nuttx/config.h>
  28. #include <unistd.h>
  29. #include <assert.h>
  30. #include <errno.h>
  31. #include <debug.h>
  32. #include <nuttx/kmalloc.h>
  33. #include <nuttx/signal.h>
  34. #include <nuttx/input/stmpe811.h>
  35. #include "stmpe811.h"
  36. #if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811)
  37. /****************************************************************************
  38. * Private Data
  39. ****************************************************************************/
  40. /* If only a single STMPE811 device is supported, then the driver state
  41. * structure may as well be pre-allocated.
  42. */
  43. #ifndef CONFIG_STMPE811_MULTIPLE
  44. static struct stmpe811_dev_s g_stmpe811;
  45. /* Otherwise, we will need to maintain allocated driver instances in a list */
  46. #else
  47. static struct stmpe811_dev_s *g_stmpe811list;
  48. #endif
  49. /****************************************************************************
  50. * Private Functions
  51. ****************************************************************************/
  52. /****************************************************************************
  53. * Name: stmpe811_worker
  54. *
  55. * Description:
  56. * This is the "bottom half" of the STMPE811 interrupt handler
  57. *
  58. ****************************************************************************/
  59. static void stmpe811_worker(FAR void *arg)
  60. {
  61. FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg;
  62. uint8_t regval;
  63. DEBUGASSERT(priv && priv->config);
  64. /* Get the global interrupt status */
  65. regval = stmpe811_getreg8(priv, STMPE811_INT_STA);
  66. /* Check for a touchscreen interrupt */
  67. #ifndef CONFIG_STMPE811_TSC_DISABLE
  68. if ((regval & (INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW)) != 0)
  69. {
  70. /* Dispatch the touchscreen interrupt if it was brought into the link */
  71. #ifdef CONFIG_HAVE_WEAKFUNCTIONS
  72. if (stmpe811_tscworker)
  73. #endif
  74. {
  75. stmpe811_tscworker(priv, regval);
  76. }
  77. stmpe811_putreg8(priv, STMPE811_INT_STA,
  78. (INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW));
  79. regval &= ~(INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW);
  80. }
  81. #endif
  82. #if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE)
  83. if ((regval & INT_GPIO) != 0)
  84. {
  85. /* Dispatch the GPIO interrupt if it was brought into the link */
  86. #ifdef CONFIG_HAVE_WEAKFUNCTIONS
  87. if (stmpe811_gpioworker)
  88. #endif
  89. {
  90. stmpe811_gpioworker(priv);
  91. }
  92. stmpe811_putreg8(priv, STMPE811_INT_STA, INT_GPIO);
  93. regval &= ~INT_GPIO;
  94. }
  95. #endif
  96. /* Clear any other residual, unhandled pending interrupt */
  97. if (regval != 0)
  98. {
  99. stmpe811_putreg8(priv, STMPE811_INT_STA, regval);
  100. }
  101. /* Re-enable the STMPE811 GPIO interrupt */
  102. priv->config->enable(priv->config, true);
  103. }
  104. /****************************************************************************
  105. * Name: stmpe811_interrupt
  106. *
  107. * Description:
  108. * The STMPE811 interrupt handler
  109. *
  110. ****************************************************************************/
  111. static int stmpe811_interrupt(int irq, FAR void *context, FAR void *arg)
  112. {
  113. FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg;
  114. FAR struct stmpe811_config_s *config;
  115. int ret;
  116. DEBUGASSERT(priv != NULL && priv->config != NULL);
  117. config = priv->config;
  118. /* Disable further interrupts */
  119. config->enable(config, false);
  120. /* Check if interrupt work is already queue. If it is already busy, then
  121. * we already have interrupt processing in the pipeline and we need to do
  122. * nothing more.
  123. */
  124. if (work_available(&priv->work))
  125. {
  126. /* Yes.. Transfer processing to the worker thread. Since STMPE811
  127. * interrupts are disabled while the work is pending, no special
  128. * action should be required to protect the work queue.
  129. */
  130. ret = work_queue(HPWORK, &priv->work, stmpe811_worker, priv, 0);
  131. if (ret != 0)
  132. {
  133. ierr("ERROR: Failed to queue work: %d\n", ret);
  134. }
  135. }
  136. /* Clear any pending interrupts and return success */
  137. config->clear(config);
  138. return OK;
  139. }
  140. /****************************************************************************
  141. * Name: stmpe811_checkid
  142. *
  143. * Description:
  144. * Read and verify the STMPE811 chip ID
  145. *
  146. ****************************************************************************/
  147. static int stmpe811_checkid(FAR struct stmpe811_dev_s *priv)
  148. {
  149. uint16_t devid = 0;
  150. /* Read device ID */
  151. devid = stmpe811_getreg8(priv, STMPE811_CHIP_ID);
  152. devid = (uint32_t)(devid << 8);
  153. devid |= (uint32_t)stmpe811_getreg8(priv, STMPE811_CHIP_ID + 1);
  154. iinfo("devid: %04x\n", devid);
  155. if (devid != (uint16_t)CHIP_ID)
  156. {
  157. /* ID is not Correct */
  158. return -ENODEV;
  159. }
  160. return OK;
  161. }
  162. /****************************************************************************
  163. * Name: stmpe811_reset
  164. *
  165. * Description:
  166. * Reset the STMPE811
  167. *
  168. ****************************************************************************/
  169. static void stmpe811_reset(FAR struct stmpe811_dev_s *priv)
  170. {
  171. /* Power Down the STMPE811 */
  172. stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, SYS_CTRL1_SOFTRESET);
  173. /* Wait a bit */
  174. nxsig_usleep(20 * 1000);
  175. /* Then power on again. All registers will be in their reset state. */
  176. stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, 0);
  177. }
  178. /****************************************************************************
  179. * Public Functions
  180. ****************************************************************************/
  181. /****************************************************************************
  182. * Name: stmpe811_instantiate
  183. *
  184. * Description:
  185. * Instantiate and configure the STMPE811 device driver to use the provided
  186. * I2C or SPIdevice instance.
  187. *
  188. * Input Parameters:
  189. * dev - An I2C or SPI driver instance
  190. * config - Persistent board configuration data
  191. *
  192. * Returned Value:
  193. * A non-zero handle is returned on success. This handle may then be used
  194. * to configure the STMPE811 driver as necessary. A NULL handle value is
  195. * returned on failure.
  196. *
  197. ****************************************************************************/
  198. #ifdef CONFIG_STMPE811_SPI
  199. STMPE811_HANDLE stmpe811_instantiate(FAR struct spi_dev_s *dev,
  200. FAR struct stmpe811_config_s *config)
  201. #else
  202. STMPE811_HANDLE stmpe811_instantiate(FAR struct i2c_master_s *dev,
  203. FAR struct stmpe811_config_s *config)
  204. #endif
  205. {
  206. FAR struct stmpe811_dev_s *priv;
  207. uint8_t regval;
  208. int ret;
  209. /* Allocate the device state structure */
  210. #ifdef CONFIG_STMPE811_MULTIPLE
  211. priv = (FAR struct stmpe811_dev_s *)kmm_zalloc(
  212. sizeof(struct stmpe811_dev_s));
  213. if (!priv)
  214. {
  215. return NULL;
  216. }
  217. /* And save the device structure in the list of STMPE811 so that we can
  218. * find it later.
  219. */
  220. priv->flink = g_stmpe811list;
  221. g_stmpe811list = priv;
  222. #else
  223. /* Use the one-and-only STMPE811 driver instance */
  224. priv = &g_stmpe811;
  225. #endif
  226. /* Initialize the device state structure */
  227. nxsem_init(&priv->exclsem, 0, 1);
  228. priv->config = config;
  229. #ifdef CONFIG_STMPE811_SPI
  230. priv->spi = dev;
  231. #else
  232. priv->i2c = dev;
  233. #endif
  234. /* Read and verify the STMPE811 chip ID */
  235. ret = stmpe811_checkid(priv);
  236. if (ret < 0)
  237. {
  238. #ifdef CONFIG_STMPE811_MULTIPLE
  239. g_stmpe811list = priv->flink;
  240. kmm_free(priv);
  241. #endif
  242. return NULL;
  243. }
  244. /* Generate STMPE811 Software reset */
  245. stmpe811_reset(priv);
  246. /* Configure the interrupt output pin to generate interrupts on high or
  247. * low level.
  248. */
  249. regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL);
  250. #ifdef CONFIG_STMPE811_ACTIVELOW
  251. regval &= ~INT_CTRL_INT_POLARITY; /* Pin polarity: Active low / falling edge */
  252. #else
  253. regval |= INT_CTRL_INT_POLARITY; /* Pin polarity: Active high / rising edge */
  254. #endif
  255. #ifdef CONFIG_STMPE811_EDGE
  256. regval |= INT_CTRL_INT_TYPE; /* Edge interrupt */
  257. #else
  258. regval &= ~INT_CTRL_INT_TYPE; /* Level interrupt */
  259. #endif
  260. stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval);
  261. /* Attach the STMPE811 interrupt handler. */
  262. config->attach(config, stmpe811_interrupt, priv);
  263. /* Clear any pending interrupts */
  264. stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL);
  265. config->clear(config);
  266. config->enable(config, true);
  267. /* Enable global interrupts */
  268. regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL);
  269. regval |= INT_CTRL_GLOBAL_INT;
  270. stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval);
  271. /* Return our private data structure as an opaque handle */
  272. return (STMPE811_HANDLE)priv;
  273. }
  274. /****************************************************************************
  275. * Name: stmpe811_getreg8
  276. *
  277. * Description:
  278. * Read from an 8-bit STMPE811 register
  279. *
  280. ****************************************************************************/
  281. uint8_t stmpe811_getreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr)
  282. {
  283. /* 8-bit data read sequence:
  284. * i2c:
  285. * Start - I2C_Write_Address - STMPE811_Reg_Address -
  286. * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data - STOP
  287. * spi:
  288. * [STMPE811_Reg_Address | 0x80] - Dummy Address - Read Register
  289. */
  290. uint8_t regval;
  291. #ifdef CONFIG_STMPE811_I2C
  292. int ret;
  293. struct i2c_msg_s msg[2];
  294. /* Setup 8-bit STMPE811 address write message */
  295. msg[0].frequency = priv->config->frequency; /* I2C frequency */
  296. msg[0].addr = priv->config->address; /* 7-bit address */
  297. msg[0].flags = 0; /* Write transaction, beginning with START */
  298. msg[0].buffer = &regaddr; /* Transfer from this address */
  299. msg[0].length = 1; /* Send one byte following the address
  300. * (no STOP) */
  301. /* Set up the 8-bit STMPE811 data read message */
  302. msg[1].frequency = priv->config->frequency; /* I2C frequency */
  303. msg[1].addr = priv->config->address; /* 7-bit address */
  304. msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */
  305. msg[1].buffer = &regval; /* Transfer to this address */
  306. msg[1].length = 1; /* Receive one byte following the address
  307. * (then STOP) */
  308. /* Perform the transfer */
  309. ret = I2C_TRANSFER(priv->i2c, msg, 2);
  310. if (ret < 0)
  311. {
  312. ierr("ERROR: I2C_TRANSFER failed: %d\n", ret);
  313. return 0;
  314. }
  315. #else /* CONFIG_STMPE811_SPI */
  316. SPI_LOCK(priv->spi, true);
  317. SPI_SETMODE(priv->spi, SPIDEV_MODE0);
  318. SPI_SETBITS(priv->spi, 8);
  319. SPI_HWFEATURES(priv->spi, 0);
  320. SPI_SETFREQUENCY(priv->spi, priv->config->frequency);
  321. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true);
  322. SPI_SEND(priv->spi, regaddr | 0x80); /* Issue a read on the address */
  323. SPI_SEND(priv->spi, 0); /* Next address (not used) */
  324. regval = SPI_SEND(priv->spi, 0); /* Read register */
  325. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), false);
  326. SPI_LOCK(priv->spi, false);
  327. #endif
  328. #ifdef CONFIG_STMPE811_REGDEBUG
  329. _err("%02x->%02x\n", regaddr, regval);
  330. #endif
  331. return regval;
  332. }
  333. /****************************************************************************
  334. * Name: stmpe811_putreg8
  335. *
  336. * Description:
  337. * Write a value to an 8-bit STMPE811 register
  338. *
  339. ****************************************************************************/
  340. void stmpe811_putreg8(FAR struct stmpe811_dev_s *priv,
  341. uint8_t regaddr, uint8_t regval)
  342. {
  343. /* 8-bit data read sequence:
  344. *
  345. * Start - I2C_Write_Address - STMPE811_Reg_Address -
  346. * STMPE811_Write_Data - STOP
  347. * spi:
  348. * STMPE811_Reg_Address - Dummy Address - Write Data
  349. */
  350. #ifdef CONFIG_STMPE811_I2C
  351. int ret;
  352. struct i2c_msg_s msg;
  353. uint8_t txbuffer[2];
  354. #ifdef CONFIG_STMPE811_REGDEBUG
  355. _err("%02x<-%02x\n", regaddr, regval);
  356. #endif
  357. /* Setup to the data to be transferred. Two bytes: The STMPE811 register
  358. * address followed by one byte of data.
  359. */
  360. txbuffer[0] = regaddr;
  361. txbuffer[1] = regval;
  362. /* Setup 8-bit STMPE811 address write message */
  363. msg.frequency = priv->config->frequency; /* I2C frequency */
  364. msg.addr = priv->config->address; /* 7-bit address */
  365. msg.flags = 0; /* Write transaction, beginning with START */
  366. msg.buffer = txbuffer; /* Transfer from this address */
  367. msg.length = 2; /* Send two byte following the address
  368. * (then STOP) */
  369. /* Perform the transfer */
  370. ret = I2C_TRANSFER(priv->i2c, &msg, 1);
  371. if (ret < 0)
  372. {
  373. ierr("ERROR: I2C_TRANSFER failed: %d\n", ret);
  374. }
  375. #else /* CONFIG_STMPE811_SPI */
  376. SPI_LOCK(priv->spi, true);
  377. SPI_SETMODE(priv->spi, SPIDEV_MODE0);
  378. SPI_SETBITS(priv->spi, 8);
  379. SPI_HWFEATURES(priv->spi, 0);
  380. SPI_SETFREQUENCY(priv->spi, priv->config->frequency);
  381. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true);
  382. SPI_SEND(priv->spi, regaddr); /* Issue a read on the address */
  383. SPI_SEND(priv->spi, 0); /* Next address (not used) */
  384. SPI_SEND(priv->spi, regval); /* write register */
  385. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), false);
  386. SPI_LOCK(priv->spi, false);
  387. #endif
  388. }
  389. /****************************************************************************
  390. * Name: stmpe811_getreg16
  391. *
  392. * Description:
  393. * Read 16-bits of data from an STMPE-11 register
  394. *
  395. ****************************************************************************/
  396. uint16_t stmpe811_getreg16(FAR struct stmpe811_dev_s *priv, uint8_t regaddr)
  397. {
  398. /* 16-bit data read sequence:
  399. * i2c:
  400. * Start - I2C_Write_Address - STMPE811_Reg_Address -
  401. * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data_1 -
  402. * STMPE811_Read_Data_2 - STOP
  403. * spi:
  404. * 16 bit registers are MSB.
  405. * [STMPE811_Reg_Address | 0x80] - [STMPE811_Reg_Address + 1 | 0x80] -
  406. * Read Register - Read Register + 1
  407. */
  408. uint8_t rxbuffer[2];
  409. #ifdef CONFIG_STMPE811_I2C
  410. int ret;
  411. struct i2c_msg_s msg[2];
  412. /* Setup 8-bit STMPE811 address write message */
  413. msg[0].frequency = priv->config->frequency; /* I2C frequency */
  414. msg[0].addr = priv->config->address; /* 7-bit address */
  415. msg[0].flags = 0; /* Write transaction, beginning with START */
  416. msg[0].buffer = &regaddr; /* Transfer from this address */
  417. msg[0].length = 1; /* Send one byte following the address
  418. * (no STOP) */
  419. /* Set up the 8-bit STMPE811 data read message */
  420. msg[1].frequency = priv->config->frequency; /* I2C frequency */
  421. msg[1].addr = priv->config->address; /* 7-bit address */
  422. msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */
  423. msg[1].buffer = rxbuffer; /* Transfer to this address */
  424. msg[1].length = 2; /* Receive two bytes following the address
  425. * (then STOP) */
  426. /* Perform the transfer */
  427. ret = I2C_TRANSFER(priv->i2c, msg, 2);
  428. if (ret < 0)
  429. {
  430. ierr("ERROR: I2C_TRANSFER failed: %d\n", ret);
  431. return 0;
  432. }
  433. #else /* CONFIG_STMPE811_SPI */
  434. SPI_LOCK(priv->spi, true);
  435. SPI_SETMODE(priv->spi, SPIDEV_MODE0);
  436. SPI_SETBITS(priv->spi, 8);
  437. SPI_HWFEATURES(priv->spi, 0);
  438. SPI_SETFREQUENCY(priv->spi, priv->config->frequency);
  439. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true);
  440. SPI_SEND(priv->spi, regaddr | 0x80); /* Issue a read on the address */
  441. SPI_SEND(priv->spi, regaddr + 1); /* Next address */
  442. rxbuffer[0] = SPI_SEND(priv->spi, 0); /* Read MSB */
  443. rxbuffer[1] = SPI_SEND(priv->spi, 0); /* Read LSB */
  444. SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN(0), true);
  445. SPI_LOCK(priv->spi, false);
  446. #endif
  447. #ifdef CONFIG_STMPE811_REGDEBUG
  448. _err("%02x->%02x%02x\n", regaddr, rxbuffer[0], rxbuffer[1]);
  449. #endif
  450. return (uint16_t)rxbuffer[0] << 8 | (uint16_t)rxbuffer[1];
  451. }
  452. #endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 */