mirror of
https://github.com/apache/nuttx.git
synced 2026-05-24 16:11:56 +08:00
Add eZ80 SPI driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1668 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -682,3 +682,7 @@
|
||||
network setup to perform that testing now (I'm in a hotel).
|
||||
|
||||
0.4.5 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
|
||||
* Add an enumeration argument to the SPI chip select and status methods so
|
||||
that the interface can handle more than one device.
|
||||
* eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards.
|
||||
|
||||
@@ -1356,6 +1356,10 @@ buildroot-0.1.3 2009-02-28 <spudmonkey@racsa.co.cr>
|
||||
<pre><ul>
|
||||
nuttx-0.4.5 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
|
||||
* Add an enumeration argument to the SPI chip select and status methods so
|
||||
that the interface can handle more than one device.
|
||||
* eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards.
|
||||
|
||||
pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
|
||||
buildroot-0.1.4 2009-xx-xx <spudmonkey@racsa.co.cr>
|
||||
|
||||
@@ -688,6 +688,12 @@ o z80/z8/ez80 (arch/z80)
|
||||
Status: Open
|
||||
Priority: High if you happen to be working with XTRS.
|
||||
|
||||
Description: A "generic" SPI driver has been coded for the eZ80Acclaim!
|
||||
However, this remains untested since I have no SPI devices for
|
||||
the board (yet).
|
||||
Status: Open
|
||||
Priority: Med
|
||||
|
||||
o z16 (arch/z16)
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ endif
|
||||
CHIP_SSRCS =
|
||||
CHIP_CSRCS = ez80_clock.c ez80_initialstate.c ez80_irq.c ez80_copystate.c \
|
||||
ez80_schedulesigaction.c ez80_sigdeliver.c ez80_timerisr.c \
|
||||
ez80_lowuart.c ez80_serial.c ez80_registerdump.c
|
||||
ez80_lowuart.c ez80_serial.c ez80_spi.c ez80_registerdump.c
|
||||
ifeq ($(CONFIG_ARCH_CHIP_EZ80F91),y)
|
||||
ifeq ($(CONFIG_EZ80_EMAC),y)
|
||||
CHIP_CSRCS += ez80_emac.c
|
||||
|
||||
Executable
+376
@@ -0,0 +1,376 @@
|
||||
/****************************************************************************
|
||||
* arch/z80/src/ez80/ez80_spi.c
|
||||
*
|
||||
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/spi.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spi.h>
|
||||
#include <arch/io.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "up_arch.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include "ez80f91_spi.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_CHIP_EZ80F91
|
||||
# define GPIOB_SPI_PINSET 0x38 /* MISO+MSOI+SCK. Excludes SS */
|
||||
#else
|
||||
# error "Check GPIO initialization for this chip"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
|
||||
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch);
|
||||
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen);
|
||||
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct spi_ops_s g_spiops =
|
||||
{
|
||||
ez80_spiselect, /* Provided externally by board logic */
|
||||
spi_setfrequency,
|
||||
ez80_spistatus, /* Provided externally by board logic */
|
||||
spi_sndbyte,
|
||||
spi_sndblock,
|
||||
spi_recvblock,
|
||||
};
|
||||
|
||||
/* This supports is only a single SPI bus/port. There you port this to an
|
||||
* architecture with multiple SPI busses/ports, then the following must
|
||||
* become an array with one 'struct spi_dev_s' instance per bus.
|
||||
*/
|
||||
|
||||
static struct spi_dev_s g_spidev = { &g_spiops };
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_setfrequency
|
||||
*
|
||||
* Description:
|
||||
* Set the SPI frequency.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* frequency - The SPI frequency requested
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns the actual frequency selected
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
|
||||
{
|
||||
/* We want select divisor to provide the highest frequency (SPIR) that does NOT
|
||||
* exceed the requested frequency.:
|
||||
*
|
||||
* SPIR <= System Clock Frequency / (2 * BRG)
|
||||
*
|
||||
* So
|
||||
*
|
||||
* BRG >= System Clock Frequency / (2 * SPIR)
|
||||
*/
|
||||
|
||||
uint32 brg = ((EZ80_SYS_CLK_FREQ+1)/2 + frequency - 1) / frequency;
|
||||
|
||||
/* "When configured as a Master, the 16-bit divisor value must be between
|
||||
* 0003h and FFFFh, inclusive. When configured as a Slave, the 16-bit
|
||||
* divisor value must be between 0004h and FFFFh, inclusive."
|
||||
*/
|
||||
|
||||
if (brg < 3)
|
||||
{
|
||||
brg = 3;
|
||||
}
|
||||
else if (brg > 0xffff)
|
||||
{
|
||||
brg = 0xfff;
|
||||
}
|
||||
|
||||
outp(EZ80_SPI_BRG_L, brg & 0xff);
|
||||
outp(EZ80_SPI_BRG_L, (brg >> 8) & 0xff);
|
||||
|
||||
return ((EZ80_SYS_CLK_FREQ+1)/2 + brg - 1) / brg;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_waitspif
|
||||
*
|
||||
* Description:
|
||||
* Wait for the SPIF bit to be set in the status register signifying the
|
||||
* the data transfer was finished.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Status register mode bits
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ubyte spi_waitspif(void)
|
||||
{
|
||||
ubyte status;
|
||||
|
||||
/* Wait for the device to be ready to accept another byte (or for an error
|
||||
* to be reported
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
status = inp(EZ80_SPI_SR) & (SPI_SR_SPIF|SPI_SR_WCOL|SPI_SR_MODF);
|
||||
}
|
||||
while (status == 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_transfer
|
||||
*
|
||||
* Description:
|
||||
* Send one byte on SPI, return th response
|
||||
*
|
||||
* Input Parameters:
|
||||
* ch - the byte to send
|
||||
*
|
||||
* Returned Value:
|
||||
* response
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ubyte spi_transfer(ubyte ch)
|
||||
{
|
||||
ubyte status;
|
||||
|
||||
/* Send the byte, repeating if some error occurs */
|
||||
|
||||
for(;;)
|
||||
{
|
||||
outp(EZ80_SPI_TSR, ch);
|
||||
|
||||
/* Wait for the device to be ready to accept another byte */
|
||||
|
||||
status = spi_waitspif();
|
||||
if ((status & SPI_SR_SPIF) != 0)
|
||||
{
|
||||
return inp(EZ80_SPI_RBR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_sndbyte
|
||||
*
|
||||
* Description:
|
||||
* Send one byte on SPI
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* ch - The byte to send
|
||||
*
|
||||
* Returned Value:
|
||||
* response
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch)
|
||||
{
|
||||
return spi_transfer(ch);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Name: spi_sndblock
|
||||
*
|
||||
* Description:
|
||||
* Send a block of data on SPI
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* buffer - A pointer to the buffer of data to be sent
|
||||
* buflen - the length of data to send from the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen)
|
||||
{
|
||||
ubyte response;
|
||||
|
||||
/* Loop while thre are bytes remaining to be sent */
|
||||
|
||||
while (buflen-- > 0)
|
||||
{
|
||||
response = spi_transfer(*buffer++);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_recvblock
|
||||
*
|
||||
* Description:
|
||||
* Revice a block of data from SPI
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* buffer - A pointer to the buffer in which to recieve data
|
||||
* buflen - the length of data that can be received in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen)
|
||||
{
|
||||
ubyte response;
|
||||
|
||||
/* Loop while thre are bytes remaining to be sent */
|
||||
|
||||
while (buflen-- > 0)
|
||||
{
|
||||
*buffer = spi_transfer(0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_spiinitialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize common parts the selected SPI port. Initialization of
|
||||
* chip select GPIOs must have been performed by board specific logic
|
||||
* prior to calling this function. Specifically: GPIOs should have
|
||||
* been configured for output, and all chip selects disabled.
|
||||
*
|
||||
* One GPIO, SS (PB2 on the eZ8F091) is reserved as a chip select. However,
|
||||
* If multiple devices on on the bus, then multiple chip selects will be
|
||||
* required. Theregore, all GPIO chip management is deferred to board-
|
||||
* specific logic.
|
||||
*
|
||||
* Input Parameter:
|
||||
* Port number (for hardware that has mutiple SPI interfaces)
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid SPI device structre reference on succcess; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct spi_dev_s *up_spiinitialize(int port)
|
||||
{
|
||||
ubyte regval;
|
||||
|
||||
/* Only the SPI1 interface is supported */
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
if (port != 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable SPI */
|
||||
|
||||
outp(EZ80_SPI_CTL, 0);
|
||||
|
||||
/* Configure GPIOs. For the eZ80F91, the pin mapping for the four SPI pins
|
||||
* is:
|
||||
*
|
||||
* GPIO ALT MASTER SLAVE COMMENT
|
||||
* ---- ----- ------- ------- ---------------------------------
|
||||
* PB2 SS INPUT INPUT Managed by board specific logic
|
||||
* PB3 SCLK OUTPUT INPUT
|
||||
* PB4 MISO INPUT OUTPUT
|
||||
* PB5 MOSI OUTPUT INPUT
|
||||
*
|
||||
* Select the alternate function for PB2-5:
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARCH_CHIP_EZ80F91
|
||||
regval = inp(EZ80_PB_DDR);
|
||||
regval |= GPIOB_SPI_PINSET;
|
||||
outp(EZ80_PB_DDR, regval);
|
||||
|
||||
regval = inp(EZ80_PB_ALT1);
|
||||
regval &= ~GPIOB_SPI_PINSET;
|
||||
outp(EZ80_PB_ALT1, regval);
|
||||
|
||||
regval = inp(EZ80_PB_ALT2);
|
||||
regval |= GPIOB_SPI_PINSET;
|
||||
outp(EZ80_PB_ALT2, regval);
|
||||
#else
|
||||
# error "Check GPIO initialization for this chip"
|
||||
#endif
|
||||
|
||||
/* Set the initial clock frequency for indentification mode < 400kHz */
|
||||
|
||||
spi_setfrequency(NULL, 400000);
|
||||
|
||||
/* Enable the SPI.
|
||||
* NOTE 1: Interrupts are not used in this driver version.
|
||||
* NOTE 2: Certain devices may need changes to SCK polarity settings.
|
||||
*/
|
||||
|
||||
outp(EZ80_SPI_CTL, SPI_CTL_SPIEN|SPI_CTL_MASTEREN);
|
||||
|
||||
return &g_spidev;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/************************************************************************************
|
||||
* arch/z80/src/ez80/ez80f91_spi.h
|
||||
* arch/z80/src/chip/ez80f91_spi.h
|
||||
*
|
||||
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H
|
||||
#define __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H
|
||||
|
||||
/************************************************************************************
|
||||
* Included Files
|
||||
************************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <nuttx/spi.h>
|
||||
|
||||
/************************************************************************************
|
||||
* Definitions
|
||||
************************************************************************************/
|
||||
|
||||
/* SPIC Registers *****************************************************************/
|
||||
|
||||
/* Provided in ez80f91.h */
|
||||
|
||||
/* SPIC Register Bit Definitions **************************************************/
|
||||
|
||||
/* Baud Rate Generator (BRG) H/L Register Definitions
|
||||
*
|
||||
* No bit definitions -- These two 8-bit registers set the 16-bit BRG divider value
|
||||
*/
|
||||
|
||||
/*SPI Control (CTL} Register Definitions */
|
||||
|
||||
#define SPI_CTL_IRQEN (1 << 7) /* Bit 7: 1=SPI system interrupt is enabled */
|
||||
#define SPI_CTL_SPIEN (1 << 5) /* Bit 5: 1=SPI is enabled */
|
||||
#define SPI_CTL_MASTEREN (1 << 4) /* Bit 4: 1=SPI operates as a master */
|
||||
#define SPI_CTL_CPOL (1 << 3) /* Bit 3: 1=Master SCK pin idles in a high (1) state */
|
||||
#define SPI_CTL_CPHA (1 << 2) /* Bit 2: 1=SS remains Low to transfer any number of data bytes */
|
||||
|
||||
/* SR Register Definitions */
|
||||
|
||||
#define SPI_SR_SPIF (1 << 7) /* Bit x: 1=SPI data transfer is finished */
|
||||
#define SPI_SR_WCOL (1 << 6) /* Bit x: 1=SPI write collision is detected*/
|
||||
#define SPI_SR_MODF (1 << 4) /* Bit x: 1=Mode fault (multimaster conflict) is detected */
|
||||
|
||||
/* RBR/TSR Register Definitions */
|
||||
|
||||
/* No definitions: 8-bit SPI receive/transmit data */
|
||||
|
||||
/************************************************************************************
|
||||
* Public Types
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Public Data
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C" {
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
|
||||
/* The external functions, ez80_spiselect and ez80_spistatus must be provided by
|
||||
* board-specific logic. The are implementations of the select and status methods
|
||||
* SPI interface defined by struct spi_ops_s (see include/nuttx/spi.h). All other
|
||||
* methods (including up_spiinitialize()) are provided by common logic. To use this
|
||||
* common SPI logic on your board:
|
||||
*
|
||||
* 1. Provide ez80_spiselect() and ez80_spistatus() functions in your board-specific
|
||||
* logic. This function will perform chip selection and status operations using
|
||||
* GPIOs in the way your board is configured.
|
||||
* 2. Add a call to up_spiinitialize() in your low level initialization logic
|
||||
* 3. The handle returned by up_spiinitialize() may then be used to bind the
|
||||
* SPI driver to higher level logic (e.g., calling mmcsd_spislotinitializ()
|
||||
* will bind the SPI driver to the SPI MMC/SD driver.
|
||||
*/
|
||||
|
||||
EXTERN void ez80_spiselect(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected);
|
||||
EXTERN ubyte ez80_spistatus(FAR struct spi_dev_s *dev, enum spidev_e devid);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H */
|
||||
Reference in New Issue
Block a user