162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * GPIO interface for Winbond Super I/O chips 462306a36Sopenharmony_ci * Currently, only W83627UHG (Nuvoton NCT6627UD) is supported. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Maciej S. Szmigiero <mail@maciej.szmigiero.name> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1262306a36Sopenharmony_ci#include <linux/ioport.h> 1362306a36Sopenharmony_ci#include <linux/isa.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define WB_GPIO_DRIVER_NAME KBUILD_MODNAME 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define WB_SIO_BASE 0x2e 1962306a36Sopenharmony_ci#define WB_SIO_BASE_HIGH 0x4e 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define WB_SIO_EXT_ENTER_KEY 0x87 2262306a36Sopenharmony_ci#define WB_SIO_EXT_EXIT_KEY 0xaa 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* global chip registers */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define WB_SIO_REG_LOGICAL 0x07 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define WB_SIO_REG_CHIP_MSB 0x20 2962306a36Sopenharmony_ci#define WB_SIO_REG_CHIP_LSB 0x21 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define WB_SIO_CHIP_ID_W83627UHG 0xa230 3262306a36Sopenharmony_ci#define WB_SIO_CHIP_ID_W83627UHG_MASK GENMASK(15, 4) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define WB_SIO_REG_DPD 0x22 3562306a36Sopenharmony_ci#define WB_SIO_REG_DPD_UARTA 4 3662306a36Sopenharmony_ci#define WB_SIO_REG_DPD_UARTB 5 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define WB_SIO_REG_IDPD 0x23 3962306a36Sopenharmony_ci#define WB_SIO_REG_IDPD_UARTC 4 4062306a36Sopenharmony_ci#define WB_SIO_REG_IDPD_UARTD 5 4162306a36Sopenharmony_ci#define WB_SIO_REG_IDPD_UARTE 6 4262306a36Sopenharmony_ci#define WB_SIO_REG_IDPD_UARTF 7 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define WB_SIO_REG_GLOBAL_OPT 0x24 4562306a36Sopenharmony_ci#define WB_SIO_REG_GO_ENFDC 1 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define WB_SIO_REG_OVTGPIO3456 0x29 4862306a36Sopenharmony_ci#define WB_SIO_REG_OG3456_G3PP 3 4962306a36Sopenharmony_ci#define WB_SIO_REG_OG3456_G4PP 4 5062306a36Sopenharmony_ci#define WB_SIO_REG_OG3456_G5PP 5 5162306a36Sopenharmony_ci#define WB_SIO_REG_OG3456_G6PP 7 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define WB_SIO_REG_I2C_PS 0x2a 5462306a36Sopenharmony_ci#define WB_SIO_REG_I2CPS_I2CFS 1 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define WB_SIO_REG_GPIO1_MF 0x2c 5762306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_G1PP 6 5862306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_G2PP 7 5962306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_FS_MASK GENMASK(1, 0) 6062306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_FS_IR_OFF 0 6162306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_FS_IR 1 6262306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_FS_GPIO1 2 6362306a36Sopenharmony_ci#define WB_SIO_REG_G1MF_FS_UARTB 3 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* not an actual device number, just a value meaning 'no device' */ 6662306a36Sopenharmony_ci#define WB_SIO_DEV_NONE 0xff 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* registers with offsets >= 0x30 are specific for a particular device */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* UART B logical device */ 7162306a36Sopenharmony_ci#define WB_SIO_DEV_UARTB 0x03 7262306a36Sopenharmony_ci#define WB_SIO_UARTB_REG_ENABLE 0x30 7362306a36Sopenharmony_ci#define WB_SIO_UARTB_ENABLE_ON 0 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* UART C logical device */ 7662306a36Sopenharmony_ci#define WB_SIO_DEV_UARTC 0x06 7762306a36Sopenharmony_ci#define WB_SIO_UARTC_REG_ENABLE 0x30 7862306a36Sopenharmony_ci#define WB_SIO_UARTC_ENABLE_ON 0 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* GPIO3, GPIO4 logical device */ 8162306a36Sopenharmony_ci#define WB_SIO_DEV_GPIO34 0x07 8262306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_ENABLE 0x30 8362306a36Sopenharmony_ci#define WB_SIO_GPIO34_ENABLE_3 0 8462306a36Sopenharmony_ci#define WB_SIO_GPIO34_ENABLE_4 1 8562306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_IO3 0xe0 8662306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_DATA3 0xe1 8762306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_INV3 0xe2 8862306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_IO4 0xe4 8962306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_DATA4 0xe5 9062306a36Sopenharmony_ci#define WB_SIO_GPIO34_REG_INV4 0xe6 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* WDTO, PLED, GPIO5, GPIO6 logical device */ 9362306a36Sopenharmony_ci#define WB_SIO_DEV_WDGPIO56 0x08 9462306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_ENABLE 0x30 9562306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_ENABLE_5 1 9662306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_ENABLE_6 2 9762306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_IO5 0xe0 9862306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_DATA5 0xe1 9962306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_INV5 0xe2 10062306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_IO6 0xe4 10162306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_DATA6 0xe5 10262306a36Sopenharmony_ci#define WB_SIO_WDGPIO56_REG_INV6 0xe6 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* GPIO1, GPIO2, SUSLED logical device */ 10562306a36Sopenharmony_ci#define WB_SIO_DEV_GPIO12 0x09 10662306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_ENABLE 0x30 10762306a36Sopenharmony_ci#define WB_SIO_GPIO12_ENABLE_1 0 10862306a36Sopenharmony_ci#define WB_SIO_GPIO12_ENABLE_2 1 10962306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_IO1 0xe0 11062306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_DATA1 0xe1 11162306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_INV1 0xe2 11262306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_IO2 0xe4 11362306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_DATA2 0xe5 11462306a36Sopenharmony_ci#define WB_SIO_GPIO12_REG_INV2 0xe6 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* UART D logical device */ 11762306a36Sopenharmony_ci#define WB_SIO_DEV_UARTD 0x0d 11862306a36Sopenharmony_ci#define WB_SIO_UARTD_REG_ENABLE 0x30 11962306a36Sopenharmony_ci#define WB_SIO_UARTD_ENABLE_ON 0 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* UART E logical device */ 12262306a36Sopenharmony_ci#define WB_SIO_DEV_UARTE 0x0e 12362306a36Sopenharmony_ci#define WB_SIO_UARTE_REG_ENABLE 0x30 12462306a36Sopenharmony_ci#define WB_SIO_UARTE_ENABLE_ON 0 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * for a description what a particular field of this struct means please see 12862306a36Sopenharmony_ci * a description of the relevant module parameter at the bottom of this file 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_cistruct winbond_gpio_params { 13162306a36Sopenharmony_ci unsigned long base; 13262306a36Sopenharmony_ci unsigned long gpios; 13362306a36Sopenharmony_ci unsigned long ppgpios; 13462306a36Sopenharmony_ci unsigned long odgpios; 13562306a36Sopenharmony_ci bool pledgpio; 13662306a36Sopenharmony_ci bool beepgpio; 13762306a36Sopenharmony_ci bool i2cgpio; 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic struct winbond_gpio_params params; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int winbond_sio_enter(unsigned long base) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci if (!request_muxed_region(base, 2, WB_GPIO_DRIVER_NAME)) 14562306a36Sopenharmony_ci return -EBUSY; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * datasheet says two successive writes of the "key" value are needed 14962306a36Sopenharmony_ci * in order for chip to enter the "Extended Function Mode" 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci outb(WB_SIO_EXT_ENTER_KEY, base); 15262306a36Sopenharmony_ci outb(WB_SIO_EXT_ENTER_KEY, base); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void winbond_sio_select_logical(unsigned long base, u8 dev) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci outb(WB_SIO_REG_LOGICAL, base); 16062306a36Sopenharmony_ci outb(dev, base + 1); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void winbond_sio_leave(unsigned long base) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci outb(WB_SIO_EXT_EXIT_KEY, base); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci release_region(base, 2); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void winbond_sio_reg_write(unsigned long base, u8 reg, u8 data) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci outb(reg, base); 17362306a36Sopenharmony_ci outb(data, base + 1); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic u8 winbond_sio_reg_read(unsigned long base, u8 reg) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci outb(reg, base); 17962306a36Sopenharmony_ci return inb(base + 1); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void winbond_sio_reg_bset(unsigned long base, u8 reg, u8 bit) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u8 val; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci val = winbond_sio_reg_read(base, reg); 18762306a36Sopenharmony_ci val |= BIT(bit); 18862306a36Sopenharmony_ci winbond_sio_reg_write(base, reg, val); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void winbond_sio_reg_bclear(unsigned long base, u8 reg, u8 bit) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci u8 val; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci val = winbond_sio_reg_read(base, reg); 19662306a36Sopenharmony_ci val &= ~BIT(bit); 19762306a36Sopenharmony_ci winbond_sio_reg_write(base, reg, val); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic bool winbond_sio_reg_btest(unsigned long base, u8 reg, u8 bit) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci return winbond_sio_reg_read(base, reg) & BIT(bit); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/** 20662306a36Sopenharmony_ci * struct winbond_gpio_port_conflict - possibly conflicting device information 20762306a36Sopenharmony_ci * @name: device name (NULL means no conflicting device defined) 20862306a36Sopenharmony_ci * @dev: Super I/O logical device number where the testreg register 20962306a36Sopenharmony_ci * is located (or WB_SIO_DEV_NONE - don't select any 21062306a36Sopenharmony_ci * logical device) 21162306a36Sopenharmony_ci * @testreg: register number where the testbit bit is located 21262306a36Sopenharmony_ci * @testbit: index of a bit to check whether an actual conflict exists 21362306a36Sopenharmony_ci * @warnonly: if set then a conflict isn't fatal (just warn about it), 21462306a36Sopenharmony_ci * otherwise disable the particular GPIO port if a conflict 21562306a36Sopenharmony_ci * is detected 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_cistruct winbond_gpio_port_conflict { 21862306a36Sopenharmony_ci const char *name; 21962306a36Sopenharmony_ci u8 dev; 22062306a36Sopenharmony_ci u8 testreg; 22162306a36Sopenharmony_ci u8 testbit; 22262306a36Sopenharmony_ci bool warnonly; 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * struct winbond_gpio_info - information about a particular GPIO port (device) 22762306a36Sopenharmony_ci * @dev: Super I/O logical device number of the registers 22862306a36Sopenharmony_ci * specified below 22962306a36Sopenharmony_ci * @enablereg: port enable bit register number 23062306a36Sopenharmony_ci * @enablebit: index of a port enable bit 23162306a36Sopenharmony_ci * @outputreg: output driver mode bit register number 23262306a36Sopenharmony_ci * @outputppbit: index of a push-pull output driver mode bit 23362306a36Sopenharmony_ci * @ioreg: data direction register number 23462306a36Sopenharmony_ci * @invreg: pin data inversion register number 23562306a36Sopenharmony_ci * @datareg: pin data register number 23662306a36Sopenharmony_ci * @conflict: description of a device that possibly conflicts with 23762306a36Sopenharmony_ci * this port 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_cistruct winbond_gpio_info { 24062306a36Sopenharmony_ci u8 dev; 24162306a36Sopenharmony_ci u8 enablereg; 24262306a36Sopenharmony_ci u8 enablebit; 24362306a36Sopenharmony_ci u8 outputreg; 24462306a36Sopenharmony_ci u8 outputppbit; 24562306a36Sopenharmony_ci u8 ioreg; 24662306a36Sopenharmony_ci u8 invreg; 24762306a36Sopenharmony_ci u8 datareg; 24862306a36Sopenharmony_ci struct winbond_gpio_port_conflict conflict; 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic const struct winbond_gpio_info winbond_gpio_infos[6] = { 25262306a36Sopenharmony_ci { /* 0 */ 25362306a36Sopenharmony_ci .dev = WB_SIO_DEV_GPIO12, 25462306a36Sopenharmony_ci .enablereg = WB_SIO_GPIO12_REG_ENABLE, 25562306a36Sopenharmony_ci .enablebit = WB_SIO_GPIO12_ENABLE_1, 25662306a36Sopenharmony_ci .outputreg = WB_SIO_REG_GPIO1_MF, 25762306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_G1MF_G1PP, 25862306a36Sopenharmony_ci .ioreg = WB_SIO_GPIO12_REG_IO1, 25962306a36Sopenharmony_ci .invreg = WB_SIO_GPIO12_REG_INV1, 26062306a36Sopenharmony_ci .datareg = WB_SIO_GPIO12_REG_DATA1, 26162306a36Sopenharmony_ci .conflict = { 26262306a36Sopenharmony_ci .name = "UARTB", 26362306a36Sopenharmony_ci .dev = WB_SIO_DEV_UARTB, 26462306a36Sopenharmony_ci .testreg = WB_SIO_UARTB_REG_ENABLE, 26562306a36Sopenharmony_ci .testbit = WB_SIO_UARTB_ENABLE_ON, 26662306a36Sopenharmony_ci .warnonly = true 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci }, 26962306a36Sopenharmony_ci { /* 1 */ 27062306a36Sopenharmony_ci .dev = WB_SIO_DEV_GPIO12, 27162306a36Sopenharmony_ci .enablereg = WB_SIO_GPIO12_REG_ENABLE, 27262306a36Sopenharmony_ci .enablebit = WB_SIO_GPIO12_ENABLE_2, 27362306a36Sopenharmony_ci .outputreg = WB_SIO_REG_GPIO1_MF, 27462306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_G1MF_G2PP, 27562306a36Sopenharmony_ci .ioreg = WB_SIO_GPIO12_REG_IO2, 27662306a36Sopenharmony_ci .invreg = WB_SIO_GPIO12_REG_INV2, 27762306a36Sopenharmony_ci .datareg = WB_SIO_GPIO12_REG_DATA2 27862306a36Sopenharmony_ci /* special conflict handling so doesn't use conflict data */ 27962306a36Sopenharmony_ci }, 28062306a36Sopenharmony_ci { /* 2 */ 28162306a36Sopenharmony_ci .dev = WB_SIO_DEV_GPIO34, 28262306a36Sopenharmony_ci .enablereg = WB_SIO_GPIO34_REG_ENABLE, 28362306a36Sopenharmony_ci .enablebit = WB_SIO_GPIO34_ENABLE_3, 28462306a36Sopenharmony_ci .outputreg = WB_SIO_REG_OVTGPIO3456, 28562306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_OG3456_G3PP, 28662306a36Sopenharmony_ci .ioreg = WB_SIO_GPIO34_REG_IO3, 28762306a36Sopenharmony_ci .invreg = WB_SIO_GPIO34_REG_INV3, 28862306a36Sopenharmony_ci .datareg = WB_SIO_GPIO34_REG_DATA3, 28962306a36Sopenharmony_ci .conflict = { 29062306a36Sopenharmony_ci .name = "UARTC", 29162306a36Sopenharmony_ci .dev = WB_SIO_DEV_UARTC, 29262306a36Sopenharmony_ci .testreg = WB_SIO_UARTC_REG_ENABLE, 29362306a36Sopenharmony_ci .testbit = WB_SIO_UARTC_ENABLE_ON, 29462306a36Sopenharmony_ci .warnonly = true 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci }, 29762306a36Sopenharmony_ci { /* 3 */ 29862306a36Sopenharmony_ci .dev = WB_SIO_DEV_GPIO34, 29962306a36Sopenharmony_ci .enablereg = WB_SIO_GPIO34_REG_ENABLE, 30062306a36Sopenharmony_ci .enablebit = WB_SIO_GPIO34_ENABLE_4, 30162306a36Sopenharmony_ci .outputreg = WB_SIO_REG_OVTGPIO3456, 30262306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_OG3456_G4PP, 30362306a36Sopenharmony_ci .ioreg = WB_SIO_GPIO34_REG_IO4, 30462306a36Sopenharmony_ci .invreg = WB_SIO_GPIO34_REG_INV4, 30562306a36Sopenharmony_ci .datareg = WB_SIO_GPIO34_REG_DATA4, 30662306a36Sopenharmony_ci .conflict = { 30762306a36Sopenharmony_ci .name = "UARTD", 30862306a36Sopenharmony_ci .dev = WB_SIO_DEV_UARTD, 30962306a36Sopenharmony_ci .testreg = WB_SIO_UARTD_REG_ENABLE, 31062306a36Sopenharmony_ci .testbit = WB_SIO_UARTD_ENABLE_ON, 31162306a36Sopenharmony_ci .warnonly = true 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci }, 31462306a36Sopenharmony_ci { /* 4 */ 31562306a36Sopenharmony_ci .dev = WB_SIO_DEV_WDGPIO56, 31662306a36Sopenharmony_ci .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, 31762306a36Sopenharmony_ci .enablebit = WB_SIO_WDGPIO56_ENABLE_5, 31862306a36Sopenharmony_ci .outputreg = WB_SIO_REG_OVTGPIO3456, 31962306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_OG3456_G5PP, 32062306a36Sopenharmony_ci .ioreg = WB_SIO_WDGPIO56_REG_IO5, 32162306a36Sopenharmony_ci .invreg = WB_SIO_WDGPIO56_REG_INV5, 32262306a36Sopenharmony_ci .datareg = WB_SIO_WDGPIO56_REG_DATA5, 32362306a36Sopenharmony_ci .conflict = { 32462306a36Sopenharmony_ci .name = "UARTE", 32562306a36Sopenharmony_ci .dev = WB_SIO_DEV_UARTE, 32662306a36Sopenharmony_ci .testreg = WB_SIO_UARTE_REG_ENABLE, 32762306a36Sopenharmony_ci .testbit = WB_SIO_UARTE_ENABLE_ON, 32862306a36Sopenharmony_ci .warnonly = true 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci }, 33162306a36Sopenharmony_ci { /* 5 */ 33262306a36Sopenharmony_ci .dev = WB_SIO_DEV_WDGPIO56, 33362306a36Sopenharmony_ci .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, 33462306a36Sopenharmony_ci .enablebit = WB_SIO_WDGPIO56_ENABLE_6, 33562306a36Sopenharmony_ci .outputreg = WB_SIO_REG_OVTGPIO3456, 33662306a36Sopenharmony_ci .outputppbit = WB_SIO_REG_OG3456_G6PP, 33762306a36Sopenharmony_ci .ioreg = WB_SIO_WDGPIO56_REG_IO6, 33862306a36Sopenharmony_ci .invreg = WB_SIO_WDGPIO56_REG_INV6, 33962306a36Sopenharmony_ci .datareg = WB_SIO_WDGPIO56_REG_DATA6, 34062306a36Sopenharmony_ci .conflict = { 34162306a36Sopenharmony_ci .name = "FDC", 34262306a36Sopenharmony_ci .dev = WB_SIO_DEV_NONE, 34362306a36Sopenharmony_ci .testreg = WB_SIO_REG_GLOBAL_OPT, 34462306a36Sopenharmony_ci .testbit = WB_SIO_REG_GO_ENFDC, 34562306a36Sopenharmony_ci .warnonly = false 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci}; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* returns whether changing a pin is allowed */ 35162306a36Sopenharmony_cistatic bool winbond_gpio_get_info(unsigned int *gpio_num, 35262306a36Sopenharmony_ci const struct winbond_gpio_info **info) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci bool allow_changing = true; 35562306a36Sopenharmony_ci unsigned long i; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) { 35862306a36Sopenharmony_ci if (*gpio_num < 8) 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci *gpio_num -= 8; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci *info = &winbond_gpio_infos[i]; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* 36762306a36Sopenharmony_ci * GPIO2 (the second port) shares some pins with a basic PC 36862306a36Sopenharmony_ci * functionality, which is very likely controlled by the firmware. 36962306a36Sopenharmony_ci * Don't allow changing these pins by default. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci if (i == 1) { 37262306a36Sopenharmony_ci if (*gpio_num == 0 && !params.pledgpio) 37362306a36Sopenharmony_ci allow_changing = false; 37462306a36Sopenharmony_ci else if (*gpio_num == 1 && !params.beepgpio) 37562306a36Sopenharmony_ci allow_changing = false; 37662306a36Sopenharmony_ci else if ((*gpio_num == 5 || *gpio_num == 6) && !params.i2cgpio) 37762306a36Sopenharmony_ci allow_changing = false; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return allow_changing; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int winbond_gpio_get(struct gpio_chip *gc, unsigned int offset) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci unsigned long *base = gpiochip_get_data(gc); 38662306a36Sopenharmony_ci const struct winbond_gpio_info *info; 38762306a36Sopenharmony_ci bool val; 38862306a36Sopenharmony_ci int ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci winbond_gpio_get_info(&offset, &info); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ret = winbond_sio_enter(*base); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci return ret; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci winbond_sio_select_logical(*base, info->dev); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci val = winbond_sio_reg_btest(*base, info->datareg, offset); 39962306a36Sopenharmony_ci if (winbond_sio_reg_btest(*base, info->invreg, offset)) 40062306a36Sopenharmony_ci val = !val; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci winbond_sio_leave(*base); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return val; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int winbond_gpio_direction_in(struct gpio_chip *gc, unsigned int offset) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci unsigned long *base = gpiochip_get_data(gc); 41062306a36Sopenharmony_ci const struct winbond_gpio_info *info; 41162306a36Sopenharmony_ci int ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (!winbond_gpio_get_info(&offset, &info)) 41462306a36Sopenharmony_ci return -EACCES; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ret = winbond_sio_enter(*base); 41762306a36Sopenharmony_ci if (ret) 41862306a36Sopenharmony_ci return ret; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci winbond_sio_select_logical(*base, info->dev); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci winbond_sio_reg_bset(*base, info->ioreg, offset); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci winbond_sio_leave(*base); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int winbond_gpio_direction_out(struct gpio_chip *gc, 43062306a36Sopenharmony_ci unsigned int offset, 43162306a36Sopenharmony_ci int val) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci unsigned long *base = gpiochip_get_data(gc); 43462306a36Sopenharmony_ci const struct winbond_gpio_info *info; 43562306a36Sopenharmony_ci int ret; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (!winbond_gpio_get_info(&offset, &info)) 43862306a36Sopenharmony_ci return -EACCES; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ret = winbond_sio_enter(*base); 44162306a36Sopenharmony_ci if (ret) 44262306a36Sopenharmony_ci return ret; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci winbond_sio_select_logical(*base, info->dev); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci winbond_sio_reg_bclear(*base, info->ioreg, offset); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (winbond_sio_reg_btest(*base, info->invreg, offset)) 44962306a36Sopenharmony_ci val = !val; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (val) 45262306a36Sopenharmony_ci winbond_sio_reg_bset(*base, info->datareg, offset); 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci winbond_sio_reg_bclear(*base, info->datareg, offset); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci winbond_sio_leave(*base); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void winbond_gpio_set(struct gpio_chip *gc, unsigned int offset, 46262306a36Sopenharmony_ci int val) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci unsigned long *base = gpiochip_get_data(gc); 46562306a36Sopenharmony_ci const struct winbond_gpio_info *info; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!winbond_gpio_get_info(&offset, &info)) 46862306a36Sopenharmony_ci return; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (winbond_sio_enter(*base) != 0) 47162306a36Sopenharmony_ci return; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci winbond_sio_select_logical(*base, info->dev); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (winbond_sio_reg_btest(*base, info->invreg, offset)) 47662306a36Sopenharmony_ci val = !val; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (val) 47962306a36Sopenharmony_ci winbond_sio_reg_bset(*base, info->datareg, offset); 48062306a36Sopenharmony_ci else 48162306a36Sopenharmony_ci winbond_sio_reg_bclear(*base, info->datareg, offset); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci winbond_sio_leave(*base); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic struct gpio_chip winbond_gpio_chip = { 48762306a36Sopenharmony_ci .base = -1, 48862306a36Sopenharmony_ci .label = WB_GPIO_DRIVER_NAME, 48962306a36Sopenharmony_ci .owner = THIS_MODULE, 49062306a36Sopenharmony_ci .can_sleep = true, 49162306a36Sopenharmony_ci .get = winbond_gpio_get, 49262306a36Sopenharmony_ci .direction_input = winbond_gpio_direction_in, 49362306a36Sopenharmony_ci .set = winbond_gpio_set, 49462306a36Sopenharmony_ci .direction_output = winbond_gpio_direction_out, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void winbond_gpio_configure_port0_pins(unsigned long base) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci unsigned int val; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci val = winbond_sio_reg_read(base, WB_SIO_REG_GPIO1_MF); 50262306a36Sopenharmony_ci if ((val & WB_SIO_REG_G1MF_FS_MASK) == WB_SIO_REG_G1MF_FS_GPIO1) 50362306a36Sopenharmony_ci return; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci pr_warn("GPIO1 pins were connected to something else (%.2x), fixing\n", 50662306a36Sopenharmony_ci val); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci val &= ~WB_SIO_REG_G1MF_FS_MASK; 50962306a36Sopenharmony_ci val |= WB_SIO_REG_G1MF_FS_GPIO1; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci winbond_sio_reg_write(base, WB_SIO_REG_GPIO1_MF, val); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic void winbond_gpio_configure_port1_check_i2c(unsigned long base) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci params.i2cgpio = !winbond_sio_reg_btest(base, WB_SIO_REG_I2C_PS, 51762306a36Sopenharmony_ci WB_SIO_REG_I2CPS_I2CFS); 51862306a36Sopenharmony_ci if (!params.i2cgpio) 51962306a36Sopenharmony_ci pr_warn("disabling GPIO2.5 and GPIO2.6 as I2C is enabled\n"); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic bool winbond_gpio_configure_port(unsigned long base, unsigned int idx) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci const struct winbond_gpio_info *info = &winbond_gpio_infos[idx]; 52562306a36Sopenharmony_ci const struct winbond_gpio_port_conflict *conflict = &info->conflict; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* is there a possible conflicting device defined? */ 52862306a36Sopenharmony_ci if (conflict->name != NULL) { 52962306a36Sopenharmony_ci if (conflict->dev != WB_SIO_DEV_NONE) 53062306a36Sopenharmony_ci winbond_sio_select_logical(base, conflict->dev); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (winbond_sio_reg_btest(base, conflict->testreg, 53362306a36Sopenharmony_ci conflict->testbit)) { 53462306a36Sopenharmony_ci if (conflict->warnonly) 53562306a36Sopenharmony_ci pr_warn("enabled GPIO%u share pins with active %s\n", 53662306a36Sopenharmony_ci idx + 1, conflict->name); 53762306a36Sopenharmony_ci else { 53862306a36Sopenharmony_ci pr_warn("disabling GPIO%u as %s is enabled\n", 53962306a36Sopenharmony_ci idx + 1, conflict->name); 54062306a36Sopenharmony_ci return false; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* GPIO1 and GPIO2 need some (additional) special handling */ 54662306a36Sopenharmony_ci if (idx == 0) 54762306a36Sopenharmony_ci winbond_gpio_configure_port0_pins(base); 54862306a36Sopenharmony_ci else if (idx == 1) 54962306a36Sopenharmony_ci winbond_gpio_configure_port1_check_i2c(base); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci winbond_sio_select_logical(base, info->dev); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci winbond_sio_reg_bset(base, info->enablereg, info->enablebit); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (params.ppgpios & BIT(idx)) 55662306a36Sopenharmony_ci winbond_sio_reg_bset(base, info->outputreg, 55762306a36Sopenharmony_ci info->outputppbit); 55862306a36Sopenharmony_ci else if (params.odgpios & BIT(idx)) 55962306a36Sopenharmony_ci winbond_sio_reg_bclear(base, info->outputreg, 56062306a36Sopenharmony_ci info->outputppbit); 56162306a36Sopenharmony_ci else 56262306a36Sopenharmony_ci pr_notice("GPIO%u pins are %s\n", idx + 1, 56362306a36Sopenharmony_ci winbond_sio_reg_btest(base, info->outputreg, 56462306a36Sopenharmony_ci info->outputppbit) ? 56562306a36Sopenharmony_ci "push-pull" : 56662306a36Sopenharmony_ci "open drain"); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return true; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int winbond_gpio_configure(unsigned long base) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci unsigned long i; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) 57662306a36Sopenharmony_ci if (!winbond_gpio_configure_port(base, i)) 57762306a36Sopenharmony_ci __clear_bit(i, ¶ms.gpios); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!params.gpios) { 58062306a36Sopenharmony_ci pr_err("please use 'gpios' module parameter to select some active GPIO ports to enable\n"); 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int winbond_gpio_check_chip(unsigned long base) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci int ret; 59062306a36Sopenharmony_ci unsigned int chip; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci ret = winbond_sio_enter(base); 59362306a36Sopenharmony_ci if (ret) 59462306a36Sopenharmony_ci return ret; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci chip = winbond_sio_reg_read(base, WB_SIO_REG_CHIP_MSB) << 8; 59762306a36Sopenharmony_ci chip |= winbond_sio_reg_read(base, WB_SIO_REG_CHIP_LSB); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci pr_notice("chip ID at %lx is %.4x\n", base, chip); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if ((chip & WB_SIO_CHIP_ID_W83627UHG_MASK) != 60262306a36Sopenharmony_ci WB_SIO_CHIP_ID_W83627UHG) { 60362306a36Sopenharmony_ci pr_err("not an our chip\n"); 60462306a36Sopenharmony_ci ret = -ENODEV; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci winbond_sio_leave(base); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return ret; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int winbond_gpio_imatch(struct device *dev, unsigned int id) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci unsigned long gpios_rem; 61562306a36Sopenharmony_ci int ret; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci gpios_rem = params.gpios & ~GENMASK(ARRAY_SIZE(winbond_gpio_infos) - 1, 61862306a36Sopenharmony_ci 0); 61962306a36Sopenharmony_ci if (gpios_rem) { 62062306a36Sopenharmony_ci pr_warn("unknown ports (%lx) enabled in GPIO ports bitmask\n", 62162306a36Sopenharmony_ci gpios_rem); 62262306a36Sopenharmony_ci params.gpios &= ~gpios_rem; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (params.ppgpios & params.odgpios) { 62662306a36Sopenharmony_ci pr_err("some GPIO ports are set both to push-pull and open drain mode at the same time\n"); 62762306a36Sopenharmony_ci return 0; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (params.base != 0) 63162306a36Sopenharmony_ci return winbond_gpio_check_chip(params.base) == 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* 63462306a36Sopenharmony_ci * if the 'base' module parameter is unset probe two chip default 63562306a36Sopenharmony_ci * I/O port bases 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci params.base = WB_SIO_BASE; 63862306a36Sopenharmony_ci ret = winbond_gpio_check_chip(params.base); 63962306a36Sopenharmony_ci if (ret == 0) 64062306a36Sopenharmony_ci return 1; 64162306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EBUSY) 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci params.base = WB_SIO_BASE_HIGH; 64562306a36Sopenharmony_ci return winbond_gpio_check_chip(params.base) == 0; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int winbond_gpio_iprobe(struct device *dev, unsigned int id) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci int ret; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (params.base == 0) 65362306a36Sopenharmony_ci return -EINVAL; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ret = winbond_sio_enter(params.base); 65662306a36Sopenharmony_ci if (ret) 65762306a36Sopenharmony_ci return ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = winbond_gpio_configure(params.base); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci winbond_sio_leave(params.base); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (ret) 66462306a36Sopenharmony_ci return ret; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* 66762306a36Sopenharmony_ci * Add 8 gpios for every GPIO port that was enabled in gpios 66862306a36Sopenharmony_ci * module parameter (that wasn't disabled earlier in 66962306a36Sopenharmony_ci * winbond_gpio_configure() & co. due to, for example, a pin conflict). 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci winbond_gpio_chip.ngpio = hweight_long(params.gpios) * 8; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* 67462306a36Sopenharmony_ci * GPIO6 port has only 5 pins, so if it is enabled we have to adjust 67562306a36Sopenharmony_ci * the total count appropriately 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_ci if (params.gpios & BIT(5)) 67862306a36Sopenharmony_ci winbond_gpio_chip.ngpio -= (8 - 5); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci winbond_gpio_chip.parent = dev; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return devm_gpiochip_add_data(dev, &winbond_gpio_chip, ¶ms.base); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic struct isa_driver winbond_gpio_idriver = { 68662306a36Sopenharmony_ci .driver = { 68762306a36Sopenharmony_ci .name = WB_GPIO_DRIVER_NAME, 68862306a36Sopenharmony_ci }, 68962306a36Sopenharmony_ci .match = winbond_gpio_imatch, 69062306a36Sopenharmony_ci .probe = winbond_gpio_iprobe, 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cimodule_isa_driver(winbond_gpio_idriver, 1); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cimodule_param_named(base, params.base, ulong, 0444); 69662306a36Sopenharmony_ciMODULE_PARM_DESC(base, 69762306a36Sopenharmony_ci "I/O port base (when unset - probe chip default ones)"); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/* This parameter sets which GPIO devices (ports) we enable */ 70062306a36Sopenharmony_cimodule_param_named(gpios, params.gpios, ulong, 0444); 70162306a36Sopenharmony_ciMODULE_PARM_DESC(gpios, 70262306a36Sopenharmony_ci "bitmask of GPIO ports to enable (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/* 70562306a36Sopenharmony_ci * These two parameters below set how we configure GPIO ports output drivers. 70662306a36Sopenharmony_ci * It can't be a one bitmask since we need three values per port: push-pull, 70762306a36Sopenharmony_ci * open-drain and keep as-is (this is the default). 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_cimodule_param_named(ppgpios, params.ppgpios, ulong, 0444); 71062306a36Sopenharmony_ciMODULE_PARM_DESC(ppgpios, 71162306a36Sopenharmony_ci "bitmask of GPIO ports to set to push-pull mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cimodule_param_named(odgpios, params.odgpios, ulong, 0444); 71462306a36Sopenharmony_ciMODULE_PARM_DESC(odgpios, 71562306a36Sopenharmony_ci "bitmask of GPIO ports to set to open drain mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* 71862306a36Sopenharmony_ci * GPIO2.0 and GPIO2.1 control a basic PC functionality that we 71962306a36Sopenharmony_ci * don't allow tinkering with by default (it is very likely that the 72062306a36Sopenharmony_ci * firmware owns these pins). 72162306a36Sopenharmony_ci * These two parameters below allow overriding these prohibitions. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_cimodule_param_named(pledgpio, params.pledgpio, bool, 0644); 72462306a36Sopenharmony_ciMODULE_PARM_DESC(pledgpio, 72562306a36Sopenharmony_ci "enable changing value of GPIO2.0 bit (Power LED), default no."); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cimodule_param_named(beepgpio, params.beepgpio, bool, 0644); 72862306a36Sopenharmony_ciMODULE_PARM_DESC(beepgpio, 72962306a36Sopenharmony_ci "enable changing value of GPIO2.1 bit (BEEP), default no."); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ciMODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>"); 73262306a36Sopenharmony_ciMODULE_DESCRIPTION("GPIO interface for Winbond Super I/O chips"); 73362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 734