ft80x.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  1. /****************************************************************************
  2. * drivers/lcd/ft80x.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. * - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet
  22. * Version 1.1, Clearance No.: FTDI# 334, Future Technology Devices
  23. * International Ltd.
  24. * - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet",
  25. * Version 1.0, Clearance No.: FTDI#376, Future Technology Devices
  26. * International Ltd.
  27. * - Application Note AN_240AN_240, "FT800 From the Ground Up", Version
  28. * 1.1, Issue Date: 2014-06-09, Future Technology Devices International
  29. * Ltd.
  30. * - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date:
  31. * 2016-09-19, Future Technology Devices International Ltd.
  32. */
  33. /****************************************************************************
  34. * Included Files
  35. ****************************************************************************/
  36. #include <nuttx/config.h>
  37. #include <sys/types.h>
  38. #include <stdint.h>
  39. #include <stdbool.h>
  40. #include <string.h>
  41. #include <assert.h>
  42. #include <errno.h>
  43. #include <debug.h>
  44. #include <nuttx/arch.h>
  45. #include <nuttx/semaphore.h>
  46. #include <nuttx/kmalloc.h>
  47. #include <nuttx/clock.h>
  48. #include <nuttx/wqueue.h>
  49. #include <nuttx/fs/fs.h>
  50. #include <nuttx/i2c/i2c_master.h>
  51. #include <nuttx/spi/spi.h>
  52. #include <nuttx/lcd/lcd.h>
  53. #include <nuttx/lcd/ft80x.h>
  54. #include <arch/irq.h>
  55. #include "ft80x.h"
  56. #ifdef CONFIG_LCD_FT80X
  57. /****************************************************************************
  58. * Pre-processor Definitions
  59. ****************************************************************************/
  60. #define CHIPID 0x7c
  61. #define ROMID_MASK 0x0000ffff
  62. #define VERSION_MASK 0xffff0000
  63. #if defined(CONFIG_LCD_FT800)
  64. # define DEVNAME "/dev/ft800"
  65. # define ROM_CHIPID 0x00010008 /* Byte [0:1] Chip ID "0800" BCD
  66. * Byte [2:3] Version "0100" BCD */
  67. #elif defined(CONFIG_LCD_FT801)
  68. # define DEVNAME "/dev/ft801"
  69. # define ROM_CHIPID 0x00010108 /* Byte [0:1] Chip ID "0801" BCD
  70. * Byte [2:3] Version "0100" BCD */
  71. #else
  72. # error No FT80x device configured
  73. #endif
  74. #define ROMID (ROM_CHIPID & ROMID_MASK)
  75. #define VERSION (ROM_CHIPID & VERSION_MASK)
  76. #define MIN_FADE_DELAY 10 /* Milliseconds */
  77. #define MAX_FADE_DELAY 16700 /* Milliseconds */
  78. #define FADE_STEP_MSEC 10 /* Milliseconds */
  79. /****************************************************************************
  80. * Private Function Prototypes
  81. ****************************************************************************/
  82. static int ft80x_fade(FAR struct ft80x_dev_s *priv,
  83. FAR const struct ft80x_fade_s *fade);
  84. static void ft80x_notify(FAR struct ft80x_dev_s *priv,
  85. enum ft80x_notify_e id, int value);
  86. static void ft80x_interrupt_work(FAR void *arg);
  87. static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg);
  88. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  89. static void ft80x_destroy(FAR struct ft80x_dev_s *priv);
  90. #endif
  91. /* Character driver methods */
  92. static int ft80x_open(FAR struct file *filep);
  93. static int ft80x_close(FAR struct file *filep);
  94. static ssize_t ft80x_read(FAR struct file *filep, FAR char *buffer,
  95. size_t buflen);
  96. static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
  97. size_t buflen);
  98. static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
  99. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  100. static int ft80x_unlink(FAR struct inode *inode);
  101. #endif
  102. /* Initialization */
  103. static int ft80x_initialize(FAR struct ft80x_dev_s *priv);
  104. /****************************************************************************
  105. * Private Data
  106. ****************************************************************************/
  107. static const struct file_operations g_ft80x_fops =
  108. {
  109. ft80x_open, /* open */
  110. ft80x_close, /* close */
  111. ft80x_read, /* read */
  112. ft80x_write, /* write */
  113. NULL, /* seek */
  114. ft80x_ioctl, /* ioctl */
  115. NULL /* poll */
  116. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  117. , ft80x_unlink /* unlink */
  118. #endif
  119. };
  120. /****************************************************************************
  121. * Private Functions
  122. ****************************************************************************/
  123. /****************************************************************************
  124. * Name: ft80x_forcetake
  125. *
  126. * Description:
  127. * This is a wrapper around but nxsem_wait_uninterruptible(). The wrapper
  128. * continues to wait even if the thread is canceled. This must be done in
  129. * certain conditions where were must continue in order to clean-up
  130. * resources.
  131. *
  132. ****************************************************************************/
  133. static void ft80x_forcetake(FAR sem_t *sem)
  134. {
  135. int ret;
  136. do
  137. {
  138. ret = nxsem_wait_uninterruptible(sem);
  139. /* The only expected error would -ECANCELED meaning that the
  140. * parent thread has been canceled. We have to continue and
  141. * terminate the poll in this case.
  142. */
  143. DEBUGASSERT(ret == OK || ret == -ECANCELED);
  144. }
  145. while (ret < 0);
  146. }
  147. /****************************************************************************
  148. * Name: ft80x_fade
  149. *
  150. * Description:
  151. * Change the backlight intensity with a controllable fade.
  152. *
  153. ****************************************************************************/
  154. static int ft80x_fade(FAR struct ft80x_dev_s *priv,
  155. FAR const struct ft80x_fade_s *fade)
  156. {
  157. clock_t start;
  158. clock_t elapsed;
  159. int32_t delay;
  160. int32_t duty;
  161. int16_t endduty;
  162. int16_t delta;
  163. /* 0% corresponds to the value 0, but 100% corresponds to the value 128 */
  164. endduty = (uint16_t)((uint16_t)fade->duty << 7) / 100;
  165. /* Get the change in duty from the current to the terminal duty. */
  166. duty = (int32_t)(ft80x_read_byte(priv, FT80X_REG_PWM_DUTY) & 0x7f);
  167. delta = endduty - (int16_t)duty;
  168. /* The "smoothness" of the steps will depend on the resolution of the
  169. * system timer. The minimum delay is <= 2 * system_clock_period.
  170. *
  171. * We will try for a FADE_STEP_MSEC delay, but we will try to adapt to
  172. * whatever we get is we are working close the system time resolution.
  173. * For human factors reasons, any delay less than 100 MS or so should
  174. * appear more or less smooth.
  175. *
  176. * The delay calculation should never overflow:
  177. *
  178. * Max delay: 16,700 msec (MAX_FADE_DELAY)
  179. * Min clock period: 1 usec
  180. * Max delay: 16,700,000 ticks
  181. * INT32_MAX 2,147,483,647
  182. */
  183. delay = MSEC2TICK((int32_t)fade->delay);
  184. if (delay <= 0)
  185. {
  186. delay = 1;
  187. }
  188. start = clock_systime_ticks();
  189. do
  190. {
  191. /* Wait for FADE_STEP_MSEC msec (or whatever we get) */
  192. nxsig_usleep(FADE_STEP_MSEC * 1000);
  193. /* Get the elapsed time */
  194. elapsed = clock_systime_ticks() - start;
  195. if (elapsed > INT32_MAX || (int32_t)elapsed >= delay)
  196. {
  197. duty = endduty;
  198. }
  199. else
  200. {
  201. /* Interpolate to get the next PWM duty in the fade. This
  202. * calculation should never overflow:
  203. *
  204. * Max delta: 128
  205. * Max elapsed: 16,700,000 ticks
  206. * Max numerator: 2,137,600,000
  207. * Min denominator: 1
  208. * Max duty: 2,137,600,000
  209. * INT32_MAX 2,147,483,647
  210. */
  211. duty += ((int32_t)delta * (int32_t)elapsed) / delay;
  212. if (duty > 128)
  213. {
  214. duty = 128;
  215. }
  216. else if (duty < 0)
  217. {
  218. duty = 0;
  219. }
  220. }
  221. /* The set the new backlight PWM duty */
  222. ft80x_write_byte(priv, FT80X_REG_PWM_DUTY, (uint8_t)duty);
  223. }
  224. while (duty != endduty);
  225. return OK;
  226. }
  227. /****************************************************************************
  228. * Name: ft80x_notify
  229. *
  230. * Description:
  231. * Notify any registered client of the FT80x event
  232. *
  233. ****************************************************************************/
  234. static void ft80x_notify(FAR struct ft80x_dev_s *priv,
  235. enum ft80x_notify_e id, int value)
  236. {
  237. FAR struct ft80x_eventinfo_s *info = &priv->notify[id];
  238. /* Are notifications enabled for this event? */
  239. if (info->enable)
  240. {
  241. DEBUGASSERT(info->pid > 0);
  242. /* Yes.. Signal the client */
  243. info->event.sigev_value.sival_int = value;
  244. nxsig_notification(info->pid, &info->event, SI_QUEUE, &info->work);
  245. }
  246. }
  247. /****************************************************************************
  248. * Name: ft80x_interrupt_work
  249. *
  250. * Description:
  251. * Back end handling for FT80x interrupts
  252. *
  253. ****************************************************************************/
  254. static void ft80x_interrupt_work(FAR void *arg)
  255. {
  256. FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
  257. uint32_t intflags;
  258. uint32_t regval;
  259. DEBUGASSERT(priv != NULL);
  260. /* Get exclusive access to the device structures */
  261. ft80x_forcetake(&priv->exclsem);
  262. /* Get the set of pending interrupts. Note that simply reading this
  263. * register is sufficient to clear all pending interrupts.
  264. */
  265. intflags = ft80x_read_word(priv, FT80X_REG_INT_FLAGS);
  266. /* And process each pending interrupt.
  267. *
  268. * REVISIT: No interrupt sources are ever enabled in the current
  269. * implementation.
  270. */
  271. if ((intflags & FT80X_INT_SWAP) != 0)
  272. {
  273. /* Display swap occurred */
  274. lcdinfo("Display swap occurred\n");
  275. ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
  276. }
  277. if ((intflags & FT80X_INT_TOUCH) != 0)
  278. {
  279. /* Touch-screen touch detected */
  280. lcdinfo("Touch-screen touch detected\n");
  281. ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
  282. }
  283. if ((intflags & FT80X_INT_TAG) != 0)
  284. {
  285. /* Touch-screen tag value change */
  286. lcdinfo("Touch-screen tag value change\n");
  287. #ifdef CONFIG_LCD_FT800
  288. regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
  289. #else
  290. regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
  291. #endif
  292. ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
  293. }
  294. if ((intflags & FT80X_INT_SOUND) != 0)
  295. {
  296. /* Sound effect ended */
  297. lcdinfo(" Sound effect ended\n");
  298. ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
  299. }
  300. if ((intflags & FT80X_INT_PLAYBACK) != 0)
  301. {
  302. /* Audio playback ended */
  303. lcdinfo("Audio playback ended\n");
  304. ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
  305. }
  306. if ((intflags & FT80X_INT_CMDEMPTY) != 0)
  307. {
  308. /* Command FIFO empty */
  309. lcdinfo("Command FIFO empty\n");
  310. ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
  311. }
  312. if ((intflags & FT80X_INT_CMDFLAG) != 0)
  313. {
  314. /* Command FIFO flag */
  315. lcdinfo("Command FIFO flag\n");
  316. ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
  317. }
  318. if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
  319. {
  320. /* Touch-screen conversions completed */
  321. lcdinfo(" Touch-screen conversions completed\n");
  322. ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
  323. }
  324. /* Re-enable interrupts */
  325. DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
  326. priv->lower->enable(priv->lower, true);
  327. nxsem_post(&priv->exclsem);
  328. }
  329. /****************************************************************************
  330. * Name: ft80x_interrupt
  331. *
  332. * Description:
  333. * FT80x interrupt handler
  334. *
  335. ****************************************************************************/
  336. static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg)
  337. {
  338. FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
  339. DEBUGASSERT(priv != NULL);
  340. /* Perform the interrupt work on the high priority work queue. */
  341. work_queue(HPWORK, &priv->intwork, ft80x_interrupt_work, priv, 0);
  342. /* Disable further interrupts for the GPIO interrupt source.
  343. * REVISIT: This assumes that GPIO interrupts will pend until re-enabled.
  344. * In certain implementations, that assumption is not true and could cause
  345. * a loss of interrupts.
  346. */
  347. DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
  348. priv->lower->enable(priv->lower, false);
  349. return OK;
  350. }
  351. /****************************************************************************
  352. * Name: ft80x_destroy
  353. *
  354. * Description:
  355. * The driver has been unlinked... clean up as best we can.
  356. *
  357. ****************************************************************************/
  358. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  359. static void ft80x_destroy(FAR struct ft80x_dev_s *priv)
  360. {
  361. /* If the lower half driver provided a destroy method, then call that
  362. * method now in order order to clean up resources used by the lower-half
  363. * driver.
  364. */
  365. DEBUGASSERT(priv != NULL && priv->lower != NULL);
  366. if (priv->lower->destroy != NULL)
  367. {
  368. priv->lower->destroy(priv->lower);
  369. }
  370. /* Then free our container */
  371. nxsem_destroy(&priv->exclsem);
  372. kmm_free(priv);
  373. }
  374. #endif
  375. /****************************************************************************
  376. * Name: ft80x_open
  377. *
  378. * Description:
  379. * This function is called whenever the PWM device is opened.
  380. *
  381. ****************************************************************************/
  382. static int ft80x_open(FAR struct file *filep)
  383. {
  384. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  385. FAR struct inode *inode;
  386. FAR struct ft80x_dev_s *priv;
  387. uint8_t tmp;
  388. int ret;
  389. DEBUGASSERT(filep != NULL);
  390. inode = filep->f_inode;
  391. DEBUGASSERT(inode != NULL && inode->i_private != NULL);
  392. priv = inode->i_private;
  393. lcdinfo("crefs: %d\n", priv->crefs);
  394. /* Get exclusive access to the device structures */
  395. ret = nxsem_wait(&priv->exclsem);
  396. if (ret < 0)
  397. {
  398. goto errout;
  399. }
  400. /* Increment the count of references to the device */
  401. tmp = priv->crefs + 1;
  402. if (tmp == 0)
  403. {
  404. /* More than 255 opens; uint8_t overflows to zero */
  405. ret = -EMFILE;
  406. goto errout_with_sem;
  407. }
  408. /* Save the new open count */
  409. priv->crefs = tmp;
  410. ret = OK;
  411. errout_with_sem:
  412. nxsem_post(&priv->exclsem);
  413. errout:
  414. return ret;
  415. #else
  416. return OK;
  417. #endif
  418. }
  419. /****************************************************************************
  420. * Name: ft80x_close
  421. *
  422. * Description:
  423. * This function is called when the PWM device is closed.
  424. *
  425. ****************************************************************************/
  426. static int ft80x_close(FAR struct file *filep)
  427. {
  428. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  429. FAR struct inode *inode;
  430. FAR struct ft80x_dev_s *priv;
  431. int ret;
  432. DEBUGASSERT(filep != NULL);
  433. inode = filep->f_inode;
  434. DEBUGASSERT(inode != NULL && inode->i_private != NULL);
  435. priv = inode->i_private;
  436. lcdinfo("crefs: %d\n", priv->crefs);
  437. /* Get exclusive access to the device structures */
  438. ret = nxsem_wait(&priv->exclsem);
  439. if (ret < 0)
  440. {
  441. goto errout;
  442. }
  443. /* Will the count decrement to zero? */
  444. if (priv->crefs <= 1)
  445. {
  446. /* Yes.. if the driver has been unlinked, then we need to destroy the
  447. * driver instance.
  448. */
  449. priv->crefs = 0;
  450. if (priv->unlinked)
  451. {
  452. ft80x_destroy(priv);
  453. return OK;
  454. }
  455. }
  456. else
  457. {
  458. /* NO.. decrement the number of references to the driver. */
  459. priv->crefs--;
  460. }
  461. ret = OK;
  462. nxsem_post(&priv->exclsem);
  463. errout:
  464. return ret;
  465. #else
  466. return OK;
  467. #endif
  468. }
  469. /****************************************************************************
  470. * Name: ft80x_read
  471. ****************************************************************************/
  472. static ssize_t ft80x_read(FAR struct file *filep, FAR char *buffer,
  473. size_t len)
  474. {
  475. /* Reading from the FT80X is an undefined operation and not support */
  476. lcdinfo("buffer: %p len %lu\n", buffer, (unsigned long)len);
  477. return 0; /* Return EOF */
  478. }
  479. /****************************************************************************
  480. * Name: ft80x_write
  481. ****************************************************************************/
  482. static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
  483. size_t len)
  484. {
  485. FAR struct inode *inode;
  486. FAR struct ft80x_dev_s *priv;
  487. int ret;
  488. lcdinfo("buffer: %p len %lu\n", buffer, (unsigned long)len);
  489. DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 3) == 0 &&
  490. len > 0 && (len & 3) == 0 && len <= FT80X_RAM_DL_SIZE);
  491. DEBUGASSERT(filep != NULL);
  492. inode = filep->f_inode;
  493. DEBUGASSERT(inode != NULL && inode->i_private != NULL);
  494. priv = inode->i_private;
  495. if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 ||
  496. len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
  497. {
  498. return -EINVAL;
  499. }
  500. /* Get exclusive access to the device structures */
  501. ret = nxsem_wait(&priv->exclsem);
  502. if (ret < 0)
  503. {
  504. return ret;
  505. }
  506. /* Note that there is no check if the driver was opened read-only. That
  507. * would be a silly thing to do.
  508. */
  509. /* The write method is functionally equivalent to the FT80X_IOC_CREATEDL
  510. * IOCTL command: It simply copies the display list in the user buffer to
  511. * the FT80x display list memory.
  512. */
  513. ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos, buffer, len);
  514. filep->f_pos += len;
  515. nxsem_post(&priv->exclsem);
  516. return len;
  517. }
  518. /****************************************************************************
  519. * Name: ft80x_ioctl
  520. *
  521. * Description:
  522. * The standard ioctl method. This is where ALL of the PWM work is done.
  523. *
  524. ****************************************************************************/
  525. static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  526. {
  527. FAR struct inode *inode;
  528. FAR struct ft80x_dev_s *priv;
  529. int ret;
  530. DEBUGASSERT(filep != NULL);
  531. inode = filep->f_inode;
  532. DEBUGASSERT(inode != NULL && inode->i_private != NULL);
  533. priv = inode->i_private;
  534. lcdinfo("cmd: %d arg: %lu\n", cmd, arg);
  535. /* Get exclusive access to the device structures */
  536. ret = nxsem_wait(&priv->exclsem);
  537. if (ret < 0)
  538. {
  539. return ret;
  540. }
  541. /* Handle built-in ioctl commands */
  542. switch (cmd)
  543. {
  544. /* FT80X_IOC_CREATEDL:
  545. * Description: Write a display list to the FT80x display list
  546. * memory
  547. * Description: Write a display list to the FT80x display list
  548. * memory starting at offset zero. This may or may
  549. * not be the entire display list. Display lists may
  550. * be created incrementally, starting with
  551. * FT80X_IOC_CREATEDL and finishing the display list
  552. * using FT80XIO_APPENDDL
  553. * Argument: A reference to a display list structure instance.
  554. * See struct ft80x_displaylist_s.
  555. * Returns: None
  556. */
  557. case FT80X_IOC_CREATEDL:
  558. /* Set the file position to zero and fall through to "append" the new
  559. * display list data at offset 0.
  560. */
  561. filep->f_pos = 0;
  562. /* FALLTHROUGH */
  563. /* FT80X_IOC_APPENDDL:
  564. * Description: Write additional display list entries to the FT80x
  565. * display list memory at the current display list
  566. * offset. This IOCTL command permits display lists
  567. * to be completed incrementally, starting with
  568. * FT80X_IOC_CREATEDL and finishing the display list
  569. * using FT80XIO_APPENDDL.
  570. * Argument: A reference to a display list structure instance.
  571. * See struct ft80x_displaylist_s.
  572. * Returns: None
  573. */
  574. case FT80X_IOC_APPENDDL:
  575. {
  576. FAR struct ft80x_displaylist_s *dl =
  577. (FAR struct ft80x_displaylist_s *)((uintptr_t)arg);
  578. if (dl == NULL || ((uintptr_t)&dl->cmd & 3) != 0 ||
  579. (dl->dlsize & 3) != 0 ||
  580. dl->dlsize + filep->f_pos > FT80X_RAM_DL_SIZE)
  581. {
  582. ret = -EINVAL;
  583. }
  584. else
  585. {
  586. /* Check if there is a display list. It might be useful for
  587. * the application to issue FT80X_IOC_CREATEDL with no data in
  588. * order to initialize the display list, then form all of the
  589. * list entries with FT80X_IOC_APPENDDL.
  590. */
  591. if (dl->dlsize > 0)
  592. {
  593. /* This IOCTL command simply copies the display list
  594. * provided into the FT80x display list memory.
  595. */
  596. ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos,
  597. &dl->cmd, dl->dlsize);
  598. filep->f_pos += dl->dlsize;
  599. }
  600. ret = OK;
  601. }
  602. }
  603. break;
  604. /* FT80X_IOC_GETRAMDL:
  605. * Description: Read a 32-bit value from the display list.
  606. * Argument: A reference to an instance of struct ft80x_relmem_s.
  607. * Returns: The 32-bit value read from the display list.
  608. */
  609. case FT80X_IOC_GETRAMDL:
  610. {
  611. FAR struct ft80x_relmem_s *ramdl =
  612. (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
  613. if (ramdl == NULL || ((uintptr_t)ramdl->offset & 3) != 0 ||
  614. ramdl->offset >= FT80X_RAM_DL_SIZE)
  615. {
  616. ret = -EINVAL;
  617. }
  618. else
  619. {
  620. ft80x_read_memory(priv, FT80X_RAM_DL + ramdl->offset,
  621. ramdl->value, ramdl->nbytes);
  622. ret = OK;
  623. }
  624. }
  625. break;
  626. /* FT80X_IOC_PUTRAMG
  627. * Description: Write byte data to FT80x graphics memory (RAM_G)
  628. * Argument: A reference to an instance of struct ft80x_relmem_s.
  629. * Returns: None.
  630. */
  631. case FT80X_IOC_PUTRAMG:
  632. {
  633. FAR struct ft80x_relmem_s *ramg =
  634. (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
  635. if (ramg == NULL ||
  636. (ramg->offset + ramg->nbytes) >= FT80X_RAM_G_SIZE)
  637. {
  638. ret = -EINVAL;
  639. }
  640. else
  641. {
  642. ft80x_write_memory(priv, FT80X_RAM_G + ramg->offset,
  643. ramg->value, ramg->nbytes);
  644. ret = OK;
  645. }
  646. }
  647. break;
  648. /* FT80X_IOC_PUTRAMCMD
  649. * Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
  650. * Argument: A reference to an instance of struct ft80x_relmem_s.
  651. * Returns: None.
  652. */
  653. case FT80X_IOC_PUTRAMCMD:
  654. {
  655. FAR struct ft80x_relmem_s *ramcmd =
  656. (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
  657. if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
  658. {
  659. ret = -EINVAL;
  660. }
  661. else
  662. {
  663. ft80x_write_memory(priv, FT80X_RAM_CMD + ramcmd->offset,
  664. ramcmd->value, ramcmd->nbytes);
  665. ret = OK;
  666. }
  667. }
  668. break;
  669. /* FT80X_IOC_GETREG8:
  670. * Description: Read an 8-bit register value from the FT80x.
  671. * Argument: A reference to an instance of struct
  672. * ft80x_register_s.
  673. * Returns: The 8-bit value read from the register.
  674. */
  675. case FT80X_IOC_GETREG8:
  676. {
  677. FAR struct ft80x_register_s *reg =
  678. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  679. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  680. {
  681. ret = -EINVAL;
  682. }
  683. else
  684. {
  685. reg->value.u8 = ft80x_read_byte(priv, reg->addr);
  686. ret = OK;
  687. }
  688. }
  689. break;
  690. /* FT80X_IOC_GETREG16:
  691. * Description: Read a 16-bit register value from the FT80x.
  692. * Argument: A reference to an instance of struct
  693. * ft80x_register_s.
  694. * Returns: The 16-bit value read from the register.
  695. */
  696. case FT80X_IOC_GETREG16:
  697. {
  698. FAR struct ft80x_register_s *reg =
  699. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  700. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  701. {
  702. ret = -EINVAL;
  703. }
  704. else
  705. {
  706. reg->value.u16 = ft80x_read_hword(priv, reg->addr);
  707. ret = OK;
  708. }
  709. }
  710. break;
  711. /* FT80X_IOC_GETREG32:
  712. * Description: Read a 32-bit register value from the FT80x.
  713. * Argument: A reference to an instance of struct
  714. * ft80x_register_s.
  715. * Returns: The 32-bit value read from the register.
  716. */
  717. case FT80X_IOC_GETREG32:
  718. {
  719. FAR struct ft80x_register_s *reg =
  720. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  721. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  722. {
  723. ret = -EINVAL;
  724. }
  725. else
  726. {
  727. reg->value.u32 = ft80x_read_word(priv, reg->addr);
  728. ret = OK;
  729. }
  730. }
  731. break;
  732. /* FT80X_IOC_GETREGS:
  733. * Description: Read multiple 32-bit register values from the FT80x.
  734. * Argument: A reference to an instance of struct
  735. * ft80x_registers_s.
  736. * Returns: The 32-bit values read from the consecutive
  737. * registers .
  738. */
  739. case FT80X_IOC_GETREGS:
  740. {
  741. FAR struct ft80x_registers_s *regs =
  742. (FAR struct ft80x_registers_s *)((uintptr_t)arg);
  743. if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
  744. {
  745. ret = -EINVAL;
  746. }
  747. else
  748. {
  749. ft80x_read_memory(priv, regs->addr, regs->value,
  750. (size_t)regs->nregs << 2);
  751. ret = OK;
  752. }
  753. }
  754. break;
  755. /* FT80X_IOC_PUTREG8:
  756. * Description: Write an 8-bit register value to the FT80x.
  757. * Argument: A reference to an instance of struct
  758. * ft80x_register_s.
  759. * Returns: None.
  760. */
  761. case FT80X_IOC_PUTREG8:
  762. {
  763. FAR struct ft80x_register_s *reg =
  764. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  765. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  766. {
  767. ret = -EINVAL;
  768. }
  769. else
  770. {
  771. ft80x_write_byte(priv, reg->addr, reg->value.u8);
  772. ret = OK;
  773. }
  774. }
  775. break;
  776. /* FT80X_IOC_PUTREG16:
  777. * Description: Write a 16-bit register value to the FT80x.
  778. * Argument: A reference to an instance of struct
  779. * ft80x_register_s.
  780. * Returns: None.
  781. */
  782. case FT80X_IOC_PUTREG16:
  783. {
  784. FAR struct ft80x_register_s *reg =
  785. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  786. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  787. {
  788. ret = -EINVAL;
  789. }
  790. else
  791. {
  792. ft80x_write_hword(priv, reg->addr, reg->value.u16);
  793. ret = OK;
  794. }
  795. }
  796. break;
  797. /* FT80X_IOC_PUTREG32:
  798. * Description: Write a 32-bit register value to the FT80x.
  799. * Argument: A reference to an instance of struct
  800. * ft80x_register_s.
  801. * Returns: None.
  802. */
  803. case FT80X_IOC_PUTREG32:
  804. {
  805. FAR struct ft80x_register_s *reg =
  806. (FAR struct ft80x_register_s *)((uintptr_t)arg);
  807. if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
  808. {
  809. ret = -EINVAL;
  810. }
  811. else
  812. {
  813. ft80x_write_word(priv, reg->addr, reg->value.u32);
  814. ret = OK;
  815. }
  816. }
  817. break;
  818. /* FT80X_IOC_PUTREGS:
  819. * Description: Write multiple 32-bit register values to the FT80x.
  820. * Argument: A reference to an instance of struct
  821. * ft80x_registers_s.
  822. * Returns: None.
  823. */
  824. case FT80X_IOC_PUTREGS:
  825. {
  826. FAR struct ft80x_registers_s *regs =
  827. (FAR struct ft80x_registers_s *)((uintptr_t)arg);
  828. if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
  829. {
  830. ret = -EINVAL;
  831. }
  832. else
  833. {
  834. ft80x_write_memory(priv, regs->addr, regs->value,
  835. (size_t)regs->nregs << 2);
  836. ret = OK;
  837. }
  838. }
  839. break;
  840. /* FT80X_IOC_EVENTNOTIFY:
  841. * Description: Setup to receive a signal when an event occurs.
  842. * Argument: A reference to an instance of struct ft80x_notify_s.
  843. * Returns: None
  844. */
  845. case FT80X_IOC_EVENTNOTIFY:
  846. {
  847. FAR struct ft80x_notify_s *notify =
  848. (FAR struct ft80x_notify_s *)((uintptr_t)arg);
  849. if (notify == NULL || notify->pid < 0 ||
  850. (unsigned int)notify->id >= FT80X_INT_NEVENTS)
  851. {
  852. ret = -EINVAL;
  853. }
  854. else
  855. {
  856. FAR struct ft80x_eventinfo_s *info = &priv->notify[notify->id];
  857. uint32_t regval;
  858. /* Are we enabling or disabling */
  859. if (notify->enable)
  860. {
  861. /* Make sure that arguments are valid for the enable */
  862. if (notify->pid == 0)
  863. {
  864. ret = -EINVAL;
  865. }
  866. else
  867. {
  868. /* Setup the new notification information */
  869. info->event = notify->event;
  870. info->pid = notify->pid;
  871. info->enable = true;
  872. /* Enable interrupts associated with the event */
  873. regval = ft80x_read_word(priv, FT80X_REG_INT_MASK);
  874. regval |= (1 << notify->id);
  875. ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);
  876. ret = OK;
  877. }
  878. }
  879. else
  880. {
  881. /* Disable the notification */
  882. info->pid = 0;
  883. info->enable = false;
  884. /* Disable interrupts associated with the event */
  885. regval = ft80x_read_word(priv, FT80X_REG_INT_MASK);
  886. regval &= ~(1 << notify->id);
  887. ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);
  888. /* Cancel any pending notification */
  889. nxsig_cancel_notification(&info->work);
  890. ret = OK;
  891. }
  892. }
  893. }
  894. break;
  895. /* FT80X_IOC_FADE:
  896. * Description: Change the backlight intensity with a controllable
  897. * fade.
  898. * Argument: A reference to an instance of struct ft80x_fade_s.
  899. * Returns: None.
  900. */
  901. case FT80X_IOC_FADE:
  902. {
  903. FAR const struct ft80x_fade_s *fade =
  904. (FAR const struct ft80x_fade_s *)((uintptr_t)arg);
  905. if (fade == NULL || fade->duty > 100 ||
  906. fade->delay < MIN_FADE_DELAY || fade->delay > MAX_FADE_DELAY)
  907. {
  908. ret = -EINVAL;
  909. }
  910. else
  911. {
  912. ret = ft80x_fade(priv, fade);
  913. }
  914. }
  915. break;
  916. /* FT80X_IOC_AUDIO:
  917. * Description: Enable/disable an external audio amplifier.
  918. * Argument: 0=disable; 1=enable.
  919. * Returns: None.
  920. */
  921. case FT80X_IOC_AUDIO:
  922. {
  923. #if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
  924. /* Amplifier is controlled by an MCU GPIO pin */
  925. DEBUGASSERT(priv->lower->attach != NULL &&
  926. priv->lower->audio != NULL);
  927. DEBUGASSERT(arg == 0 || arg == 1);
  928. priv->lower->audio(priv->lower, (arg != 0));
  929. ret = OK;
  930. #elif defined(CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN)
  931. /* Amplifier is controlled by an FT80x GPIO pin */
  932. uint8_t regval8;
  933. DEBUGASSERT(arg == 0 || arg == 1);
  934. regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO);
  935. /* Active low logic assumed */
  936. if (arg == 0)
  937. {
  938. regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
  939. }
  940. else
  941. {
  942. regval8 &= ~(1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
  943. }
  944. ft80x_write_byte(priv, FT80X_REG_GPIO, regval8);
  945. ret = OK;
  946. #else
  947. /* Amplifier is not controllable. */
  948. DEBUGASSERT(arg == 0 || arg == 1);
  949. return OK;
  950. #endif
  951. }
  952. break;
  953. /* Unrecognized IOCTL command */
  954. default:
  955. lcderr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg);
  956. ret = -ENOTTY;
  957. break;
  958. }
  959. nxsem_post(&priv->exclsem);
  960. return ret;
  961. }
  962. /****************************************************************************
  963. * Name: ft80x_unlink
  964. ****************************************************************************/
  965. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  966. static int ft80x_unlink(FAR struct inode *inode)
  967. {
  968. FAR struct ft80x_dev_s *priv;
  969. /* Get the reference to our internal state structure from the inode
  970. * structure.
  971. */
  972. DEBUGASSERT(inode && inode->i_private);
  973. priv = inode->i_private;
  974. /* Indicate that the driver has been unlinked */
  975. priv->unlinked = true;
  976. /* If there are no further open references to the driver, then commit
  977. * Hara-Kiri now.
  978. */
  979. if (priv->crefs == 0)
  980. {
  981. ft80x_destroy(priv);
  982. }
  983. return OK;
  984. }
  985. #endif
  986. /****************************************************************************
  987. * Name: ft80x_initialize
  988. *
  989. * Description:
  990. * Initialize the FT80x
  991. *
  992. ****************************************************************************/
  993. static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
  994. {
  995. uint32_t timeout;
  996. uint32_t regval32;
  997. uint8_t regval8;
  998. /* To configure the display, load the timing control registers with values
  999. * for the particular display. These registers control horizontal timing:
  1000. *
  1001. * - FT80X_REG_PCLK
  1002. * - FT80X_REG_PCLK_POL
  1003. * - FT80X_REG_HCYCLE
  1004. * - FT80X_REG_HOFFSET
  1005. * - FT80X_REG_HSIZE
  1006. * - FT80X_REG_HSYNC0
  1007. * - FT80X_REG_HSYNC1
  1008. *
  1009. * These registers control vertical timing:
  1010. *
  1011. * - FT80X_REG_VCYCLE
  1012. * - FT80X_REG_VOFFSET
  1013. * - FT80X_REG_VSIZE
  1014. * - FT80X_REG_VSYNC0
  1015. * - FT80X_REG_VSYNC1
  1016. *
  1017. * And the FT80X_REG_CSPREAD register changes color clock timing to reduce
  1018. * system noise.
  1019. *
  1020. * GPIO bit 7 is used for the display enable pin of the LCD module. By
  1021. * setting the direction of the GPIO bit to out direction, the display can
  1022. * be enabled by writing value of 1 into GPIO bit 7 or the display can be
  1023. * disabled by writing a value of 0 into GPIO bit 7. By default GPIO bit 7
  1024. * direction is output and the value is 0.
  1025. */
  1026. /* Initialization Sequence from Power Down using PD_N pin:
  1027. *
  1028. * 1. Drive the PD_N pin high
  1029. * 2. Wait for at least 20ms
  1030. * 3. Execute "Initialization Sequence during the Boot up" from steps 1
  1031. * to 9
  1032. *
  1033. * Initialization Sequence from Sleep Mode:
  1034. *
  1035. * 1. Send Host command "ACTIVE" to enable clock to FT800
  1036. * 2. Wait for at least 20ms
  1037. * 3. Execute "Initialization Sequence during Boot Up" from steps 5 to 8
  1038. *
  1039. * Initialization sequence from standby mode:
  1040. *
  1041. * Execute all the steps mentioned in "Initialization Sequence from Sleep
  1042. * Mode" except waiting for at least 20ms in step 2.
  1043. */
  1044. DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
  1045. priv->lower->pwrdown(priv->lower, false);
  1046. up_mdelay(20);
  1047. /* Initialization Sequence during the boot up:
  1048. *
  1049. * 1. Use MCU SPI clock not more than 11MHz
  1050. * 2. Send Host command CLKEXT to FT800 to enable PLL input from oscillator
  1051. * or external clock. Should default to 48MHz PLL output.
  1052. * 3. Send Host command ACTIVE to enable clock and wake up the FT80x.
  1053. * 4. Configure video timing registers, except FT80X_REG_PCLK
  1054. * 5. Write first display list
  1055. * 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately
  1056. * 7. Enable back light control for display
  1057. * 8. Write FT80X_REG_PCLK, video output begins with the first display list
  1058. * 9. Use MCU SPI clock not more than 30MHz
  1059. */
  1060. /* 1. Select the initial SPI frequency */
  1061. DEBUGASSERT(priv->lower->init_frequency <= 11000000);
  1062. priv->frequency = priv->lower->init_frequency;
  1063. /* 2. Send Host command CLKEXT to FT800 to enable PLL input from oscillator
  1064. * or external clock.
  1065. */
  1066. ft80x_host_command(priv, FT80X_CMD_CLKEXT);
  1067. up_mdelay(10);
  1068. #if 0 /* Un-necessary? */
  1069. /* Switch PLL output to 48MHz (should be the default) */
  1070. ft80x_host_command(priv, FT80X_CMD_CLK48M);
  1071. up_mdelay(10);
  1072. #endif
  1073. /* 3. Send Host command ACTIVE to enable clock and wake up the FT80x. */
  1074. ft80x_host_command(priv, FT80X_CMD_ACTIVE);
  1075. up_mdelay(10);
  1076. #if 0 /* Un-necessary? */
  1077. /* Do a core reset for safer */
  1078. ft80x_host_command(priv, FT80X_CMD_CORERST);
  1079. #endif
  1080. /* Verify the chip ID. Read repeatedly until FT80x is ready. */
  1081. timeout = 0;
  1082. for (; ; )
  1083. {
  1084. /* Read the Chip ID */
  1085. regval8 = ft80x_read_byte(priv, FT80X_REG_ID);
  1086. if (regval8 == CHIPID)
  1087. {
  1088. /* Chip ID verify so FT80x is ready */
  1089. break;
  1090. }
  1091. /* Initial Chip ID read may fail because the chip is not yet ready. */
  1092. if (++timeout > 100000)
  1093. {
  1094. lcderr("ERROR: Bad chip ID: %02x\n", regval8);
  1095. return -ENODEV;
  1096. }
  1097. }
  1098. regval32 = ft80x_read_word(priv, FT80X_ROM_CHIPID);
  1099. if ((regval32 & ROMID_MASK) != ROMID)
  1100. {
  1101. lcderr("ERROR: Bad ROM chip ID: %08lx\n", (unsigned long)regval32);
  1102. return -ENODEV;
  1103. }
  1104. /* 4. Configure video timing registers, except FT80X_REG_PCLK
  1105. *
  1106. * Once the FT800 is awake and the internal clock set and Device ID
  1107. * checked, the next task is to configure the LCD display parameters for
  1108. * the chosen display with the values determined in Section 2.3.3 above.
  1109. *
  1110. * a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output
  1111. * while the LCD and other system parameters are configured
  1112. * b. Set the following registers with values for the chosen display.
  1113. * Typical WQVGA and QVGA values are shown:
  1114. *
  1115. * Register Description WQVGA QVGA
  1116. * 480x272 320x240
  1117. * FT80X_REG_PCLK_POL Pixel Clock Polarity 1 0
  1118. * FT80X_REG_HSIZE Image width in pixels 480 320
  1119. * FT80X_REG_HCYCLE Total number of clocks per line 548 408
  1120. * FT80X_REG_HOFFSET Horizontal image start 43 70
  1121. * (pixels from left)
  1122. * FT80X_REG_HSYNC0 Start of HSYNC pulse 0 0
  1123. * (falling edge)
  1124. * FT80X_REG_HSYNC1 End of HSYNC pulse 41 10
  1125. * (rising edge)
  1126. * FT80X_REG_VSIZE Image height in pixels 272 240
  1127. * FT80X_REG_VCYCLE Total number of lines per screen 292 263
  1128. * FT80X_REG_VOFFSET Vertical image start 12 13
  1129. * (lines from top)
  1130. * FT80X_REG_VSYNC0 Start of VSYNC pulse 0 0
  1131. * (falling edge)
  1132. * FT80X_REG_VSYNC1 End of VSYNC pulse 10 2
  1133. * (rising edge)
  1134. *
  1135. * c. Enable or disable FT80X_REG_CSPREAD with a value of 01h or 00h,
  1136. * respectively. Enabling FT80X_REG_CSPREAD will offset the R, G and B
  1137. * output bits so all they do not all change at the same time.
  1138. */
  1139. ft80x_write_byte(priv, FT80X_REG_PCLK, 0);
  1140. #if defined(CONFIG_LCD_FT80X_WQVGA)
  1141. ft80x_write_hword(priv, FT80X_REG_HCYCLE, 548);
  1142. ft80x_write_hword(priv, FT80X_REG_HOFFSET, 43);
  1143. ft80x_write_hword(priv, FT80X_REG_HSYNC0, 0);
  1144. ft80x_write_hword(priv, FT80X_REG_HSYNC1, 41);
  1145. ft80x_write_hword(priv, FT80X_REG_VCYCLE, 292);
  1146. ft80x_write_hword(priv, FT80X_REG_VOFFSET, 12);
  1147. ft80x_write_hword(priv, FT80X_REG_VSYNC0, 0);
  1148. ft80x_write_hword(priv, FT80X_REG_VSYNC1, 10);
  1149. ft80x_write_byte(priv, FT80X_REG_SWIZZLE, 0);
  1150. ft80x_write_byte(priv, FT80X_REG_PCLK_POL, 1);
  1151. ft80x_write_byte(priv, FT80X_REG_CSPREAD, 1);
  1152. ft80x_write_hword(priv, FT80X_REG_HSIZE, 480);
  1153. ft80x_write_hword(priv, FT80X_REG_VSIZE, 272);
  1154. #elif defined(CONFIG_LCD_FT80X_QVGA)
  1155. ft80x_write_hword(priv, FT80X_REG_HCYCLE, 408);
  1156. ft80x_write_hword(priv, FT80X_REG_HOFFSET, 70);
  1157. ft80x_write_hword(priv, FT80X_REG_HSYNC0, 0);
  1158. ft80x_write_hword(priv, FT80X_REG_HSYNC1, 10);
  1159. ft80x_write_hword(priv, FT80X_REG_VCYCLE, 263);
  1160. ft80x_write_hword(priv, FT80X_REG_VOFFSET, 13);
  1161. ft80x_write_hword(priv, FT80X_REG_VSYNC0, 0);
  1162. ft80x_write_hword(priv, FT80X_REG_VSYNC1, 2);
  1163. ft80x_write_byte(priv, FT80X_REG_SWIZZLE, 2);
  1164. ft80x_write_byte(priv, FT80X_REG_PCLK_POL, 0);
  1165. ft80x_write_byte(priv, FT80X_REG_CSPREAD, 1);
  1166. ft80x_write_hword(priv, FT80X_REG_HSIZE, 320);
  1167. ft80x_write_hword(priv, FT80X_REG_VSIZE, 240);
  1168. #else
  1169. # error Unknown display size
  1170. #endif
  1171. /* 5. Write first display list */
  1172. ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0, 0, 0));
  1173. ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1, 1, 1));
  1174. ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
  1175. /* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */
  1176. ft80x_write_byte(priv, FT80X_REG_DLSWAP, DLSWAP_FRAME);
  1177. /* GPIO bit 7 is used for the display enable pin of the LCD module. By
  1178. * setting the direction of the GPIO bit to out direction, the display can
  1179. * be enabled by writing value of 1 into GPIO bit 7 or the display can be
  1180. * disabled by writing a value of 0 into GPIO bit 7. By default GPIO bit 7
  1181. * direction is output and the value is 0.
  1182. *
  1183. * If an external audio amplified is controlled by an FT80x GPIO, then
  1184. * configure that GPIO as well. Active low logic is assumed so that the
  1185. * amplifier is initially in the shutdown state.
  1186. */
  1187. regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO_DIR);
  1188. regval8 |= (1 << 7);
  1189. #ifdef CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN
  1190. regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
  1191. #endif
  1192. ft80x_write_byte(priv, FT80X_REG_GPIO_DIR, regval8);
  1193. regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO);
  1194. regval8 |= (1 << 7);
  1195. #ifdef CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN
  1196. regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
  1197. #endif
  1198. ft80x_write_byte(priv, FT80X_REG_GPIO, regval8);
  1199. /* 7. Enable back light control for display */
  1200. #warning Missing logic
  1201. /* 8. Write FT80X_REG_PCLK, video output with the first display list */
  1202. #if defined(CONFIG_LCD_FT80X_WQVGA)
  1203. ft80x_write_byte(priv, FT80X_REG_PCLK, 5);
  1204. #elif defined(CONFIG_LCD_FT80X_QVGA)
  1205. ft80x_write_byte(priv, FT80X_REG_PCLK, 8);
  1206. #else
  1207. # error Unknown display size
  1208. #endif
  1209. /* 9. Use MCU SPI clock not more than 30MHz */
  1210. DEBUGASSERT(priv->lower->op_frequency <= 30000000);
  1211. priv->frequency = priv->lower->op_frequency;
  1212. /* Configure touch mode. Using default touch mode of FRAME_SYNC (~60Hz) */
  1213. ft80x_write_byte(priv, FT80X_REG_TOUCH_MODE, TOUCH_MODE_FRAMESYNC);
  1214. #if defined(CONFIG_LCD_FT800)
  1215. /* Configure the touch threshold. The value 1200 may need to be tweaked
  1216. * for your application.
  1217. */
  1218. ft80x_write_hword(priv, FT80X_REG_TOUCH_RZTHRESH, 1200);
  1219. #elif defined(CONFIG_LCD_FT801)
  1220. #ifdef CONFIG_LCD_FT801_MULTITOUCH
  1221. /* Selected extended mode */
  1222. ft80x_write_byte(priv, FT80X_REG_CTOUCH_EXTENDED, 0);
  1223. #else
  1224. /* Selected compatibility mode */
  1225. ft80x_write_byte(priv, FT80X_REG_CTOUCH_EXTENDED, 1);
  1226. #endif
  1227. #else
  1228. # error No FT80x device configured
  1229. #endif
  1230. return OK;
  1231. }
  1232. /****************************************************************************
  1233. * Public Functions
  1234. ****************************************************************************/
  1235. /****************************************************************************
  1236. * Name: ft80x_register
  1237. *
  1238. * Description:
  1239. * Configure the ADS7843E to use the provided SPI device instance. This
  1240. * will register the driver as /dev/ft800 or /dev/ft801, depending upon
  1241. * the configuration.
  1242. *
  1243. * Input Parameters:
  1244. * spi - An SPI driver instance
  1245. * i2c - An I2C master driver instance
  1246. * lower - Persistent board configuration data / lower half interface
  1247. *
  1248. * Returned Value:
  1249. * Zero is returned on success. Otherwise, a negated errno value is
  1250. * returned to indicate the nature of the failure.
  1251. *
  1252. ****************************************************************************/
  1253. #if defined(CONFIG_LCD_FT80X_SPI)
  1254. int ft80x_register(FAR struct spi_dev_s *spi,
  1255. FAR const struct ft80x_config_s *lower)
  1256. #elif defined(CONFIG_LCD_FT80X_I2C)
  1257. int ft80x_register(FAR struct i2c_master_s *i2c,
  1258. FAR const struct ft80x_config_s *lower)
  1259. #endif
  1260. {
  1261. FAR struct ft80x_dev_s *priv;
  1262. int ret;
  1263. #if defined(CONFIG_LCD_FT80X_SPI)
  1264. DEBUGASSERT(spi != NULL && lower != NULL);
  1265. #elif defined(CONFIG_LCD_FT80X_I2C)
  1266. DEBUGASSERT(i2c != NULL && lower != NULL);
  1267. #endif
  1268. /* Allocate the driver state structure */
  1269. priv = (FAR struct ft80x_dev_s *)kmm_zalloc(sizeof(struct ft80x_dev_s));
  1270. if (priv == NULL)
  1271. {
  1272. lcderr("ERROR: Failed to allocate state structure\n");
  1273. return -ENOMEM;
  1274. }
  1275. /* Save the lower level interface and configuration information */
  1276. priv->lower = lower;
  1277. #ifdef CONFIG_LCD_FT80X_SPI
  1278. /* Remember the SPI configuration */
  1279. priv->spi = spi;
  1280. #else
  1281. /* Remember the I2C configuration */
  1282. priv->i2c = i2c;
  1283. #endif
  1284. /* Initialize the mutual exclusion semaphore */
  1285. nxsem_init(&priv->exclsem, 0, 1);
  1286. /* Initialize the FT80x */
  1287. ret = ft80x_initialize(priv);
  1288. if (ret < 0)
  1289. {
  1290. goto errout_with_sem;
  1291. }
  1292. /* Attach our interrupt handler */
  1293. DEBUGASSERT(lower->attach != NULL && lower->enable != NULL);
  1294. ret = lower->attach(lower, ft80x_interrupt, priv);
  1295. if (ret < 0)
  1296. {
  1297. goto errout_with_sem;
  1298. }
  1299. /* Disable all interrupt sources, but enable interrupts both in the lower
  1300. * half driver and in the FT80x.
  1301. */
  1302. ft80x_write_word(priv, FT80X_REG_INT_MASK, 0);
  1303. ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_ENABLE);
  1304. lower->enable(lower, true);
  1305. /* Register the FT80x character driver */
  1306. ret = register_driver(DEVNAME, &g_ft80x_fops, 0666, priv);
  1307. if (ret < 0)
  1308. {
  1309. goto errout_with_interrupts;
  1310. }
  1311. return OK;
  1312. errout_with_interrupts:
  1313. lower->enable(lower, false);
  1314. ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_DISABLE);
  1315. lower->attach(lower, NULL, NULL);
  1316. errout_with_sem:
  1317. nxsem_destroy(&priv->exclsem);
  1318. return ret;
  1319. }
  1320. #endif /* CONFIG_LCD_FT80X */