// SPDX-License-Identifier: GPL-2.0+ /* * GPIO interface for Winbond Super I/O chips * Currently, only W83627UHG (Nuvoton NCT6627UD) is supported. * * Author: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
*/
/* * for a description what a particular field of this struct means please see * a description of the relevant module parameter at the bottom of this file
*/ struct winbond_gpio_params { unsignedlong base; unsignedlong gpios; unsignedlong ppgpios; unsignedlong odgpios; bool pledgpio; bool beepgpio; bool i2cgpio;
};
staticstruct winbond_gpio_params params;
staticint winbond_sio_enter(unsignedlong base)
{ if (!request_muxed_region(base, 2, WB_GPIO_DRIVER_NAME)) return -EBUSY;
/* * datasheet says two successive writes of the "key" value are needed * in order for chip to enter the "Extended Function Mode"
*/
outb(WB_SIO_EXT_ENTER_KEY, base);
outb(WB_SIO_EXT_ENTER_KEY, base);
/** * struct winbond_gpio_port_conflict - possibly conflicting device information * @name: device name (NULL means no conflicting device defined) * @dev: Super I/O logical device number where the testreg register * is located (or WB_SIO_DEV_NONE - don't select any * logical device) * @testreg: register number where the testbit bit is located * @testbit: index of a bit to check whether an actual conflict exists * @warnonly: if set then a conflict isn't fatal (just warn about it), * otherwise disable the particular GPIO port if a conflict * is detected
*/ struct winbond_gpio_port_conflict { constchar *name;
u8 dev;
u8 testreg;
u8 testbit; bool warnonly;
};
/** * struct winbond_gpio_info - information about a particular GPIO port (device) * @dev: Super I/O logical device number of the registers * specified below * @enablereg: port enable bit register number * @enablebit: index of a port enable bit * @outputreg: output driver mode bit register number * @outputppbit: index of a push-pull output driver mode bit * @ioreg: data direction register number * @invreg: pin data inversion register number * @datareg: pin data register number * @conflict: description of a device that possibly conflicts with * this port
*/ struct winbond_gpio_info {
u8 dev;
u8 enablereg;
u8 enablebit;
u8 outputreg;
u8 outputppbit;
u8 ioreg;
u8 invreg;
u8 datareg; struct winbond_gpio_port_conflict conflict;
};
for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) { if (*gpio_num < 8) break;
*gpio_num -= 8;
}
*info = &winbond_gpio_infos[i];
/* * GPIO2 (the second port) shares some pins with a basic PC * functionality, which is very likely controlled by the firmware. * Don't allow changing these pins by default.
*/ if (i == 1) { if (*gpio_num == 0 && !params.pledgpio)
allow_changing = false; elseif (*gpio_num == 1 && !params.beepgpio)
allow_changing = false; elseif ((*gpio_num == 5 || *gpio_num == 6) && !params.i2cgpio)
allow_changing = false;
}
staticvoid winbond_gpio_configure_port1_check_i2c(unsignedlong base)
{
params.i2cgpio = !winbond_sio_reg_btest(base, WB_SIO_REG_I2C_PS,
WB_SIO_REG_I2CPS_I2CFS); if (!params.i2cgpio)
pr_warn("disabling GPIO2.5 and GPIO2.6 as I2C is enabled\n");
}
/* is there a possible conflicting device defined? */ if (conflict->name != NULL) { if (conflict->dev != WB_SIO_DEV_NONE)
winbond_sio_select_logical(base, conflict->dev);
if (winbond_sio_reg_btest(base, conflict->testreg,
conflict->testbit)) { if (conflict->warnonly)
pr_warn("enabled GPIO%u share pins with active %s\n",
idx + 1, conflict->name); else {
pr_warn("disabling GPIO%u as %s is enabled\n",
idx + 1, conflict->name); returnfalse;
}
}
}
/* GPIO1 and GPIO2 need some (additional) special handling */ if (idx == 0)
winbond_gpio_configure_port0_pins(base); elseif (idx == 1)
winbond_gpio_configure_port1_check_i2c(base);
if (params.ppgpios & params.odgpios) {
pr_err("some GPIO ports are set both to push-pull and open drain mode at the same time\n"); return 0;
}
if (params.base != 0) return winbond_gpio_check_chip(params.base) == 0;
/* * if the 'base' module parameter is unset probe two chip default * I/O port bases
*/
params.base = WB_SIO_BASE;
ret = winbond_gpio_check_chip(params.base); if (ret == 0) return 1; if (ret != -ENODEV && ret != -EBUSY) return 0;
staticint winbond_gpio_iprobe(struct device *dev, unsignedint id)
{ int ret;
if (params.base == 0) return -EINVAL;
ret = winbond_sio_enter(params.base); if (ret) return ret;
ret = winbond_gpio_configure(params.base);
winbond_sio_leave(params.base);
if (ret) return ret;
/* * Add 8 gpios for every GPIO port that was enabled in gpios * module parameter (that wasn't disabled earlier in * winbond_gpio_configure() & co. due to, for example, a pin conflict).
*/
winbond_gpio_chip.ngpio = hweight_long(params.gpios) * 8;
/* * GPIO6 port has only 5 pins, so if it is enabled we have to adjust * the total count appropriately
*/ if (params.gpios & BIT(5))
winbond_gpio_chip.ngpio -= (8 - 5);
module_param_named(base, params.base, ulong, 0444);
MODULE_PARM_DESC(base, "I/O port base (when unset - probe chip default ones)");
/* This parameter sets which GPIO devices (ports) we enable */
module_param_named(gpios, params.gpios, ulong, 0444);
MODULE_PARM_DESC(gpios, "bitmask of GPIO ports to enable (bit 0 - GPIO1, bit 1 - GPIO2, etc.");
/* * These two parameters below set how we configure GPIO ports output drivers. * It can't be a one bitmask since we need three values per port: push-pull, * open-drain and keep as-is (this is the default).
*/
module_param_named(ppgpios, params.ppgpios, ulong, 0444);
MODULE_PARM_DESC(ppgpios, "bitmask of GPIO ports to set to push-pull mode (bit 0 - GPIO1, bit 1 - GPIO2, etc.");
module_param_named(odgpios, params.odgpios, ulong, 0444);
MODULE_PARM_DESC(odgpios, "bitmask of GPIO ports to set to open drain mode (bit 0 - GPIO1, bit 1 - GPIO2, etc.");
/* * GPIO2.0 and GPIO2.1 control a basic PC functionality that we * don't allow tinkering with by default (it is very likely that the * firmware owns these pins). * These two parameters below allow overriding these prohibitions.
*/
module_param_named(pledgpio, params.pledgpio, bool, 0644);
MODULE_PARM_DESC(pledgpio, "enable changing value of GPIO2.0 bit (Power LED), default no.");
module_param_named(beepgpio, params.beepgpio, bool, 0644);
MODULE_PARM_DESC(beepgpio, "enable changing value of GPIO2.1 bit (BEEP), default no.");
MODULE_AUTHOR("Maciej S. Szmigiero ");
MODULE_DESCRIPTION("GPIO interface for Winbond Super I/O chips");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.