Commit 98af34f897a6ef5de253806049d033471b02479f

Authored by Bin Meng
1 parent 4374139627

superio: Add SMSC SIO1007 driver

The SMSC SIO1007 superio chipset integrates two ns16550 compatible
serial ports for legacy applications, 16 GPIO pins and some other
functionalities like power management.

This adds a simple driver to enable serial port and handle GPIO.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>

Showing 3 changed files with 242 additions and 0 deletions Side-by-side Diff

drivers/misc/Makefile
... ... @@ -32,6 +32,7 @@
32 32 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
33 33 endif
34 34 obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
  35 +obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
35 36 obj-$(CONFIG_STATUS_LED) += status_led.o
36 37 obj-$(CONFIG_SANDBOX) += swap_case.o
37 38 obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
drivers/misc/smsc_sio1007.c
  1 +/*
  2 + * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <asm/io.h>
  9 +#include <errno.h>
  10 +#include <smsc_sio1007.h>
  11 +
  12 +static inline u8 sio1007_read(int port, int reg)
  13 +{
  14 + outb(reg, port);
  15 +
  16 + return inb(port + 1);
  17 +}
  18 +
  19 +static inline void sio1007_write(int port, int reg, int val)
  20 +{
  21 + outb(reg, port);
  22 + outb(val, port + 1);
  23 +}
  24 +
  25 +static inline void sio1007_clrsetbits(int port, int reg, u8 clr, u8 set)
  26 +{
  27 + sio1007_write(port, reg, (sio1007_read(port, reg) & ~clr) | set);
  28 +}
  29 +
  30 +void sio1007_enable_serial(int port, int num, int iobase, int irq)
  31 +{
  32 + if (num < 0 || num > SIO1007_UART_NUM)
  33 + return;
  34 +
  35 + /* enter configuration state */
  36 + outb(0x55, port);
  37 +
  38 + /* power on serial port and set up its i/o base & irq */
  39 + if (!num) {
  40 + sio1007_clrsetbits(port, DEV_POWER_CTRL, 0, UART1_POWER_ON);
  41 + sio1007_clrsetbits(port, UART1_IOBASE, 0xfe, iobase >> 2);
  42 + sio1007_clrsetbits(port, UART_IRQ, 0xf0, irq << 4);
  43 + } else {
  44 + sio1007_clrsetbits(port, DEV_POWER_CTRL, 0, UART2_POWER_ON);
  45 + sio1007_clrsetbits(port, UART2_IOBASE, 0xfe, iobase >> 2);
  46 + sio1007_clrsetbits(port, UART_IRQ, 0x0f, irq);
  47 + }
  48 +
  49 + /* exit configuration state */
  50 + outb(0xaa, port);
  51 +}
  52 +
  53 +void sio1007_enable_runtime(int port, int iobase)
  54 +{
  55 + /* enter configuration state */
  56 + outb(0x55, port);
  57 +
  58 + /* set i/o base for the runtime register block */
  59 + sio1007_clrsetbits(port, RTR_IOBASE_LOW, 0, iobase >> 4);
  60 + sio1007_clrsetbits(port, RTR_IOBASE_HIGH, 0, iobase >> 12);
  61 + /* turn on address decoding for this block */
  62 + sio1007_clrsetbits(port, DEV_ACTIVATE, 0, RTR_EN);
  63 +
  64 + /* exit configuration state */
  65 + outb(0xaa, port);
  66 +}
  67 +
  68 +void sio1007_gpio_config(int port, int gpio, int dir, int pol, int type)
  69 +{
  70 + int reg = GPIO0_DIR;
  71 +
  72 + if (gpio < 0 || gpio > SIO1007_GPIO_NUM)
  73 + return;
  74 + if (gpio >= GPIO_NUM_PER_GROUP) {
  75 + reg = GPIO1_DIR;
  76 + gpio -= GPIO_NUM_PER_GROUP;
  77 + }
  78 +
  79 + /* enter configuration state */
  80 + outb(0x55, port);
  81 +
  82 + /* set gpio pin direction, polority and type */
  83 + sio1007_clrsetbits(port, reg, 1 << gpio, dir << gpio);
  84 + sio1007_clrsetbits(port, reg + 1, 1 << gpio, pol << gpio);
  85 + sio1007_clrsetbits(port, reg + 2, 1 << gpio, type << gpio);
  86 +
  87 + /* exit configuration state */
  88 + outb(0xaa, port);
  89 +}
  90 +
  91 +int sio1007_gpio_get_value(int port, int gpio)
  92 +{
  93 + int reg = GPIO0_DATA;
  94 + int val;
  95 +
  96 + if (gpio < 0 || gpio > SIO1007_GPIO_NUM)
  97 + return -EINVAL;
  98 + if (gpio >= GPIO_NUM_PER_GROUP) {
  99 + reg = GPIO1_DATA;
  100 + gpio -= GPIO_NUM_PER_GROUP;
  101 + }
  102 +
  103 + val = inb(port + reg);
  104 + if (val & (1 << gpio))
  105 + return 1;
  106 + else
  107 + return 0;
  108 +}
  109 +
  110 +void sio1007_gpio_set_value(int port, int gpio, int val)
  111 +{
  112 + int reg = GPIO0_DATA;
  113 + u8 data;
  114 +
  115 + if (gpio < 0 || gpio > SIO1007_GPIO_NUM)
  116 + return;
  117 + if (gpio >= GPIO_NUM_PER_GROUP) {
  118 + reg = GPIO1_DATA;
  119 + gpio -= GPIO_NUM_PER_GROUP;
  120 + }
  121 +
  122 + data = inb(port + reg);
  123 + data &= ~(1 << gpio);
  124 + data |= (val << gpio);
  125 + outb(data, port + reg);
  126 +}
