Commit 59d0612252a0ffcb878a1891249d32a306a24fa6

Authored by Richard Retanubun
Committed by Jason
1 parent 198cafbf2c
Exists in master and in 57 other branches 8qm-imx_v2020.04_5.4.70_2.3.0, emb_lf-6.6.52-2.2.0, emb_lf_v2022.04, emb_lf_v2023.04, emb_lf_v2024.04, imx_v2015.04_4.1.15_1.0.0_ga, pitx_8mp_lf_v2020.04, smarc-8m-android-10.0.0_2.6.0, smarc-8m-android-11.0.0_2.0.0, smarc-8mp-android-11.0.0_2.0.0, smarc-emmc-imx_v2014.04_3.10.53_1.1.0_ga, smarc-emmc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx-l5.0.0_1.0.0-ga, smarc-imx6_v2018.03_4.14.98_2.0.0_ga, smarc-imx7_v2017.03_4.9.11_1.0.0_ga, smarc-imx7_v2018.03_4.14.98_2.0.0_ga, smarc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx_v2015.04_4.1.15_1.0.0_ga, smarc-imx_v2017.03_4.9.11_1.0.0_ga, smarc-imx_v2017.03_4.9.88_2.0.0_ga, smarc-imx_v2017.03_o8.1.0_1.3.0_8m, smarc-imx_v2018.03_4.14.78_1.0.0_ga, smarc-m6.0.1_2.1.0-ga, smarc-n7.1.2_2.0.0-ga, smarc-rel_imx_4.1.15_2.0.0_ga, smarc_8m-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8m-imx_v2019.04_4.19.35_1.1.0, smarc_8m_00d0-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2019.04_4.19.35_1.1.0, smarc_8mm-imx_v2020.04_5.4.24_2.1.0, smarc_8mp_lf_v2020.04, smarc_8mq-imx_v2020.04_5.4.24_2.1.0, smarc_8mq_lf_v2020.04, ti-u-boot-2015.07, u-boot-2013.01.y, v2013.10, v2013.10-smarct33, v2013.10-smartmen, v2014.01, v2014.04, v2014.04-smarct33, v2014.04-smarct33-emmc, v2014.04-smartmen, v2014.07, v2014.07-smarct33, v2014.07-smartmen, v2015.07-smarct33, v2015.07-smarct33-emmc, v2015.07-smarct4x, v2016.05-dlt, v2016.05-smarct3x, v2016.05-smarct3x-emmc, v2016.05-smarct4x, v2017.01-smarct3x, v2017.01-smarct3x-emmc, v2017.01-smarct4x

ColdFire: Queued SPI driver

This patch adds a driver for Freescale Colfire Queued SPI bus.
Coded to work with 8 bits per transfer to use with SPI flash.
CPOL, CPHA, and CS_ACTIVE_HIGH can be configured.

Tested with MCF5270 which have 4 chip selects.

Activate by #define CONFIG_CF_QSPI in board config.

Signed-off-by: Richard Retanubun <richardretanubun@ruggedcom.com>

Showing 5 changed files with 415 additions and 2 deletions Side-by-side Diff

arch/m68k/cpu/mcf52x2/cpu_init.c
... ... @@ -333,7 +333,20 @@
333 333 return 0;
334 334 }
335 335 #endif /* CONFIG_CMD_NET */
336   -#endif
  336 +
  337 +#if defined(CONFIG_CF_QSPI)
  338 +
  339 +/* Configure PIOs for SIN, SOUT, and SCK */
  340 +void cfspi_port_conf(void)
  341 +{
  342 + mbar_writeByte(MCF_GPIO_PAR_QSPI,
  343 + MCF_GPIO_PAR_QSPI_SIN_SIN |
  344 + MCF_GPIO_PAR_QSPI_SOUT_SOUT |
  345 + MCF_GPIO_PAR_QSPI_SCK_SCK);
  346 +}
  347 +#endif /* CONFIG_CF_QSPI */
  348 +
  349 +#endif /* CONFIG_M5271 */
337 350  
338 351 #if defined(CONFIG_M5272)
339 352 /*
arch/m68k/include/asm/coldfire/qspi.h
... ... @@ -98,7 +98,7 @@
98 98 #define QSPI_QAR_RECV (0x0010)
99 99 #define QSPI_QAR_CMD (0x0020)
100 100  
101   -/* DR */
  101 +/* DR with RAM command word definitions */
