^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * GPIO driver for the SMSC SCH311x Super-I/O chips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2013 Bruno Randolf <br1@einfach.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * SuperIO functions and chip detection:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/gpio/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define DRV_NAME "gpio-sch311x"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define SCH311X_GPIO_CONF_DIR BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define SCH311X_GPIO_CONF_INVERT BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define SCH311X_GPIO_CONF_OPEN_DRAIN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define SIO_CONFIG_KEY_ENTER 0x55
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define SIO_CONFIG_KEY_EXIT 0xaa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define GP1 0x4b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static struct platform_device *sch311x_gpio_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct sch311x_pdev_data { /* platform device data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned short runtime_reg; /* runtime register base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct sch311x_gpio_block { /* one GPIO block runtime data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct gpio_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned short data_reg; /* from definition below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned short *config_regs; /* pointer to definition below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned short runtime_reg; /* runtime register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) spinlock_t lock; /* lock for this GPIO block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct sch311x_gpio_priv { /* driver private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct sch311x_gpio_block blocks[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct sch311x_gpio_block_def { /* register address definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned short data_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned short config_regs[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned short base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Note: some GPIOs are not available, these are marked with 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .data_reg = 0x4b, /* GP1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .base = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .data_reg = 0x4c, /* GP2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .base = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .data_reg = 0x4d, /* GP3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .base = 30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .data_reg = 0x4e, /* GP4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .base = 40,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .data_reg = 0x4f, /* GP5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .base = 50,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .data_reg = 0x50, /* GP6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .base = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * Super-IO functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static inline int sch311x_sio_enter(int sio_config_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* Don't step on other drivers' I/O space by accident. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static inline void sch311x_sio_exit(int sio_config_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) release_region(sio_config_port, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static inline int sch311x_sio_inb(int sio_config_port, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) outb(reg, sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return inb(sio_config_port + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) outb(reg, sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) outb(val, sio_config_port + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * GPIO functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (block->config_regs[offset] == 0) /* GPIO is not available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (!request_region(block->runtime_reg + block->config_regs[offset],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 1, DRV_NAME)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev_err(chip->parent, "Failed to request region 0x%04x.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (block->config_regs[offset] == 0) /* GPIO is not available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) release_region(block->runtime_reg + block->config_regs[offset], 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) data = inb(block->runtime_reg + block->data_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return !!(data & BIT(offset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned offset, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) u8 data = inb(block->runtime_reg + block->data_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) data |= BIT(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) data &= ~BIT(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) outb(data, block->runtime_reg + block->data_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) __sch311x_gpio_set(block, offset, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) data = inb(block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) data |= SCH311X_GPIO_CONF_DIR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) outb(data, block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) data = inb(block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) data &= ~SCH311X_GPIO_CONF_DIR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) outb(data, block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) __sch311x_gpio_set(block, offset, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) data = inb(block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (data & SCH311X_GPIO_CONF_DIR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return GPIO_LINE_DIRECTION_IN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return GPIO_LINE_DIRECTION_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) unsigned long config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct sch311x_gpio_block *block = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) enum pin_config_param param = pinconf_to_config_param(config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) switch (param) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) case PIN_CONFIG_DRIVE_OPEN_DRAIN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) data = inb(block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) data |= SCH311X_GPIO_CONF_OPEN_DRAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) outb(data, block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case PIN_CONFIG_DRIVE_PUSH_PULL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) spin_lock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) data = inb(block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) outb(data, block->runtime_reg + block->config_regs[offset]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) spin_unlock(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int sch311x_gpio_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct sch311x_gpio_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct sch311x_gpio_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* we can register all GPIO data registers at once */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) DRV_NAME)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) platform_set_drvdata(pdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) block = &priv->blocks[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) spin_lock_init(&block->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) block->chip.label = DRV_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) block->chip.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) block->chip.request = sch311x_gpio_request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) block->chip.free = sch311x_gpio_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) block->chip.direction_input = sch311x_gpio_direction_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) block->chip.direction_output = sch311x_gpio_direction_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) block->chip.get_direction = sch311x_gpio_get_direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) block->chip.set_config = sch311x_gpio_set_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) block->chip.get = sch311x_gpio_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) block->chip.set = sch311x_gpio_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) block->chip.ngpio = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) block->chip.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) block->chip.base = sch311x_gpio_blocks[i].base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) block->config_regs = sch311x_gpio_blocks[i].config_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) block->data_reg = sch311x_gpio_blocks[i].data_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) block->runtime_reg = pdata->runtime_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) err = gpiochip_add_data(&block->chip, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) "Could not register gpiochip, %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) goto exit_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) dev_info(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) "SMSC SCH311x GPIO block %d registered.\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) exit_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* release already registered chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) for (--i; i >= 0; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) gpiochip_remove(&priv->blocks[i].chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int sch311x_gpio_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) gpiochip_remove(&priv->blocks[i].chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) dev_info(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) "SMSC SCH311x GPIO block %d unregistered.\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static struct platform_driver sch311x_gpio_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .driver.name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .probe = sch311x_gpio_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .remove = sch311x_gpio_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * Init & exit routines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int err = 0, reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) unsigned short base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) u8 dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) err = sch311x_sio_enter(sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* Check device ID. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) reg = sch311x_sio_inb(sio_config_port, 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) case 0x7c: /* SCH3112 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) dev_id = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) case 0x7d: /* SCH3114 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) dev_id = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) case 0x7f: /* SCH3116 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) dev_id = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* Select logical device A (runtime registers) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /* Check if Logical Device Register is currently active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) pr_info("Seems that LDN 0x0a is not active...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) /* Get the base address of the runtime registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) sch311x_sio_inb(sio_config_port, 0x61);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (!base_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) pr_err("Base address not set\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) *addr = base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) sch311x_sio_exit(sio_config_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static int __init sch311x_gpio_pdev_add(const unsigned short addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct sch311x_pdev_data pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) pdata.runtime_reg = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!sch311x_gpio_pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) err = platform_device_add_data(sch311x_gpio_pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) &pdata, sizeof(pdata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) pr_err(DRV_NAME "Platform data allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) err = platform_device_add(sch311x_gpio_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pr_err(DRV_NAME "Device addition failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) platform_device_put(sch311x_gpio_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static int __init sch311x_gpio_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) unsigned short addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) err = platform_driver_register(&sch311x_gpio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) err = sch311x_gpio_pdev_add(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) goto unreg_platform_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) unreg_platform_driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) platform_driver_unregister(&sch311x_gpio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static void __exit sch311x_gpio_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) platform_device_unregister(sch311x_gpio_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) platform_driver_unregister(&sch311x_gpio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) module_init(sch311x_gpio_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) module_exit(sch311x_gpio_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) MODULE_ALIAS("platform:gpio-sch311x");