1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615 |
- /****************************************************************************
- * drivers/lcd/ft80x.c
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
- /* References:
- * - Document No.: FT_000792, "FT800 Embedded Video Engine", Datasheet
- * Version 1.1, Clearance No.: FTDI# 334, Future Technology Devices
- * International Ltd.
- * - Document No.: FT_000986, "FT801 Embedded Video Engine Datasheet",
- * Version 1.0, Clearance No.: FTDI#376, Future Technology Devices
- * International Ltd.
- * - Application Note AN_240AN_240, "FT800 From the Ground Up", Version
- * 1.1, Issue Date: 2014-06-09, Future Technology Devices International
- * Ltd.
- * - "FT800 Series Programmer Guide Guide", Version 2.1, Issue Date:
- * 2016-09-19, Future Technology Devices International Ltd.
- */
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <nuttx/config.h>
- #include <sys/types.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
- #include <debug.h>
- #include <nuttx/arch.h>
- #include <nuttx/semaphore.h>
- #include <nuttx/kmalloc.h>
- #include <nuttx/clock.h>
- #include <nuttx/wqueue.h>
- #include <nuttx/fs/fs.h>
- #include <nuttx/i2c/i2c_master.h>
- #include <nuttx/spi/spi.h>
- #include <nuttx/lcd/lcd.h>
- #include <nuttx/lcd/ft80x.h>
- #include <arch/irq.h>
- #include "ft80x.h"
- #ifdef CONFIG_LCD_FT80X
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- #define CHIPID 0x7c
- #define ROMID_MASK 0x0000ffff
- #define VERSION_MASK 0xffff0000
- #if defined(CONFIG_LCD_FT800)
- # define DEVNAME "/dev/ft800"
- # define ROM_CHIPID 0x00010008 /* Byte [0:1] Chip ID "0800" BCD
- * Byte [2:3] Version "0100" BCD */
- #elif defined(CONFIG_LCD_FT801)
- # define DEVNAME "/dev/ft801"
- # define ROM_CHIPID 0x00010108 /* Byte [0:1] Chip ID "0801" BCD
- * Byte [2:3] Version "0100" BCD */
- #else
- # error No FT80x device configured
- #endif
- #define ROMID (ROM_CHIPID & ROMID_MASK)
- #define VERSION (ROM_CHIPID & VERSION_MASK)
- #define MIN_FADE_DELAY 10 /* Milliseconds */
- #define MAX_FADE_DELAY 16700 /* Milliseconds */
- #define FADE_STEP_MSEC 10 /* Milliseconds */
- /****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
- static int ft80x_fade(FAR struct ft80x_dev_s *priv,
- FAR const struct ft80x_fade_s *fade);
- static void ft80x_notify(FAR struct ft80x_dev_s *priv,
- enum ft80x_notify_e id, int value);
- static void ft80x_interrupt_work(FAR void *arg);
- static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg);
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- static void ft80x_destroy(FAR struct ft80x_dev_s *priv);
- #endif
- /* Character driver methods */
- static int ft80x_open(FAR struct file *filep);
- static int ft80x_close(FAR struct file *filep);
- static ssize_t ft80x_read(FAR struct file *filep, FAR char *buffer,
- size_t buflen);
- static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
- size_t buflen);
- static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- static int ft80x_unlink(FAR struct inode *inode);
- #endif
- /* Initialization */
- static int ft80x_initialize(FAR struct ft80x_dev_s *priv);
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- static const struct file_operations g_ft80x_fops =
- {
- ft80x_open, /* open */
- ft80x_close, /* close */
- ft80x_read, /* read */
- ft80x_write, /* write */
- NULL, /* seek */
- ft80x_ioctl, /* ioctl */
- NULL /* poll */
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- , ft80x_unlink /* unlink */
- #endif
- };
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: ft80x_forcetake
- *
- * Description:
- * This is a wrapper around but nxsem_wait_uninterruptible(). The wrapper
- * continues to wait even if the thread is canceled. This must be done in
- * certain conditions where were must continue in order to clean-up
- * resources.
- *
- ****************************************************************************/
- static void ft80x_forcetake(FAR sem_t *sem)
- {
- int ret;
- do
- {
- ret = nxsem_wait_uninterruptible(sem);
- /* The only expected error would -ECANCELED meaning that the
- * parent thread has been canceled. We have to continue and
- * terminate the poll in this case.
- */
- DEBUGASSERT(ret == OK || ret == -ECANCELED);
- }
- while (ret < 0);
- }
- /****************************************************************************
- * Name: ft80x_fade
- *
- * Description:
- * Change the backlight intensity with a controllable fade.
- *
- ****************************************************************************/
- static int ft80x_fade(FAR struct ft80x_dev_s *priv,
- FAR const struct ft80x_fade_s *fade)
- {
- clock_t start;
- clock_t elapsed;
- int32_t delay;
- int32_t duty;
- int16_t endduty;
- int16_t delta;
- /* 0% corresponds to the value 0, but 100% corresponds to the value 128 */
- endduty = (uint16_t)((uint16_t)fade->duty << 7) / 100;
- /* Get the change in duty from the current to the terminal duty. */
- duty = (int32_t)(ft80x_read_byte(priv, FT80X_REG_PWM_DUTY) & 0x7f);
- delta = endduty - (int16_t)duty;
- /* The "smoothness" of the steps will depend on the resolution of the
- * system timer. The minimum delay is <= 2 * system_clock_period.
- *
- * We will try for a FADE_STEP_MSEC delay, but we will try to adapt to
- * whatever we get is we are working close the system time resolution.
- * For human factors reasons, any delay less than 100 MS or so should
- * appear more or less smooth.
- *
- * The delay calculation should never overflow:
- *
- * Max delay: 16,700 msec (MAX_FADE_DELAY)
- * Min clock period: 1 usec
- * Max delay: 16,700,000 ticks
- * INT32_MAX 2,147,483,647
- */
- delay = MSEC2TICK((int32_t)fade->delay);
- if (delay <= 0)
- {
- delay = 1;
- }
- start = clock_systime_ticks();
- do
- {
- /* Wait for FADE_STEP_MSEC msec (or whatever we get) */
- nxsig_usleep(FADE_STEP_MSEC * 1000);
- /* Get the elapsed time */
- elapsed = clock_systime_ticks() - start;
- if (elapsed > INT32_MAX || (int32_t)elapsed >= delay)
- {
- duty = endduty;
- }
- else
- {
- /* Interpolate to get the next PWM duty in the fade. This
- * calculation should never overflow:
- *
- * Max delta: 128
- * Max elapsed: 16,700,000 ticks
- * Max numerator: 2,137,600,000
- * Min denominator: 1
- * Max duty: 2,137,600,000
- * INT32_MAX 2,147,483,647
- */
- duty += ((int32_t)delta * (int32_t)elapsed) / delay;
- if (duty > 128)
- {
- duty = 128;
- }
- else if (duty < 0)
- {
- duty = 0;
- }
- }
- /* The set the new backlight PWM duty */
- ft80x_write_byte(priv, FT80X_REG_PWM_DUTY, (uint8_t)duty);
- }
- while (duty != endduty);
- return OK;
- }
- /****************************************************************************
- * Name: ft80x_notify
- *
- * Description:
- * Notify any registered client of the FT80x event
- *
- ****************************************************************************/
- static void ft80x_notify(FAR struct ft80x_dev_s *priv,
- enum ft80x_notify_e id, int value)
- {
- FAR struct ft80x_eventinfo_s *info = &priv->notify[id];
- /* Are notifications enabled for this event? */
- if (info->enable)
- {
- DEBUGASSERT(info->pid > 0);
- /* Yes.. Signal the client */
- info->event.sigev_value.sival_int = value;
- nxsig_notification(info->pid, &info->event, SI_QUEUE, &info->work);
- }
- }
- /****************************************************************************
- * Name: ft80x_interrupt_work
- *
- * Description:
- * Back end handling for FT80x interrupts
- *
- ****************************************************************************/
- static void ft80x_interrupt_work(FAR void *arg)
- {
- FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
- uint32_t intflags;
- uint32_t regval;
- DEBUGASSERT(priv != NULL);
- /* Get exclusive access to the device structures */
- ft80x_forcetake(&priv->exclsem);
- /* Get the set of pending interrupts. Note that simply reading this
- * register is sufficient to clear all pending interrupts.
- */
- intflags = ft80x_read_word(priv, FT80X_REG_INT_FLAGS);
- /* And process each pending interrupt.
- *
- * REVISIT: No interrupt sources are ever enabled in the current
- * implementation.
- */
- if ((intflags & FT80X_INT_SWAP) != 0)
- {
- /* Display swap occurred */
- lcdinfo("Display swap occurred\n");
- ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0);
- }
- if ((intflags & FT80X_INT_TOUCH) != 0)
- {
- /* Touch-screen touch detected */
- lcdinfo("Touch-screen touch detected\n");
- ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0);
- }
- if ((intflags & FT80X_INT_TAG) != 0)
- {
- /* Touch-screen tag value change */
- lcdinfo("Touch-screen tag value change\n");
- #ifdef CONFIG_LCD_FT800
- regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG);
- #else
- regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG);
- #endif
- ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK));
- }
- if ((intflags & FT80X_INT_SOUND) != 0)
- {
- /* Sound effect ended */
- lcdinfo(" Sound effect ended\n");
- ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0);
- }
- if ((intflags & FT80X_INT_PLAYBACK) != 0)
- {
- /* Audio playback ended */
- lcdinfo("Audio playback ended\n");
- ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0);
- }
- if ((intflags & FT80X_INT_CMDEMPTY) != 0)
- {
- /* Command FIFO empty */
- lcdinfo("Command FIFO empty\n");
- ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0);
- }
- if ((intflags & FT80X_INT_CMDFLAG) != 0)
- {
- /* Command FIFO flag */
- lcdinfo("Command FIFO flag\n");
- ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0);
- }
- if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
- {
- /* Touch-screen conversions completed */
- lcdinfo(" Touch-screen conversions completed\n");
- ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0);
- }
- /* Re-enable interrupts */
- DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
- priv->lower->enable(priv->lower, true);
- nxsem_post(&priv->exclsem);
- }
- /****************************************************************************
- * Name: ft80x_interrupt
- *
- * Description:
- * FT80x interrupt handler
- *
- ****************************************************************************/
- static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg)
- {
- FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
- DEBUGASSERT(priv != NULL);
- /* Perform the interrupt work on the high priority work queue. */
- work_queue(HPWORK, &priv->intwork, ft80x_interrupt_work, priv, 0);
- /* Disable further interrupts for the GPIO interrupt source.
- * REVISIT: This assumes that GPIO interrupts will pend until re-enabled.
- * In certain implementations, that assumption is not true and could cause
- * a loss of interrupts.
- */
- DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
- priv->lower->enable(priv->lower, false);
- return OK;
- }
- /****************************************************************************
- * Name: ft80x_destroy
- *
- * Description:
- * The driver has been unlinked... clean up as best we can.
- *
- ****************************************************************************/
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- static void ft80x_destroy(FAR struct ft80x_dev_s *priv)
- {
- /* If the lower half driver provided a destroy method, then call that
- * method now in order order to clean up resources used by the lower-half
- * driver.
- */
- DEBUGASSERT(priv != NULL && priv->lower != NULL);
- if (priv->lower->destroy != NULL)
- {
- priv->lower->destroy(priv->lower);
- }
- /* Then free our container */
- nxsem_destroy(&priv->exclsem);
- kmm_free(priv);
- }
- #endif
- /****************************************************************************
- * Name: ft80x_open
- *
- * Description:
- * This function is called whenever the PWM device is opened.
- *
- ****************************************************************************/
- static int ft80x_open(FAR struct file *filep)
- {
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- FAR struct inode *inode;
- FAR struct ft80x_dev_s *priv;
- uint8_t tmp;
- int ret;
- DEBUGASSERT(filep != NULL);
- inode = filep->f_inode;
- DEBUGASSERT(inode != NULL && inode->i_private != NULL);
- priv = inode->i_private;
- lcdinfo("crefs: %d\n", priv->crefs);
- /* Get exclusive access to the device structures */
- ret = nxsem_wait(&priv->exclsem);
- if (ret < 0)
- {
- goto errout;
- }
- /* Increment the count of references to the device */
- tmp = priv->crefs + 1;
- if (tmp == 0)
- {
- /* More than 255 opens; uint8_t overflows to zero */
- ret = -EMFILE;
- goto errout_with_sem;
- }
- /* Save the new open count */
- priv->crefs = tmp;
- ret = OK;
- errout_with_sem:
- nxsem_post(&priv->exclsem);
- errout:
- return ret;
- #else
- return OK;
- #endif
- }
- /****************************************************************************
- * Name: ft80x_close
- *
- * Description:
- * This function is called when the PWM device is closed.
- *
- ****************************************************************************/
- static int ft80x_close(FAR struct file *filep)
- {
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- FAR struct inode *inode;
- FAR struct ft80x_dev_s *priv;
- int ret;
- DEBUGASSERT(filep != NULL);
- inode = filep->f_inode;
- DEBUGASSERT(inode != NULL && inode->i_private != NULL);
- priv = inode->i_private;
- lcdinfo("crefs: %d\n", priv->crefs);
- /* Get exclusive access to the device structures */
- ret = nxsem_wait(&priv->exclsem);
- if (ret < 0)
- {
- goto errout;
- }
- /* Will the count decrement to zero? */
- if (priv->crefs <= 1)
- {
- /* Yes.. if the driver has been unlinked, then we need to destroy the
- * driver instance.
- */
- priv->crefs = 0;
- if (priv->unlinked)
- {
- ft80x_destroy(priv);
- return OK;
- }
- }
- else
- {
- /* NO.. decrement the number of references to the driver. */
- priv->crefs--;
- }
- ret = OK;
- nxsem_post(&priv->exclsem);
- errout:
- return ret;
- #else
- return OK;
- #endif
- }
- /****************************************************************************
- * Name: ft80x_read
- ****************************************************************************/
- static ssize_t ft80x_read(FAR struct file *filep, FAR char *buffer,
- size_t len)
- {
- /* Reading from the FT80X is an undefined operation and not support */
- lcdinfo("buffer: %p len %lu\n", buffer, (unsigned long)len);
- return 0; /* Return EOF */
- }
- /****************************************************************************
- * Name: ft80x_write
- ****************************************************************************/
- static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
- size_t len)
- {
- FAR struct inode *inode;
- FAR struct ft80x_dev_s *priv;
- int ret;
- lcdinfo("buffer: %p len %lu\n", buffer, (unsigned long)len);
- DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 3) == 0 &&
- len > 0 && (len & 3) == 0 && len <= FT80X_RAM_DL_SIZE);
- DEBUGASSERT(filep != NULL);
- inode = filep->f_inode;
- DEBUGASSERT(inode != NULL && inode->i_private != NULL);
- priv = inode->i_private;
- if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 ||
- len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE)
- {
- return -EINVAL;
- }
- /* Get exclusive access to the device structures */
- ret = nxsem_wait(&priv->exclsem);
- if (ret < 0)
- {
- return ret;
- }
- /* Note that there is no check if the driver was opened read-only. That
- * would be a silly thing to do.
- */
- /* The write method is functionally equivalent to the FT80X_IOC_CREATEDL
- * IOCTL command: It simply copies the display list in the user buffer to
- * the FT80x display list memory.
- */
- ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos, buffer, len);
- filep->f_pos += len;
- nxsem_post(&priv->exclsem);
- return len;
- }
- /****************************************************************************
- * Name: ft80x_ioctl
- *
- * Description:
- * The standard ioctl method. This is where ALL of the PWM work is done.
- *
- ****************************************************************************/
- static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
- {
- FAR struct inode *inode;
- FAR struct ft80x_dev_s *priv;
- int ret;
- DEBUGASSERT(filep != NULL);
- inode = filep->f_inode;
- DEBUGASSERT(inode != NULL && inode->i_private != NULL);
- priv = inode->i_private;
- lcdinfo("cmd: %d arg: %lu\n", cmd, arg);
- /* Get exclusive access to the device structures */
- ret = nxsem_wait(&priv->exclsem);
- if (ret < 0)
- {
- return ret;
- }
- /* Handle built-in ioctl commands */
- switch (cmd)
- {
- /* FT80X_IOC_CREATEDL:
- * Description: Write a display list to the FT80x display list
- * memory
- * Description: Write a display list to the FT80x display list
- * memory starting at offset zero. This may or may
- * not be the entire display list. Display lists may
- * be created incrementally, starting with
- * FT80X_IOC_CREATEDL and finishing the display list
- * using FT80XIO_APPENDDL
- * Argument: A reference to a display list structure instance.
- * See struct ft80x_displaylist_s.
- * Returns: None
- */
- case FT80X_IOC_CREATEDL:
- /* Set the file position to zero and fall through to "append" the new
- * display list data at offset 0.
- */
- filep->f_pos = 0;
- /* FALLTHROUGH */
- /* FT80X_IOC_APPENDDL:
- * Description: Write additional display list entries to the FT80x
- * display list memory at the current display list
- * offset. This IOCTL command permits display lists
- * to be completed incrementally, starting with
- * FT80X_IOC_CREATEDL and finishing the display list
- * using FT80XIO_APPENDDL.
- * Argument: A reference to a display list structure instance.
- * See struct ft80x_displaylist_s.
- * Returns: None
- */
- case FT80X_IOC_APPENDDL:
- {
- FAR struct ft80x_displaylist_s *dl =
- (FAR struct ft80x_displaylist_s *)((uintptr_t)arg);
- if (dl == NULL || ((uintptr_t)&dl->cmd & 3) != 0 ||
- (dl->dlsize & 3) != 0 ||
- dl->dlsize + filep->f_pos > FT80X_RAM_DL_SIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- /* Check if there is a display list. It might be useful for
- * the application to issue FT80X_IOC_CREATEDL with no data in
- * order to initialize the display list, then form all of the
- * list entries with FT80X_IOC_APPENDDL.
- */
- if (dl->dlsize > 0)
- {
- /* This IOCTL command simply copies the display list
- * provided into the FT80x display list memory.
- */
- ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos,
- &dl->cmd, dl->dlsize);
- filep->f_pos += dl->dlsize;
- }
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_GETRAMDL:
- * Description: Read a 32-bit value from the display list.
- * Argument: A reference to an instance of struct ft80x_relmem_s.
- * Returns: The 32-bit value read from the display list.
- */
- case FT80X_IOC_GETRAMDL:
- {
- FAR struct ft80x_relmem_s *ramdl =
- (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
- if (ramdl == NULL || ((uintptr_t)ramdl->offset & 3) != 0 ||
- ramdl->offset >= FT80X_RAM_DL_SIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_read_memory(priv, FT80X_RAM_DL + ramdl->offset,
- ramdl->value, ramdl->nbytes);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTRAMG
- * Description: Write byte data to FT80x graphics memory (RAM_G)
- * Argument: A reference to an instance of struct ft80x_relmem_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTRAMG:
- {
- FAR struct ft80x_relmem_s *ramg =
- (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
- if (ramg == NULL ||
- (ramg->offset + ramg->nbytes) >= FT80X_RAM_G_SIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_memory(priv, FT80X_RAM_G + ramg->offset,
- ramg->value, ramg->nbytes);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTRAMCMD
- * Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
- * Argument: A reference to an instance of struct ft80x_relmem_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTRAMCMD:
- {
- FAR struct ft80x_relmem_s *ramcmd =
- (FAR struct ft80x_relmem_s *)((uintptr_t)arg);
- if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_memory(priv, FT80X_RAM_CMD + ramcmd->offset,
- ramcmd->value, ramcmd->nbytes);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_GETREG8:
- * Description: Read an 8-bit register value from the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: The 8-bit value read from the register.
- */
- case FT80X_IOC_GETREG8:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- reg->value.u8 = ft80x_read_byte(priv, reg->addr);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_GETREG16:
- * Description: Read a 16-bit register value from the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: The 16-bit value read from the register.
- */
- case FT80X_IOC_GETREG16:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- reg->value.u16 = ft80x_read_hword(priv, reg->addr);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_GETREG32:
- * Description: Read a 32-bit register value from the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: The 32-bit value read from the register.
- */
- case FT80X_IOC_GETREG32:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- reg->value.u32 = ft80x_read_word(priv, reg->addr);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_GETREGS:
- * Description: Read multiple 32-bit register values from the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_registers_s.
- * Returns: The 32-bit values read from the consecutive
- * registers .
- */
- case FT80X_IOC_GETREGS:
- {
- FAR struct ft80x_registers_s *regs =
- (FAR struct ft80x_registers_s *)((uintptr_t)arg);
- if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_read_memory(priv, regs->addr, regs->value,
- (size_t)regs->nregs << 2);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTREG8:
- * Description: Write an 8-bit register value to the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTREG8:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_byte(priv, reg->addr, reg->value.u8);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTREG16:
- * Description: Write a 16-bit register value to the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTREG16:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_hword(priv, reg->addr, reg->value.u16);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTREG32:
- * Description: Write a 32-bit register value to the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_register_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTREG32:
- {
- FAR struct ft80x_register_s *reg =
- (FAR struct ft80x_register_s *)((uintptr_t)arg);
- if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_word(priv, reg->addr, reg->value.u32);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_PUTREGS:
- * Description: Write multiple 32-bit register values to the FT80x.
- * Argument: A reference to an instance of struct
- * ft80x_registers_s.
- * Returns: None.
- */
- case FT80X_IOC_PUTREGS:
- {
- FAR struct ft80x_registers_s *regs =
- (FAR struct ft80x_registers_s *)((uintptr_t)arg);
- if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
- {
- ret = -EINVAL;
- }
- else
- {
- ft80x_write_memory(priv, regs->addr, regs->value,
- (size_t)regs->nregs << 2);
- ret = OK;
- }
- }
- break;
- /* FT80X_IOC_EVENTNOTIFY:
- * Description: Setup to receive a signal when an event occurs.
- * Argument: A reference to an instance of struct ft80x_notify_s.
- * Returns: None
- */
- case FT80X_IOC_EVENTNOTIFY:
- {
- FAR struct ft80x_notify_s *notify =
- (FAR struct ft80x_notify_s *)((uintptr_t)arg);
- if (notify == NULL || notify->pid < 0 ||
- (unsigned int)notify->id >= FT80X_INT_NEVENTS)
- {
- ret = -EINVAL;
- }
- else
- {
- FAR struct ft80x_eventinfo_s *info = &priv->notify[notify->id];
- uint32_t regval;
- /* Are we enabling or disabling */
- if (notify->enable)
- {
- /* Make sure that arguments are valid for the enable */
- if (notify->pid == 0)
- {
- ret = -EINVAL;
- }
- else
- {
- /* Setup the new notification information */
- info->event = notify->event;
- info->pid = notify->pid;
- info->enable = true;
- /* Enable interrupts associated with the event */
- regval = ft80x_read_word(priv, FT80X_REG_INT_MASK);
- regval |= (1 << notify->id);
- ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);
- ret = OK;
- }
- }
- else
- {
- /* Disable the notification */
- info->pid = 0;
- info->enable = false;
- /* Disable interrupts associated with the event */
- regval = ft80x_read_word(priv, FT80X_REG_INT_MASK);
- regval &= ~(1 << notify->id);
- ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);
- /* Cancel any pending notification */
- nxsig_cancel_notification(&info->work);
- ret = OK;
- }
- }
- }
- break;
- /* FT80X_IOC_FADE:
- * Description: Change the backlight intensity with a controllable
- * fade.
- * Argument: A reference to an instance of struct ft80x_fade_s.
- * Returns: None.
- */
- case FT80X_IOC_FADE:
- {
- FAR const struct ft80x_fade_s *fade =
- (FAR const struct ft80x_fade_s *)((uintptr_t)arg);
- if (fade == NULL || fade->duty > 100 ||
- fade->delay < MIN_FADE_DELAY || fade->delay > MAX_FADE_DELAY)
- {
- ret = -EINVAL;
- }
- else
- {
- ret = ft80x_fade(priv, fade);
- }
- }
- break;
- /* FT80X_IOC_AUDIO:
- * Description: Enable/disable an external audio amplifier.
- * Argument: 0=disable; 1=enable.
- * Returns: None.
- */
- case FT80X_IOC_AUDIO:
- {
- #if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
- /* Amplifier is controlled by an MCU GPIO pin */
- DEBUGASSERT(priv->lower->attach != NULL &&
- priv->lower->audio != NULL);
- DEBUGASSERT(arg == 0 || arg == 1);
- priv->lower->audio(priv->lower, (arg != 0));
- ret = OK;
- #elif defined(CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN)
- /* Amplifier is controlled by an FT80x GPIO pin */
- uint8_t regval8;
- DEBUGASSERT(arg == 0 || arg == 1);
- regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO);
- /* Active low logic assumed */
- if (arg == 0)
- {
- regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
- }
- else
- {
- regval8 &= ~(1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
- }
- ft80x_write_byte(priv, FT80X_REG_GPIO, regval8);
- ret = OK;
- #else
- /* Amplifier is not controllable. */
- DEBUGASSERT(arg == 0 || arg == 1);
- return OK;
- #endif
- }
- break;
- /* Unrecognized IOCTL command */
- default:
- lcderr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg);
- ret = -ENOTTY;
- break;
- }
- nxsem_post(&priv->exclsem);
- return ret;
- }
- /****************************************************************************
- * Name: ft80x_unlink
- ****************************************************************************/
- #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
- static int ft80x_unlink(FAR struct inode *inode)
- {
- FAR struct ft80x_dev_s *priv;
- /* Get the reference to our internal state structure from the inode
- * structure.
- */
- DEBUGASSERT(inode && inode->i_private);
- priv = inode->i_private;
- /* Indicate that the driver has been unlinked */
- priv->unlinked = true;
- /* If there are no further open references to the driver, then commit
- * Hara-Kiri now.
- */
- if (priv->crefs == 0)
- {
- ft80x_destroy(priv);
- }
- return OK;
- }
- #endif
- /****************************************************************************
- * Name: ft80x_initialize
- *
- * Description:
- * Initialize the FT80x
- *
- ****************************************************************************/
- static int ft80x_initialize(FAR struct ft80x_dev_s *priv)
- {
- uint32_t timeout;
- uint32_t regval32;
- uint8_t regval8;
- /* To configure the display, load the timing control registers with values
- * for the particular display. These registers control horizontal timing:
- *
- * - FT80X_REG_PCLK
- * - FT80X_REG_PCLK_POL
- * - FT80X_REG_HCYCLE
- * - FT80X_REG_HOFFSET
- * - FT80X_REG_HSIZE
- * - FT80X_REG_HSYNC0
- * - FT80X_REG_HSYNC1
- *
- * These registers control vertical timing:
- *
- * - FT80X_REG_VCYCLE
- * - FT80X_REG_VOFFSET
- * - FT80X_REG_VSIZE
- * - FT80X_REG_VSYNC0
- * - FT80X_REG_VSYNC1
- *
- * And the FT80X_REG_CSPREAD register changes color clock timing to reduce
- * system noise.
- *
- * GPIO bit 7 is used for the display enable pin of the LCD module. By
- * setting the direction of the GPIO bit to out direction, the display can
- * be enabled by writing value of 1 into GPIO bit 7 or the display can be
- * disabled by writing a value of 0 into GPIO bit 7. By default GPIO bit 7
- * direction is output and the value is 0.
- */
- /* Initialization Sequence from Power Down using PD_N pin:
- *
- * 1. Drive the PD_N pin high
- * 2. Wait for at least 20ms
- * 3. Execute "Initialization Sequence during the Boot up" from steps 1
- * to 9
- *
- * Initialization Sequence from Sleep Mode:
- *
- * 1. Send Host command "ACTIVE" to enable clock to FT800
- * 2. Wait for at least 20ms
- * 3. Execute "Initialization Sequence during Boot Up" from steps 5 to 8
- *
- * Initialization sequence from standby mode:
- *
- * Execute all the steps mentioned in "Initialization Sequence from Sleep
- * Mode" except waiting for at least 20ms in step 2.
- */
- DEBUGASSERT(priv->lower != NULL && priv->lower->pwrdown != NULL);
- priv->lower->pwrdown(priv->lower, false);
- up_mdelay(20);
- /* Initialization Sequence during the boot up:
- *
- * 1. Use MCU SPI clock not more than 11MHz
- * 2. Send Host command CLKEXT to FT800 to enable PLL input from oscillator
- * or external clock. Should default to 48MHz PLL output.
- * 3. Send Host command ACTIVE to enable clock and wake up the FT80x.
- * 4. Configure video timing registers, except FT80X_REG_PCLK
- * 5. Write first display list
- * 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately
- * 7. Enable back light control for display
- * 8. Write FT80X_REG_PCLK, video output begins with the first display list
- * 9. Use MCU SPI clock not more than 30MHz
- */
- /* 1. Select the initial SPI frequency */
- DEBUGASSERT(priv->lower->init_frequency <= 11000000);
- priv->frequency = priv->lower->init_frequency;
- /* 2. Send Host command CLKEXT to FT800 to enable PLL input from oscillator
- * or external clock.
- */
- ft80x_host_command(priv, FT80X_CMD_CLKEXT);
- up_mdelay(10);
- #if 0 /* Un-necessary? */
- /* Switch PLL output to 48MHz (should be the default) */
- ft80x_host_command(priv, FT80X_CMD_CLK48M);
- up_mdelay(10);
- #endif
- /* 3. Send Host command ACTIVE to enable clock and wake up the FT80x. */
- ft80x_host_command(priv, FT80X_CMD_ACTIVE);
- up_mdelay(10);
- #if 0 /* Un-necessary? */
- /* Do a core reset for safer */
- ft80x_host_command(priv, FT80X_CMD_CORERST);
- #endif
- /* Verify the chip ID. Read repeatedly until FT80x is ready. */
- timeout = 0;
- for (; ; )
- {
- /* Read the Chip ID */
- regval8 = ft80x_read_byte(priv, FT80X_REG_ID);
- if (regval8 == CHIPID)
- {
- /* Chip ID verify so FT80x is ready */
- break;
- }
- /* Initial Chip ID read may fail because the chip is not yet ready. */
- if (++timeout > 100000)
- {
- lcderr("ERROR: Bad chip ID: %02x\n", regval8);
- return -ENODEV;
- }
- }
- regval32 = ft80x_read_word(priv, FT80X_ROM_CHIPID);
- if ((regval32 & ROMID_MASK) != ROMID)
- {
- lcderr("ERROR: Bad ROM chip ID: %08lx\n", (unsigned long)regval32);
- return -ENODEV;
- }
- /* 4. Configure video timing registers, except FT80X_REG_PCLK
- *
- * Once the FT800 is awake and the internal clock set and Device ID
- * checked, the next task is to configure the LCD display parameters for
- * the chosen display with the values determined in Section 2.3.3 above.
- *
- * a. Set FT80X_REG_PCLK to zero - This disables the pixel clock output
- * while the LCD and other system parameters are configured
- * b. Set the following registers with values for the chosen display.
- * Typical WQVGA and QVGA values are shown:
- *
- * Register Description WQVGA QVGA
- * 480x272 320x240
- * FT80X_REG_PCLK_POL Pixel Clock Polarity 1 0
- * FT80X_REG_HSIZE Image width in pixels 480 320
- * FT80X_REG_HCYCLE Total number of clocks per line 548 408
- * FT80X_REG_HOFFSET Horizontal image start 43 70
- * (pixels from left)
- * FT80X_REG_HSYNC0 Start of HSYNC pulse 0 0
- * (falling edge)
- * FT80X_REG_HSYNC1 End of HSYNC pulse 41 10
- * (rising edge)
- * FT80X_REG_VSIZE Image height in pixels 272 240
- * FT80X_REG_VCYCLE Total number of lines per screen 292 263
- * FT80X_REG_VOFFSET Vertical image start 12 13
- * (lines from top)
- * FT80X_REG_VSYNC0 Start of VSYNC pulse 0 0
- * (falling edge)
- * FT80X_REG_VSYNC1 End of VSYNC pulse 10 2
- * (rising edge)
- *
- * c. Enable or disable FT80X_REG_CSPREAD with a value of 01h or 00h,
- * respectively. Enabling FT80X_REG_CSPREAD will offset the R, G and B
- * output bits so all they do not all change at the same time.
- */
- ft80x_write_byte(priv, FT80X_REG_PCLK, 0);
- #if defined(CONFIG_LCD_FT80X_WQVGA)
- ft80x_write_hword(priv, FT80X_REG_HCYCLE, 548);
- ft80x_write_hword(priv, FT80X_REG_HOFFSET, 43);
- ft80x_write_hword(priv, FT80X_REG_HSYNC0, 0);
- ft80x_write_hword(priv, FT80X_REG_HSYNC1, 41);
- ft80x_write_hword(priv, FT80X_REG_VCYCLE, 292);
- ft80x_write_hword(priv, FT80X_REG_VOFFSET, 12);
- ft80x_write_hword(priv, FT80X_REG_VSYNC0, 0);
- ft80x_write_hword(priv, FT80X_REG_VSYNC1, 10);
- ft80x_write_byte(priv, FT80X_REG_SWIZZLE, 0);
- ft80x_write_byte(priv, FT80X_REG_PCLK_POL, 1);
- ft80x_write_byte(priv, FT80X_REG_CSPREAD, 1);
- ft80x_write_hword(priv, FT80X_REG_HSIZE, 480);
- ft80x_write_hword(priv, FT80X_REG_VSIZE, 272);
- #elif defined(CONFIG_LCD_FT80X_QVGA)
- ft80x_write_hword(priv, FT80X_REG_HCYCLE, 408);
- ft80x_write_hword(priv, FT80X_REG_HOFFSET, 70);
- ft80x_write_hword(priv, FT80X_REG_HSYNC0, 0);
- ft80x_write_hword(priv, FT80X_REG_HSYNC1, 10);
- ft80x_write_hword(priv, FT80X_REG_VCYCLE, 263);
- ft80x_write_hword(priv, FT80X_REG_VOFFSET, 13);
- ft80x_write_hword(priv, FT80X_REG_VSYNC0, 0);
- ft80x_write_hword(priv, FT80X_REG_VSYNC1, 2);
- ft80x_write_byte(priv, FT80X_REG_SWIZZLE, 2);
- ft80x_write_byte(priv, FT80X_REG_PCLK_POL, 0);
- ft80x_write_byte(priv, FT80X_REG_CSPREAD, 1);
- ft80x_write_hword(priv, FT80X_REG_HSIZE, 320);
- ft80x_write_hword(priv, FT80X_REG_VSIZE, 240);
- #else
- # error Unknown display size
- #endif
- /* 5. Write first display list */
- ft80x_write_word(priv, FT80X_RAM_DL + 0, FT80X_CLEAR_COLOR_RGB(0, 0, 0));
- ft80x_write_word(priv, FT80X_RAM_DL + 4, FT80X_CLEAR(1, 1, 1));
- ft80x_write_word(priv, FT80X_RAM_DL + 8, FT80X_DISPLAY());
- /* 6. Write FT80X_REG_DLSWAP, FT800 swaps display list immediately */
- ft80x_write_byte(priv, FT80X_REG_DLSWAP, DLSWAP_FRAME);
- /* GPIO bit 7 is used for the display enable pin of the LCD module. By
- * setting the direction of the GPIO bit to out direction, the display can
- * be enabled by writing value of 1 into GPIO bit 7 or the display can be
- * disabled by writing a value of 0 into GPIO bit 7. By default GPIO bit 7
- * direction is output and the value is 0.
- *
- * If an external audio amplified is controlled by an FT80x GPIO, then
- * configure that GPIO as well. Active low logic is assumed so that the
- * amplifier is initially in the shutdown state.
- */
- regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO_DIR);
- regval8 |= (1 << 7);
- #ifdef CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN
- regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
- #endif
- ft80x_write_byte(priv, FT80X_REG_GPIO_DIR, regval8);
- regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO);
- regval8 |= (1 << 7);
- #ifdef CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN
- regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
- #endif
- ft80x_write_byte(priv, FT80X_REG_GPIO, regval8);
- /* 7. Enable back light control for display */
- #warning Missing logic
- /* 8. Write FT80X_REG_PCLK, video output with the first display list */
- #if defined(CONFIG_LCD_FT80X_WQVGA)
- ft80x_write_byte(priv, FT80X_REG_PCLK, 5);
- #elif defined(CONFIG_LCD_FT80X_QVGA)
- ft80x_write_byte(priv, FT80X_REG_PCLK, 8);
- #else
- # error Unknown display size
- #endif
- /* 9. Use MCU SPI clock not more than 30MHz */
- DEBUGASSERT(priv->lower->op_frequency <= 30000000);
- priv->frequency = priv->lower->op_frequency;
- /* Configure touch mode. Using default touch mode of FRAME_SYNC (~60Hz) */
- ft80x_write_byte(priv, FT80X_REG_TOUCH_MODE, TOUCH_MODE_FRAMESYNC);
- #if defined(CONFIG_LCD_FT800)
- /* Configure the touch threshold. The value 1200 may need to be tweaked
- * for your application.
- */
- ft80x_write_hword(priv, FT80X_REG_TOUCH_RZTHRESH, 1200);
- #elif defined(CONFIG_LCD_FT801)
- #ifdef CONFIG_LCD_FT801_MULTITOUCH
- /* Selected extended mode */
- ft80x_write_byte(priv, FT80X_REG_CTOUCH_EXTENDED, 0);
- #else
- /* Selected compatibility mode */
- ft80x_write_byte(priv, FT80X_REG_CTOUCH_EXTENDED, 1);
- #endif
- #else
- # error No FT80x device configured
- #endif
- return OK;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: ft80x_register
- *
- * Description:
- * Configure the ADS7843E to use the provided SPI device instance. This
- * will register the driver as /dev/ft800 or /dev/ft801, depending upon
- * the configuration.
- *
- * Input Parameters:
- * spi - An SPI driver instance
- * i2c - An I2C master driver instance
- * lower - Persistent board configuration data / lower half interface
- *
- * Returned Value:
- * Zero is returned on success. Otherwise, a negated errno value is
- * returned to indicate the nature of the failure.
- *
- ****************************************************************************/
- #if defined(CONFIG_LCD_FT80X_SPI)
- int ft80x_register(FAR struct spi_dev_s *spi,
- FAR const struct ft80x_config_s *lower)
- #elif defined(CONFIG_LCD_FT80X_I2C)
- int ft80x_register(FAR struct i2c_master_s *i2c,
- FAR const struct ft80x_config_s *lower)
- #endif
- {
- FAR struct ft80x_dev_s *priv;
- int ret;
- #if defined(CONFIG_LCD_FT80X_SPI)
- DEBUGASSERT(spi != NULL && lower != NULL);
- #elif defined(CONFIG_LCD_FT80X_I2C)
- DEBUGASSERT(i2c != NULL && lower != NULL);
- #endif
- /* Allocate the driver state structure */
- priv = (FAR struct ft80x_dev_s *)kmm_zalloc(sizeof(struct ft80x_dev_s));
- if (priv == NULL)
- {
- lcderr("ERROR: Failed to allocate state structure\n");
- return -ENOMEM;
- }
- /* Save the lower level interface and configuration information */
- priv->lower = lower;
- #ifdef CONFIG_LCD_FT80X_SPI
- /* Remember the SPI configuration */
- priv->spi = spi;
- #else
- /* Remember the I2C configuration */
- priv->i2c = i2c;
- #endif
- /* Initialize the mutual exclusion semaphore */
- nxsem_init(&priv->exclsem, 0, 1);
- /* Initialize the FT80x */
- ret = ft80x_initialize(priv);
- if (ret < 0)
- {
- goto errout_with_sem;
- }
- /* Attach our interrupt handler */
- DEBUGASSERT(lower->attach != NULL && lower->enable != NULL);
- ret = lower->attach(lower, ft80x_interrupt, priv);
- if (ret < 0)
- {
- goto errout_with_sem;
- }
- /* Disable all interrupt sources, but enable interrupts both in the lower
- * half driver and in the FT80x.
- */
- ft80x_write_word(priv, FT80X_REG_INT_MASK, 0);
- ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_ENABLE);
- lower->enable(lower, true);
- /* Register the FT80x character driver */
- ret = register_driver(DEVNAME, &g_ft80x_fops, 0666, priv);
- if (ret < 0)
- {
- goto errout_with_interrupts;
- }
- return OK;
- errout_with_interrupts:
- lower->enable(lower, false);
- ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_DISABLE);
- lower->attach(lower, NULL, NULL);
- errout_with_sem:
- nxsem_destroy(&priv->exclsem);
- return ret;
- }
- #endif /* CONFIG_LCD_FT80X */
|