include/smsc_sio1007.h
  1 +/*
  2 + * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#ifndef _SMSC_SIO1007_H_
  8 +#define _SMSC_SIO1007_H_
  9 +
  10 +/*
  11 + * The I/O base address of SIO1007 at power-up is determined by the SYSOPT0
  12 + * and SYSOPT1 pins at the deasserting edge of PCIRST#. The combination of
  13 + * SYSOPT0 and SYSOPT1 determines one of the following addresses.
  14 + */
  15 +#define SIO1007_IOPORT0 0x002e
  16 +#define SIO1007_IOPORT1 0x004e
  17 +#define SIO1007_IOPORT2 0x162e
  18 +#define SIO1007_IOPORT3 0x164e
  19 +
  20 +/* SIO1007 registers */
  21 +
  22 +#define DEV_POWER_CTRL 0x02
  23 +#define UART1_POWER_ON (1 << 3)
  24 +#define UART2_POWER_ON (1 << 7)
  25 +
  26 +#define UART1_IOBASE 0x24
  27 +#define UART2_IOBASE 0x25
  28 +#define UART_IRQ 0x28
  29 +
  30 +#define RTR_IOBASE_HIGH 0x21
  31 +#define RTR_IOBASE_LOW 0x30
  32 +
  33 +#define GPIO0_DIR 0x31
  34 +#define GPIO1_DIR 0x35
  35 +#define GPIO_DIR_INPUT 0
  36 +#define GPIO_DIR_OUTPUT 1
  37 +
  38 +#define GPIO0_POL 0x32
  39 +#define GPIO1_POL 0x36
  40 +#define GPIO_POL_NO_INVERT 0
  41 +#define GPIO_POL_INVERT 1
  42 +
  43 +#define GPIO0_TYPE 0x33
  44 +#define GPIO1_TYPE 0x37
  45 +#define GPIO_TYPE_PUSH_PULL 0
  46 +#define GPIO_TYPE_OPEN_DRAIN 1
  47 +
  48 +#define DEV_ACTIVATE 0x3a
  49 +#define RTR_EN (1 << 1)
  50 +
  51 +/* Runtime register offset */
  52 +
  53 +#define GPIO0_DATA 0xc
  54 +#define GPIO1_DATA 0xe
  55 +
  56 +/* Number of serial ports supported */
  57 +#define SIO1007_UART_NUM 2
  58 +
  59 +/* Number of gpio pins supported */
  60 +#define GPIO_NUM_PER_GROUP 8
  61 +#define GPIO_GROUP_NUM 2
  62 +#define SIO1007_GPIO_NUM (GPIO_NUM_PER_GROUP * GPIO_GROUP_NUM)
  63 +
  64 +/**
  65 + * Configure the I/O port address of the specified serial device and
  66 + * enable the serial device.
  67 + *
  68 + * @port: SIO1007 I/O port address
  69 + * @num: serial device number (0 or 1)
  70 + * @iobase: processor I/O port address to assign to this serial device
  71 + * @irq: processor IRQ number to assign to this serial device
  72 + */
  73 +void sio1007_enable_serial(int port, int num, int iobase, int irq);
  74 +
  75 +/**
  76 + * Configure the I/O port address of the runtime register block and
  77 + * enable the address decoding.
  78 + *
  79 + * @port: SIO1007 I/O port address
  80 + * @iobase: processor I/O port address to assign to the runtime registers
  81 + */
  82 +void sio1007_enable_runtime(int port, int iobase);
  83 +
  84 +/**
  85 + * Configure the direction/polority/type of a specified GPIO pin
  86 + *
  87 + * @port: SIO1007 I/O port address
  88 + * @gpio: GPIO number (0-7 for GP10-GP17, 8-15 for GP30-GP37)
  89 + * @dir: GPIO_DIR_INPUT or GPIO_DIR_OUTPUT
  90 + * @pol: GPIO_POL_NO_INVERT or GPIO_POL_INVERT
  91 + * @type: GPIO_TYPE_PUSH_PULL or GPIO_TYPE_OPEN_DRAIN
  92 + */
  93 +void sio1007_gpio_config(int port, int gpio, int dir, int pol, int type);
  94 +
  95 +/**
  96 + * Get a GPIO pin value.
  97 + * This will work whether the GPIO is an input or an output.
  98 + *
  99 + * @port: runtime register block I/O port address
  100 + * @gpio: GPIO number (0-7 for GP10-GP17, 8-15 for GP30-GP37)
  101 + * @return: 0 if low, 1 if high, -EINVAL if gpio number is invalid
  102 + */
  103 +int sio1007_gpio_get_value(int port, int gpio);
  104 +
  105 +/**
  106 + * Set a GPIO pin value.
  107 + * This will only work when the GPIO is configured as an output.
  108 + *
  109 + * @port: runtime register block I/O port address
  110 + * @gpio: GPIO number (0-7 for GP10-GP17, 8-15 for GP30-GP37)
  111 + * @val: 0 if low, 1 if high
  112 + */
  113 +void sio1007_gpio_set_value(int port, int gpio, int val);
  114 +
  115 +#endif /* _SMSC_SIO1007_H_ */