static int f7188x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { int err; struct f7188x_gpio_bank *bank = container_of(chip, struct f7188x_gpio_bank, chip); struct f7188x_sio *sio = bank->data->sio; u8 dir, data_out; err = superio_enter(sio->addr); if (err) return err; superio_select(sio->addr, SIO_LD_GPIO); data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); if (value) data_out |= (1 << offset); else data_out &= ~(1 << offset); superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); dir |= (1 << offset); superio_outb(sio->addr, gpio_dir(bank->regbase), dir); superio_exit(sio->addr); return 0; }
static void wdt_stop(void) { unsigned long flags; spin_lock_irqsave(&spinlock, flags); superio_enter(); superio_select(GPIO); superio_outb(0x00, WDTCTRL); superio_outb(WDT_TOV1, WDTCFG); superio_outb(0x00, WDTVALMSB); superio_outb(0x00, WDTVALLSB); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); }
static void select_pin(unsigned iminor) { /* select GPIO port/pin from device minor number */ device_select(SIO_GPIO_UNIT); superio_outb(SIO_GPIO_PIN_SELECT, ((iminor << 1) & 0xF0) | (iminor & 0x7)); }
static void select_pin(unsigned iminor) { device_select(SIO_GPIO_UNIT); superio_outb(SIO_GPIO_PIN_SELECT, ((iminor << 1) & 0xF0) | (iminor & 0x7)); }
static ssize_t beep_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nct6683_data *data = dev_get_drvdata(dev); unsigned long val; u8 reg; int ret; if (kstrtoul(buf, 10, &val) || (val != 0 && val != 1)) return -EINVAL; mutex_lock(&data->update_lock); ret = superio_enter(data->sioreg); if (ret) { count = ret; goto error; } superio_select(data->sioreg, NCT6683_LD_HWM); reg = superio_inb(data->sioreg, NCT6683_REG_CR_BEEP); if (val) reg |= NCT6683_CR_BEEP_MASK; else reg &= ~NCT6683_CR_BEEP_MASK; superio_outb(data->sioreg, NCT6683_REG_CR_BEEP, reg); superio_exit(data->sioreg); error: mutex_unlock(&data->update_lock); return count; }
/* * The Nuvoton NCT6102D starts per default after reset with both, * the internal watchdog and the internal legacy UART enabled. This * code provides a function to disable the watchdog. */ int nct6102d_wdt_disable(void) { superio_enter(); /* Select logical device for WDT */ superio_select(NCT6102D_LD_WDT); superio_outb(NCT6102D_WDT_TIMEOUT, 0x00); superio_exit(); return 0; }
static void wdt_start(void) { unsigned long flags; spin_lock_irqsave(&spinlock, flags); superio_enter(); superio_select(GPIO); if (test_bit(WDTS_USE_GP, &wdt_status)) superio_outb(WDT_GAMEPORT, WDTCTRL); else superio_outb(WDT_CIRINT, WDTCTRL); if (!testmode) superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); else superio_outb(WDT_TOV1, WDTCFG); superio_outb(timeout>>8, WDTVALMSB); superio_outb(timeout, WDTVALLSB); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); }
static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data) { int addr; u16 val; int err; err = superio_enter(sioaddr); if (err) return err; val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | superio_inb(sioaddr, SIO_REG_DEVID + 1); switch (val & SIO_ID_MASK) { case SIO_NCT6683_ID: sio_data->kind = nct6683; break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); goto fail; } /* We have a known chip, find the HWM I/O address */ superio_select(sioaddr, NCT6683_LD_HWM); val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) | superio_inb(sioaddr, SIO_REG_ADDR + 1); addr = val & IOREGION_ALIGNMENT; if (addr == 0) { pr_err("EC base I/O port unconfigured\n"); goto fail; } /* Activate logical device if needed */ val = superio_inb(sioaddr, SIO_REG_ENABLE); if (!(val & 0x01)) { pr_warn("Forcibly enabling EC access. Data may be unusable.\n"); superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } superio_exit(sioaddr); pr_info("Found %s or compatible chip at %#x:%#x\n", nct6683_chip_names[sio_data->kind], sioaddr, addr); sio_data->sioreg = sioaddr; return addr; fail: superio_exit(sioaddr); return -ENODEV; }
static ssize_t intrusion0_alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nct6683_data *data = dev_get_drvdata(dev); unsigned long val; u8 reg; int ret; if (kstrtoul(buf, 10, &val) || val != 0) return -EINVAL; mutex_lock(&data->update_lock); /* * Use CR registers to clear caseopen status. * Caseopen is activ low, clear by writing 1 into the register. */ ret = superio_enter(data->sioreg); if (ret) { count = ret; goto error; } superio_select(data->sioreg, NCT6683_LD_ACPI); reg = superio_inb(data->sioreg, NCT6683_REG_CR_CASEOPEN); reg |= NCT6683_CR_CASEOPEN_MASK; superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); reg &= ~NCT6683_CR_CASEOPEN_MASK; superio_outb(data->sioreg, NCT6683_REG_CR_CASEOPEN, reg); superio_exit(data->sioreg); data->valid = false; /* Force cache refresh */ error: mutex_unlock(&data->update_lock); return count; }
static int wdt_set_time(unsigned int timeout) { int ret; ret = superio_enter(); if (ret) return ret; superio_select(W83627HF_LD_WDT); superio_outb(cr_wdt_timeout, timeout); superio_exit(); return 0; }
static int wdt_set_timeout(int t) { unsigned long flags; if (t < 1 || t > 65535) return -EINVAL; timeout = t; spin_lock_irqsave(&spinlock, flags); if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { superio_enter(); superio_select(GPIO); superio_outb(t>>8, WDTVALMSB); superio_outb(t, WDTVALLSB); superio_exit(); }
static int __init qnap_gpio_button_init(void) { u16 chip_type; u8 chip_rev; unsigned long flags; int err = -ENODEV; int tmp; spin_lock_irqsave(&spinlock, flags); superio_enter(); chip_type = superio_inw(SIO_CHIP_ID); chip_rev = superio_inb(SIO_CHIP_REV) & 0x0f; if (chip_type != SIO_IT8718_ID) goto exit; superio_select(SIO_GPIO_LDN); gpio_base_address = superio_inw(GPIO_ADDR_MSB_REG); // GP16 GP17 tmp = superio_inb(GPIO_SET1_SEL_REG); superio_outb(GPIO_SET1_SEL_REG, tmp | 0xc0); //select GPIO Set1 function tmp = superio_inb(GPIO_SET1_ENABLE_REG); superio_outb(GPIO_SET1_ENABLE_REG, tmp | 0xc0); //enable simple IO function tmp = superio_inb(GPIO_SET1_OUTPUT_EN_REG); superio_outb(GPIO_SET1_OUTPUT_EN_REG, tmp & 0x3f); //enable input direction superio_outb(GPIO_DBOUNCE_SEL_REG, 0x03); // set De-Bounce tmp = superio_inb(GPIO_SMI_STATUS_REG); superio_outb(GPIO_SMI_STATUS_REG, tmp | 0xc0); /* reset panel button de-bounce status */ superio_outb(GPIO_BTN0_MAPPING_REG, 0x4e); /* GP16 = 001110 */ superio_outb(GPIO_BTN1_MAPPING_REG, 0x4f); /* GP17 = 001111 */ err = 0; exit: superio_exit(); spin_unlock_irqrestore(&spinlock, flags); return err; }
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { int err; struct f7188x_gpio_bank *bank = gpiochip_get_data(chip); struct f7188x_sio *sio = bank->data->sio; u8 dir; err = superio_enter(sio->addr); if (err) return err; superio_select(sio->addr, SIO_LD_GPIO); dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); dir &= ~(1 << offset); superio_outb(sio->addr, gpio_dir(bank->regbase), dir); superio_exit(sio->addr); return 0; }
static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { int err; struct f7188x_gpio_bank *bank = gpiochip_get_data(chip); struct f7188x_sio *sio = bank->data->sio; u8 data_out; err = superio_enter(sio->addr); if (err) return; superio_select(sio->addr, SIO_LD_GPIO); data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase)); if (value) data_out |= (1 << offset); else data_out &= ~(1 << offset); superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out); superio_exit(sio->addr); }
static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits, u32 func_slct) { u32 config, new_config; mutex_lock(&pc8736x_gpio_config_lock); device_select(SIO_GPIO_UNIT); select_pin(index); /* read current config value */ config = superio_inb(func_slct); /* set new config */ new_config = (config & mask) | bits; superio_outb(func_slct, new_config); mutex_unlock(&pc8736x_gpio_config_lock); return config; }
static void qnap_timer(unsigned long data) { int tmp; unsigned long flags; struct input_dev *qnap_input = (struct input_dev *) data; spin_lock_irqsave(&spinlock, flags); superio_enter(); superio_select(SIO_GPIO_LDN); tmp = inb(gpio_base_address); input_report_key(qnap_input, KEY_ARCHIVE, (tmp & 0x40) >> 6 ); /* USB Copy Button */ input_report_key(qnap_input, KEY_RESTART, (tmp & 0x80) >> 7 ); /* RESET Button */ input_sync(qnap_input); superio_outb(GPIO_SMI_STATUS_REG, tmp | 0xc0); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); }
static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) { int ret; unsigned char t; ret = superio_enter(); if (ret) return ret; superio_select(W83627HF_LD_WDT); /* set CR30 bit 0 to activate GPIO2 */ t = superio_inb(0x30); if (!(t & 0x01)) superio_outb(0x30, t | 0x01); switch (chip) { case w83627hf: case w83627s: t = superio_inb(0x2B) & ~0x10; superio_outb(0x2B, t); /* set GPIO24 to WDT0 */ break; case w83697hf: /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ t = superio_inb(0x29) & ~0x60; t |= 0x20; superio_outb(0x29, t); break; case w83697ug: /* Set pin 118 to WDTO# mode */ t = superio_inb(0x2b) & ~0x04; superio_outb(0x2b, t); break; case w83627thf: t = (superio_inb(0x2B) & ~0x08) | 0x04; superio_outb(0x2B, t); /* set GPIO3 to WDT0 */ break; case w83627dhg: case w83627dhg_p: t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */ superio_outb(0x2D, t); /* set GPIO5 to WDT0 */ t = superio_inb(cr_wdt_control); t |= 0x02; /* enable the WDTO# output low pulse * to the KBRST# pin */ superio_outb(cr_wdt_control, t); break; case w83637hf: break; case w83687thf: t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */ superio_outb(0x2C, t); break; case w83627ehf: case w83627uhg: case w83667hg: case w83667hg_b: case nct6775: case nct6776: case nct6779: /* * These chips have a fixed WDTO# output pin (W83627UHG), * or support more than one WDTO# output pin. * Don't touch its configuration, and hope the BIOS * does the right thing. */ t = superio_inb(cr_wdt_control); t |= 0x02; /* enable the WDTO# output low pulse * to the KBRST# pin */ superio_outb(cr_wdt_control, t); break; default: break; } t = superio_inb(cr_wdt_timeout); if (t != 0) { pr_info("Watchdog already running. Resetting timeout to %d sec\n", wdog->timeout); superio_outb(cr_wdt_timeout, wdog->timeout); } /* set second mode & disable keyboard turning off watchdog */ t = superio_inb(cr_wdt_control) & ~0x0C; superio_outb(cr_wdt_control, t); /* reset trigger, disable keyboard & mouse turning off watchdog */ t = superio_inb(0xF7) & ~0xD0; superio_outb(0xF7, t); superio_exit(); return 0; }
static void device_select(unsigned devldn) { superio_outb(SIO_UNIT_SEL, devldn); selected_device = devldn; }
static void superio_select(int ld) { superio_outb(NCT_LD_SELECT_REG, ld); }
static int __init pc87427_device_add(unsigned short address) { struct resource res = { .start = address, .end = address + REGION_LENGTH - 1, .name = logdev_str[0], .flags = IORESOURCE_IO, }; int err; err = acpi_check_resource_conflict(&res); if (err) goto exit; pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; printk(KERN_ERR DRVNAME ": Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { printk(KERN_ERR DRVNAME ": Device resource addition failed " "(%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", err); goto exit_device_put; } return 0; exit_device_put: platform_device_put(pdev); exit: return err; } static int __init pc87427_find(int sioaddr, unsigned short *address) { u16 val; int i, err = 0; /* Identify device */ val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID); if (val != 0xf2) { /* PC87427 */ err = -ENODEV; goto exit; } for (i = 0; i < 2; i++) { address[i] = 0; /* Select logical device */ superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]); val = superio_inb(sioaddr, SIOREG_ACT); if (!(val & 0x01)) { printk(KERN_INFO DRVNAME ": Logical device 0x%02x " "not activated\n", logdev[i]); continue; } val = superio_inb(sioaddr, SIOREG_MAP); if (val & 0x01) { printk(KERN_WARNING DRVNAME ": Logical device 0x%02x " "is memory-mapped, can't use\n", logdev[i]); continue; } val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8) | superio_inb(sioaddr, SIOREG_IOBASE + 1); if (!val) { printk(KERN_INFO DRVNAME ": I/O base address not set " "for logical device 0x%02x\n", logdev[i]); continue; } address[i] = val; } exit: superio_exit(sioaddr); return err; }
static void superio_select(int ld) { superio_outb(0x07, ld); }