Commit 98af34f897a6ef5de253806049d033471b02479f
1 parent
4374139627
Exists in
v2017.01-smarct4x
and in
30 other branches
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_ */ |