102 102 #define QSPI_QDR_CONT (0x8000)
103 103 #define QSPI_QDR_BITSE (0x4000)
104 104 #define QSPI_QDR_DT (0x2000)
arch/m68k/include/asm/m5271.h
... ... @@ -171,6 +171,32 @@
171 171 #define MCF_GPIO_PAR_UART_U1RXD_UART1 0x0C00
172 172 #define MCF_GPIO_PAR_UART_U1TXD_UART1 0x0300
173 173  
  174 +/* Bit definitions and macros for PAR_QSPI */
  175 +#define MCF_GPIO_PAR_QSPI_PCS1_UNMASK 0x3F
  176 +#define MCF_GPIO_PAR_QSPI_PCS1_PCS1 0xC0
  177 +#define MCF_GPIO_PAR_QSPI_PCS1_SDRAM_SCKE 0x80
  178 +#define MCF_GPIO_PAR_QSPI_PCS1_GPIO 0x00
  179 +#define MCF_GPIO_PAR_QSPI_PCS0_UNMASK 0xDF
  180 +#define MCF_GPIO_PAR_QSPI_PCS0_PCS0 0x20
  181 +#define MCF_GPIO_PAR_QSPI_PCS0_GPIO 0x00
  182 +#define MCF_GPIO_PAR_QSPI_SIN_UNMASK 0xE7
  183 +#define MCF_GPIO_PAR_QSPI_SIN_SIN 0x18
  184 +#define MCF_GPIO_PAR_QSPI_SIN_I2C_SDA 0x10
  185 +#define MCF_GPIO_PAR_QSPI_SIN_GPIO 0x00
  186 +#define MCF_GPIO_PAR_QSPI_SOUT_UNMASK 0xFB
  187 +#define MCF_GPIO_PAR_QSPI_SOUT_SOUT 0x04
  188 +#define MCF_GPIO_PAR_QSPI_SOUT_GPIO 0x00
  189 +#define MCF_GPIO_PAR_QSPI_SCK_UNMASK 0xFC
  190 +#define MCF_GPIO_PAR_QSPI_SCK_SCK 0x03
  191 +#define MCF_GPIO_PAR_QSPI_SCK_I2C_SCL 0x02
  192 +#define MCF_GPIO_PAR_QSPI_SCK_GPIO 0x00
  193 +
  194 +/* Bit definitions and macros for PAR_TIMER for QSPI */
  195 +#define MCF_GPIO_PAR_TIMER_T3IN_UNMASK 0x3FFF
  196 +#define MCF_GPIO_PAR_TIMER_T3IN_QSPI_PCS2 0x4000
  197 +#define MCF_GPIO_PAR_TIMER_T3OUT_UNMASK 0xFF3F
  198 +#define MCF_GPIO_PAR_TIMER_T3OUT_QSPI_PCS3 0x0040
  199 +
174 200 #define MCF_GPIO_PAR_SDRAM_PAR_CSSDCS(x) (((x)&0x03)<<6)
175 201  
176 202 #define MCF_SDRAMC_DCR 0x000040
drivers/spi/Makefile
... ... @@ -32,6 +32,7 @@
32 32 COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
33 33 COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o
34 34 COBJS-$(CONFIG_CF_SPI) += cf_spi.o
  35 +COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
