mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 03:50:24 +09:00
exynos: serial clear and set big endian fix
Samsung serial driver uses __set_bit and __clear_bit functions directly with h/w registers. But these functions are not endian neutral. In case of BE host before operation on the bit byte swap is needed and byte swap is required after operation on the bit is complete. Patch creates and use __hw_set_bit and __hw_clear_bit, that in case of LE just call __set_bit and __clear_bit, but in case of BE they do required byteswaps Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org>
This commit is contained in:
committed by
Andrey Konovalov
parent
725fe31c2b
commit
66d1c41f51
@@ -59,6 +59,41 @@
|
||||
#define S3C24XX_SERIAL_MAJOR 204
|
||||
#define S3C24XX_SERIAL_MINOR 64
|
||||
|
||||
#ifndef CONFIG_CPU_BIG_ENDIAN /* little endian */
|
||||
static inline void __hw_set_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
__set_bit(nr, addr);
|
||||
}
|
||||
|
||||
static inline void __hw_clear_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
__clear_bit(nr, addr);
|
||||
}
|
||||
#else
|
||||
static inline void __hw_set_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
unsigned long val = le32_to_cpu(*p);
|
||||
|
||||
val |= mask;
|
||||
|
||||
*p = cpu_to_le32(val);
|
||||
}
|
||||
|
||||
static inline void __hw_clear_bit(int nr, volatile unsigned long *addr)
|
||||
{
|
||||
unsigned long mask = BIT_MASK(nr);
|
||||
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
|
||||
|
||||
unsigned long val = le32_to_cpu(*p);
|
||||
|
||||
val &= ~mask;
|
||||
|
||||
*p = cpu_to_le32(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* macros to change one thing to another */
|
||||
|
||||
#define tx_enabled(port) ((port)->unused[0])
|
||||
@@ -138,7 +173,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
|
||||
|
||||
if (tx_enabled(port)) {
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__set_bit(S3C64XX_UINTM_TXD,
|
||||
__hw_set_bit(S3C64XX_UINTM_TXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
else
|
||||
disable_irq_nosync(ourport->tx_irq);
|
||||
@@ -157,7 +192,7 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
|
||||
s3c24xx_serial_rx_disable(port);
|
||||
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__clear_bit(S3C64XX_UINTM_TXD,
|
||||
__hw_clear_bit(S3C64XX_UINTM_TXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
else
|
||||
enable_irq(ourport->tx_irq);
|
||||
@@ -172,7 +207,7 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
||||
if (rx_enabled(port)) {
|
||||
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
|
||||
if (s3c24xx_serial_has_interrupt_mask(port))
|
||||
__set_bit(S3C64XX_UINTM_RXD,
|
||||
__hw_set_bit(S3C64XX_UINTM_RXD,
|
||||
portaddrl(port, S3C64XX_UINTM));
|
||||
else
|
||||
disable_irq_nosync(ourport->rx_irq);
|
||||
@@ -533,7 +568,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
||||
ourport->tx_claimed = 1;
|
||||
|
||||
/* Enable Rx Interrupt */
|
||||
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
|
||||
__hw_clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
|
||||
dbg("s3c64xx_serial_startup ok\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user