35 36 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
36 37 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
37 38 COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
drivers/spi/cf_qspi.c
  1 +/*
  2 + * Freescale Coldfire Queued SPI driver
  3 + *
  4 + * NOTE:
  5 + * This driver is written to transfer 8 bit at-a-time and uses the dedicated
  6 + * SPI slave select pins as bit-banged GPIO to work with spi_flash subsystem.
  7 + *
  8 + *
  9 + * Copyright (C) 2011 Ruggedcom, Inc.
  10 + * Richard Retanubun (richardretanubun@freescale.com)
  11 + *
  12 + * See file CREDITS for list of people who contributed to this project.
  13 + *
  14 + * This program is free software; you can redistribute it and/or
  15 + * modify it under the terms of the GNU General Public License as
  16 + * published by the Free Software Foundation; either version 2 of
  17 + * the License, or (at your option) any later version.
  18 + *
  19 + * This program is distributed in the hope that it will be useful,
  20 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22 + * GNU General Public License for more details.
  23 + *
  24 + * You should have received a copy of the GNU General Public License
  25 + * along with this program; if not, write to the Free Software
  26 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27 + * MA 02111-1307 USA
  28 + */
  29 +
  30 +#include <common.h>
  31 +#include <malloc.h>
  32 +#include <spi.h>
  33 +#include <asm/immap.h>
  34 +#include <asm/io.h>
  35 +
  36 +DECLARE_GLOBAL_DATA_PTR;
  37 +
  38 +#define clamp(x, low, high) (min(max(low, x), high))
  39 +#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, s)
  40 +
  41 +struct cf_qspi_slave {
  42 + struct spi_slave slave; /* Specific bus:cs ID for each device */
  43 + qspi_t *regs; /* Pointer to SPI controller registers */
  44 + u16 qmr; /* QMR: Queued Mode Register */
  45 + u16 qwr; /* QWR: Queued Wrap Register */
  46 + u16 qcr; /* QCR: Queued Command Ram */
  47 +};
  48 +
  49 +/* Register write wrapper functions */
  50 +static void write_qmr(volatile qspi_t *qspi, u16 val) { qspi->mr = val; }
  51 +static void write_qdlyr(volatile qspi_t *qspi, u16 val) { qspi->dlyr = val; }
  52 +static void write_qwr(volatile qspi_t *qspi, u16 val) { qspi->wr = val; }
  53 +static void write_qir(volatile qspi_t *qspi, u16 val) { qspi->ir = val; }
  54 +static void write_qar(volatile qspi_t *qspi, u16 val) { qspi->ar = val; }
  55 +static void write_qdr(volatile qspi_t *qspi, u16 val) { qspi->dr = val; }
  56 +/* Register read wrapper functions */
  57 +static u16 read_qdlyr(volatile qspi_t *qspi) { return qspi->dlyr; }
  58 +static u16 read_qwr(volatile qspi_t *qspi) { return qspi->wr; }
  59 +static u16 read_qir(volatile qspi_t *qspi) { return qspi->ir; }
  60 +static u16 read_qdr(volatile qspi_t *qspi) { return qspi->dr; }
  61 +
  62 +/* These call points may be different for each ColdFire CPU */
  63 +extern void cfspi_port_conf(void);
  64 +static void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high);
  65 +static void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high);
  66 +
  67 +int spi_claim_bus(struct spi_slave *slave)
  68 +{
  69 + return 0;
  70 +}
  71 +void spi_release_bus(struct spi_slave *slave)
  72 +{
  73 +}
  74 +
  75 +__attribute__((weak))
  76 +void spi_init(void)
  77 +{
  78 + cfspi_port_conf();
  79 +}
  80 +
  81 +__attribute__((weak))
  82 +void spi_cs_activate(struct spi_slave *slave)
  83 +{
  84 + struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
  85 +
  86 + cfspi_cs_activate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV));
  87 +}
  88 +
  89 +__attribute__((weak))
  90 +void spi_cs_deactivate(struct spi_slave *slave)
  91 +{
  92 + struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
  93 +
  94 + cfspi_cs_deactivate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV));
  95 +}
  96 +
  97 +__attribute__((weak))
  98 +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
  99 +{
  100 + /* Only 1 bus and 4 chipselect per controller */
  101 + if (bus == 0 && (cs >= 0 && cs < 4))
  102 + return 1;
  103 + else
  104 + return 0;
  105 +}
  106 +
  107 +void spi_free_slave(struct spi_slave *slave)
  108 +{
  109 + struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
  110 +
  111 + free(dev);
  112 +}
  113 +
  114 +/* Translate information given by spi_setup_slave to members of cf_qspi_slave */
  115 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  116 + unsigned int max_hz, unsigned int mode)
  117 +{
  118 + struct cf_qspi_slave *dev = NULL;
  119 +
  120 + if (!spi_cs_is_valid(bus, cs))
  121 + return NULL;
  122 +
  123 + dev = malloc(sizeof(struct cf_qspi_slave));
  124 + if (!dev)
  125 + return NULL;
  126 +
  127 + /* Initialize to known value */
  128 + dev->slave.bus = bus;
  129 + dev->slave.cs = cs;
  130 + dev->regs = (qspi_t *)MMAP_QSPI;
  131 + dev->qmr = 0;
  132 + dev->qwr = 0;
  133 + dev->qcr = 0;
  134 +
  135 +
  136 + /* Map max_hz to QMR[BAUD] */
  137 + if (max_hz == 0) /* Go as fast as possible */
  138 + dev->qmr = 2u;
  139 + else /* Get the closest baud rate */
  140 + dev->qmr = clamp(((gd->bus_clk >> 2) + max_hz - 1)/max_hz,
  141 + 2u, 255u);
  142 +
  143 + /* Map mode to QMR[CPOL] and QMR[CPHA] */
  144 + if (mode & SPI_CPOL)
  145 + dev->qmr |= QSPI_QMR_CPOL;
  146 +
  147 + if (mode & SPI_CPHA)
  148 + dev->qmr |= QSPI_QMR_CPHA;
  149 +
  150 + /* Hardcode bit length to 8 bit per transter */
  151 + dev->qmr |= QSPI_QMR_BITS_8;
  152 +
  153 + /* Set QMR[MSTR] to enable QSPI as master */
  154 + dev->qmr |= QSPI_QMR_MSTR;
  155 +
  156 + /*
  157 + * Set QCR and QWR to default values for spi flash operation.
  158 + * If more custom QCR and QRW are needed, overload mode variable
  159 + */
  160 + dev->qcr = (QSPI_QDR_CONT | QSPI_QDR_BITSE);
  161 +
  162 + if (!(mode & SPI_CS_HIGH))
  163 + dev->qwr |= QSPI_QWR_CSIV;
  164 +
  165 + return &dev->slave;
  166 +}
  167 +
  168 +/* Transfer 8 bit at a time */
  169 +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
  170 + void *din, unsigned long flags)
  171 +{
  172 + struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
  173 + volatile qspi_t *qspi = dev->regs;
  174 + u8 *txbuf = (u8 *)dout;
  175 + u8 *rxbuf = (u8 *)din;
  176 + u32 count = ((bitlen / 8) + (bitlen % 8 ? 1 : 0));
  177 + u32 n, i = 0;
  178 +
  179 + /* Sanitize arguments */
  180 + if (slave == NULL) {
  181 + printf("%s: NULL slave ptr\n", __func__);
  182 + return -1;
  183 + }
  184 +
  185 + if (flags & SPI_XFER_BEGIN)
  186 + spi_cs_activate(slave);
  187 +
  188 + /* There is something to send, lets process it. spi_xfer is also called
  189 + * just to toggle chip select, so bitlen of 0 is valid */
  190 + if (count > 0) {
  191 + /*
  192 + * NOTE: Since chip select is driven as a bit-bang-ed GPIO
  193 + * using spi_cs_activate() and spi_cs_deactivate(),
  194 + * the chip select settings inside the controller
  195 + * (i.e. QCR[CONT] and QWR[CSIV]) are moot. The bits are set to
  196 + * keep the controller settings consistent with the actual
  197 + * operation of the bus.
  198 + */
  199 +
  200 + /* Write the slave device's settings for the controller.*/
  201 + write_qmr(qspi, dev->qmr);
  202 + write_qwr(qspi, dev->qwr);
  203 +
  204 + /* Limit transfer to 16 at a time */
  205 + n = min(count, 16u);
  206 + do {
  207 + /* Setup queue end point */
  208 + write_qwr(qspi, ((read_qwr(qspi) & QSPI_QWR_ENDQP_MASK)
  209 + | QSPI_QWR_ENDQP((n-1))));
  210 +
  211 + /* Write Command RAM */
  212 + write_qar(qspi, QSPI_QAR_CMD);
  213 + for (i = 0; i < n; ++i)
  214 + write_qdr(qspi, dev->qcr);
  215 +
  216 + /* Write TxBuf, if none given, fill with ZEROes */
  217 + write_qar(qspi, QSPI_QAR_TRANS);
  218 + if (txbuf) {
  219 + for (i = 0; i < n; ++i)
  220 + write_qdr(qspi, *txbuf++);
  221 + } else {
  222 + for (i = 0; i < n; ++i)
  223 + write_qdr(qspi, 0);
  224 + }
  225 +
  226 + /* Clear QIR[SPIF] by writing a 1 to it */
  227 + write_qir(qspi, read_qir(qspi) | QSPI_QIR_SPIF);
  228 + /* Set QDLYR[SPE] to start sending */
  229 + write_qdlyr(qspi, read_qdlyr(qspi) | QSPI_QDLYR_SPE);
  230 +
  231 + /* Poll QIR[SPIF] for transfer completion */
  232 + while ((read_qir(qspi) & QSPI_QIR_SPIF) != 1)
  233 + udelay(1);
  234 +
  235 + /* If given read RxBuf, load data to it */
  236 + if (rxbuf) {
  237 + write_qar(qspi, QSPI_QAR_RECV);
  238 + for (i = 0; i < n; ++i)
  239 + *rxbuf++ = read_qdr(qspi);
  240 + }
  241 +
  242 + /* Decrement count */
  243 + count -= n;
  244 + } while (count);
  245 + }
  246 +
  247 + if (flags & SPI_XFER_END)
  248 + spi_cs_deactivate(slave);
  249 +
  250 + return 0;
  251 +}
  252 +
  253 +/* Each MCF CPU may have different pin assignments for chip selects. */
  254 +#if defined(CONFIG_M5271)
  255 +/* Assert chip select, val = [1|0] , dir = out, mode = GPIO */
  256 +void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high)
  257 +{
  258 + debug("%s: bus %d cs %d cs_active_high %d\n",
  259 + __func__, bus, cs, cs_active_high);
  260 +
  261 + switch (cs) {
  262 + case 0: /* QSPI_CS[0] = PQSPI[3] */
  263 + if (cs_active_high)
  264 + mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08);
  265 + else
  266 + mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7);
  267 +
  268 + mbar_writeByte(MCF_GPIO_PDDR_QSPI,
  269 + mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x08);
  270 +
  271 + mbar_writeByte(MCF_GPIO_PAR_QSPI,
  272 + mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF);
  273 + break;
  274 + case 1: /* QSPI_CS[1] = PQSPI[4] */
  275 + if (cs_active_high)
  276 + mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10);
  277 + else
  278 + mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF);
  279 +
  280 + mbar_writeByte(MCF_GPIO_PDDR_QSPI,
  281 + mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x10);
  282 +
  283 + mbar_writeByte(MCF_GPIO_PAR_QSPI,
  284 + mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F);
  285 + break;
  286 + case 2: /* QSPI_CS[2] = PTIMER[7] */
  287 + if (cs_active_high)
  288 + mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80);
  289 + else
  290 + mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F);
  291 +
  292 + mbar_writeByte(MCF_GPIO_PDDR_TIMER,
  293 + mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x80);
  294 +
  295 + mbar_writeShort(MCF_GPIO_PAR_TIMER,
  296 + mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF);
  297 + break;
  298 + case 3: /* QSPI_CS[3] = PTIMER[3] */
  299 + if (cs_active_high)
  300 + mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08);
  301 + else
  302 + mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7);
  303 +
  304 + mbar_writeByte(MCF_GPIO_PDDR_TIMER,
  305 + mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x08);
  306 +
  307 + mbar_writeShort(MCF_GPIO_PAR_TIMER,
  308 + mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F);
  309 + break;
  310 + }
  311 +}
  312 +
  313 +/* Deassert chip select, val = [1|0], dir = in, mode = GPIO
  314 + * direction set as IN to undrive the pin, external pullup/pulldown will bring
  315 + * bus to deassert state.
  316 + */
  317 +void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high)
  318 +{
  319 + debug("%s: bus %d cs %d cs_active_high %d\n",
  320 + __func__, bus, cs, cs_active_high);
  321 +
  322 + switch (cs) {
  323 + case 0: /* QSPI_CS[0] = PQSPI[3] */
  324 + if (cs_active_high)
  325 + mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7);
  326 + else
  327 + mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08);
  328 +
  329 + mbar_writeByte(MCF_GPIO_PDDR_QSPI,
  330 + mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xF7);
  331 +
  332 + mbar_writeByte(MCF_GPIO_PAR_QSPI,
  333 + mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF);
  334 + break;
  335 + case 1: /* QSPI_CS[1] = PQSPI[4] */
  336 + if (cs_active_high)
  337 + mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF);
  338 + else
  339 + mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10);
  340 +
  341 + mbar_writeByte(MCF_GPIO_PDDR_QSPI,
  342 + mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xEF);
  343 +
  344 + mbar_writeByte(MCF_GPIO_PAR_QSPI,
  345 + mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F);
  346 + break;
  347 + case 2: /* QSPI_CS[2] = PTIMER[7] */
  348 + if (cs_active_high)
  349 + mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F);
  350 + else
  351 + mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80);
  352 +
  353 + mbar_writeByte(MCF_GPIO_PDDR_TIMER,
  354 + mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0x7F);
  355 +
  356 + mbar_writeShort(MCF_GPIO_PAR_TIMER,
  357 + mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF);
  358 + break;
  359 + case 3: /* QSPI_CS[3] = PTIMER[3] */
  360 + if (cs_active_high)
  361 + mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7);
  362 + else
  363 + mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08);
  364 +
  365 + mbar_writeByte(MCF_GPIO_PDDR_TIMER,
  366 + mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0xF7);
  367 +
  368 + mbar_writeShort(MCF_GPIO_PAR_TIMER,
  369 + mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F);
  370 + break;
  371 + }
  372 +}
  373 +#endif /* CONFIG_M5271 */