112262befSBruno Randolf /* 212262befSBruno Randolf * GPIO driver for the SMSC SCH311x Super-I/O chips 312262befSBruno Randolf * 412262befSBruno Randolf * Copyright (C) 2013 Bruno Randolf <br1@einfach.org> 512262befSBruno Randolf * 612262befSBruno Randolf * SuperIO functions and chip detection: 712262befSBruno Randolf * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>. 812262befSBruno Randolf * 912262befSBruno Randolf * This program is free software; you can redistribute it and/or modify 1012262befSBruno Randolf * it under the terms of the GNU General Public License as published by 1112262befSBruno Randolf * the Free Software Foundation; either version 2 of the License, or 1212262befSBruno Randolf * (at your option) any later version. 1312262befSBruno Randolf */ 1412262befSBruno Randolf 1513441457SWilliam Breathitt Gray #include <linux/ioport.h> 1612262befSBruno Randolf #include <linux/module.h> 1712262befSBruno Randolf #include <linux/kernel.h> 1812262befSBruno Randolf #include <linux/init.h> 1912262befSBruno Randolf #include <linux/platform_device.h> 2030467c19SLinus Walleij #include <linux/gpio/driver.h> 2112262befSBruno Randolf #include <linux/bitops.h> 22523639e6SLinus Walleij #include <linux/io.h> 2312262befSBruno Randolf 2412262befSBruno Randolf #define DRV_NAME "gpio-sch311x" 2512262befSBruno Randolf 264a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_DIR BIT(0) 274a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_INVERT BIT(1) 284a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_OPEN_DRAIN BIT(7) 2912262befSBruno Randolf 3012262befSBruno Randolf #define SIO_CONFIG_KEY_ENTER 0x55 3112262befSBruno Randolf #define SIO_CONFIG_KEY_EXIT 0xaa 3212262befSBruno Randolf 3312262befSBruno Randolf #define GP1 0x4b 3412262befSBruno Randolf 3512262befSBruno Randolf static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e }; 3612262befSBruno Randolf 3712262befSBruno Randolf static struct platform_device *sch311x_gpio_pdev; 3812262befSBruno Randolf 3912262befSBruno Randolf struct sch311x_pdev_data { /* platform device data */ 4012262befSBruno Randolf unsigned short runtime_reg; /* runtime register base address */ 4112262befSBruno Randolf }; 4212262befSBruno Randolf 4312262befSBruno Randolf struct sch311x_gpio_block { /* one GPIO block runtime data */ 4412262befSBruno Randolf struct gpio_chip chip; 4512262befSBruno Randolf unsigned short data_reg; /* from definition below */ 4612262befSBruno Randolf unsigned short *config_regs; /* pointer to definition below */ 4712262befSBruno Randolf unsigned short runtime_reg; /* runtime register */ 4812262befSBruno Randolf spinlock_t lock; /* lock for this GPIO block */ 4912262befSBruno Randolf }; 5012262befSBruno Randolf 5112262befSBruno Randolf struct sch311x_gpio_priv { /* driver private data */ 5212262befSBruno Randolf struct sch311x_gpio_block blocks[6]; 5312262befSBruno Randolf }; 5412262befSBruno Randolf 5512262befSBruno Randolf struct sch311x_gpio_block_def { /* register address definitions */ 5612262befSBruno Randolf unsigned short data_reg; 5712262befSBruno Randolf unsigned short config_regs[8]; 5812262befSBruno Randolf unsigned short base; 5912262befSBruno Randolf }; 6012262befSBruno Randolf 6112262befSBruno Randolf /* Note: some GPIOs are not available, these are marked with 0x00 */ 6212262befSBruno Randolf 6312262befSBruno Randolf static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = { 6412262befSBruno Randolf { 6512262befSBruno Randolf .data_reg = 0x4b, /* GP1 */ 6612262befSBruno Randolf .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b}, 6712262befSBruno Randolf .base = 10, 6812262befSBruno Randolf }, 6912262befSBruno Randolf { 7012262befSBruno Randolf .data_reg = 0x4c, /* GP2 */ 7112262befSBruno Randolf .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32}, 7212262befSBruno Randolf .base = 20, 7312262befSBruno Randolf }, 7412262befSBruno Randolf { 7512262befSBruno Randolf .data_reg = 0x4d, /* GP3 */ 7612262befSBruno Randolf .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a}, 7712262befSBruno Randolf .base = 30, 7812262befSBruno Randolf }, 7912262befSBruno Randolf { 8012262befSBruno Randolf .data_reg = 0x4e, /* GP4 */ 8112262befSBruno Randolf .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73}, 8212262befSBruno Randolf .base = 40, 8312262befSBruno Randolf }, 8412262befSBruno Randolf { 8512262befSBruno Randolf .data_reg = 0x4f, /* GP5 */ 8612262befSBruno Randolf .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, 8712262befSBruno Randolf .base = 50, 8812262befSBruno Randolf }, 8912262befSBruno Randolf { 9012262befSBruno Randolf .data_reg = 0x50, /* GP6 */ 9112262befSBruno Randolf .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59}, 9212262befSBruno Randolf .base = 60, 9312262befSBruno Randolf }, 9412262befSBruno Randolf }; 9512262befSBruno Randolf 9612262befSBruno Randolf /* 9712262befSBruno Randolf * Super-IO functions 9812262befSBruno Randolf */ 9912262befSBruno Randolf 10012262befSBruno Randolf static inline int sch311x_sio_enter(int sio_config_port) 10112262befSBruno Randolf { 10212262befSBruno Randolf /* Don't step on other drivers' I/O space by accident. */ 10312262befSBruno Randolf if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) { 10412262befSBruno Randolf pr_err(DRV_NAME "I/O address 0x%04x already in use\n", 10512262befSBruno Randolf sio_config_port); 10612262befSBruno Randolf return -EBUSY; 10712262befSBruno Randolf } 10812262befSBruno Randolf 10912262befSBruno Randolf outb(SIO_CONFIG_KEY_ENTER, sio_config_port); 11012262befSBruno Randolf return 0; 11112262befSBruno Randolf } 11212262befSBruno Randolf 11312262befSBruno Randolf static inline void sch311x_sio_exit(int sio_config_port) 11412262befSBruno Randolf { 11512262befSBruno Randolf outb(SIO_CONFIG_KEY_EXIT, sio_config_port); 11612262befSBruno Randolf release_region(sio_config_port, 2); 11712262befSBruno Randolf } 11812262befSBruno Randolf 11912262befSBruno Randolf static inline int sch311x_sio_inb(int sio_config_port, int reg) 12012262befSBruno Randolf { 12112262befSBruno Randolf outb(reg, sio_config_port); 12212262befSBruno Randolf return inb(sio_config_port + 1); 12312262befSBruno Randolf } 12412262befSBruno Randolf 12512262befSBruno Randolf static inline void sch311x_sio_outb(int sio_config_port, int reg, int val) 12612262befSBruno Randolf { 12712262befSBruno Randolf outb(reg, sio_config_port); 12812262befSBruno Randolf outb(val, sio_config_port + 1); 12912262befSBruno Randolf } 13012262befSBruno Randolf 13112262befSBruno Randolf 13212262befSBruno Randolf /* 13312262befSBruno Randolf * GPIO functions 13412262befSBruno Randolf */ 13512262befSBruno Randolf 13612262befSBruno Randolf static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset) 13712262befSBruno Randolf { 1388ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 13912262befSBruno Randolf 14012262befSBruno Randolf if (block->config_regs[offset] == 0) /* GPIO is not available */ 14112262befSBruno Randolf return -ENODEV; 14212262befSBruno Randolf 14312262befSBruno Randolf if (!request_region(block->runtime_reg + block->config_regs[offset], 14412262befSBruno Randolf 1, DRV_NAME)) { 14558383c78SLinus Walleij dev_err(chip->parent, "Failed to request region 0x%04x.\n", 14612262befSBruno Randolf block->runtime_reg + block->config_regs[offset]); 14712262befSBruno Randolf return -EBUSY; 14812262befSBruno Randolf } 14912262befSBruno Randolf return 0; 15012262befSBruno Randolf } 15112262befSBruno Randolf 15212262befSBruno Randolf static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset) 15312262befSBruno Randolf { 1548ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 15512262befSBruno Randolf 15612262befSBruno Randolf if (block->config_regs[offset] == 0) /* GPIO is not available */ 15712262befSBruno Randolf return; 15812262befSBruno Randolf 15912262befSBruno Randolf release_region(block->runtime_reg + block->config_regs[offset], 1); 16012262befSBruno Randolf } 16112262befSBruno Randolf 16212262befSBruno Randolf static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) 16312262befSBruno Randolf { 1648ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 165*eb452a84SLinus Walleij u8 data; 16612262befSBruno Randolf 16712262befSBruno Randolf spin_lock(&block->lock); 16812262befSBruno Randolf data = inb(block->runtime_reg + block->data_reg); 16912262befSBruno Randolf spin_unlock(&block->lock); 17012262befSBruno Randolf 17112262befSBruno Randolf return !!(data & BIT(offset)); 17212262befSBruno Randolf } 17312262befSBruno Randolf 17412262befSBruno Randolf static void __sch311x_gpio_set(struct sch311x_gpio_block *block, 17512262befSBruno Randolf unsigned offset, int value) 17612262befSBruno Randolf { 177*eb452a84SLinus Walleij u8 data = inb(block->runtime_reg + block->data_reg); 17812262befSBruno Randolf if (value) 17912262befSBruno Randolf data |= BIT(offset); 18012262befSBruno Randolf else 18112262befSBruno Randolf data &= ~BIT(offset); 18212262befSBruno Randolf outb(data, block->runtime_reg + block->data_reg); 18312262befSBruno Randolf } 18412262befSBruno Randolf 18512262befSBruno Randolf static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, 18612262befSBruno Randolf int value) 18712262befSBruno Randolf { 1888ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 18912262befSBruno Randolf 19012262befSBruno Randolf spin_lock(&block->lock); 19112262befSBruno Randolf __sch311x_gpio_set(block, offset, value); 19212262befSBruno Randolf spin_unlock(&block->lock); 19312262befSBruno Randolf } 19412262befSBruno Randolf 19512262befSBruno Randolf static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) 19612262befSBruno Randolf { 1978ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 198*eb452a84SLinus Walleij u8 data; 19912262befSBruno Randolf 20012262befSBruno Randolf spin_lock(&block->lock); 2014a2398d7SLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]); 2024a2398d7SLinus Walleij data |= SCH311X_GPIO_CONF_DIR; 2034a2398d7SLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]); 20412262befSBruno Randolf spin_unlock(&block->lock); 20512262befSBruno Randolf 20612262befSBruno Randolf return 0; 20712262befSBruno Randolf } 20812262befSBruno Randolf 20912262befSBruno Randolf static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, 21012262befSBruno Randolf int value) 21112262befSBruno Randolf { 2128ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 213*eb452a84SLinus Walleij u8 data; 21412262befSBruno Randolf 21512262befSBruno Randolf spin_lock(&block->lock); 21612262befSBruno Randolf 2174a2398d7SLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]); 2184a2398d7SLinus Walleij data &= ~SCH311X_GPIO_CONF_DIR; 2194a2398d7SLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]); 22012262befSBruno Randolf __sch311x_gpio_set(block, offset, value); 22112262befSBruno Randolf 22212262befSBruno Randolf spin_unlock(&block->lock); 22312262befSBruno Randolf return 0; 22412262befSBruno Randolf } 22512262befSBruno Randolf 226f9e03b0eSLinus Walleij static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 227f9e03b0eSLinus Walleij { 228f9e03b0eSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 229*eb452a84SLinus Walleij u8 data; 230f9e03b0eSLinus Walleij 231f9e03b0eSLinus Walleij spin_lock(&block->lock); 232f9e03b0eSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]); 233f9e03b0eSLinus Walleij spin_unlock(&block->lock); 234f9e03b0eSLinus Walleij 2354a2398d7SLinus Walleij return !!(data & SCH311X_GPIO_CONF_DIR); 236f9e03b0eSLinus Walleij } 237f9e03b0eSLinus Walleij 2384455a82aSLinus Walleij static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, 2394455a82aSLinus Walleij unsigned long config) 2404455a82aSLinus Walleij { 2414455a82aSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip); 2424455a82aSLinus Walleij enum pin_config_param param = pinconf_to_config_param(config); 243*eb452a84SLinus Walleij u8 data; 2444455a82aSLinus Walleij 2454455a82aSLinus Walleij switch (param) { 2464455a82aSLinus Walleij case PIN_CONFIG_DRIVE_OPEN_DRAIN: 2474455a82aSLinus Walleij spin_lock(&block->lock); 2484455a82aSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]); 2494455a82aSLinus Walleij data |= SCH311X_GPIO_CONF_OPEN_DRAIN; 2504455a82aSLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]); 2514455a82aSLinus Walleij spin_unlock(&block->lock); 2524455a82aSLinus Walleij return 0; 2534455a82aSLinus Walleij case PIN_CONFIG_DRIVE_PUSH_PULL: 2544455a82aSLinus Walleij spin_lock(&block->lock); 2554455a82aSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]); 2564455a82aSLinus Walleij data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN; 2574455a82aSLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]); 2584455a82aSLinus Walleij spin_unlock(&block->lock); 2594455a82aSLinus Walleij return 0; 2604455a82aSLinus Walleij default: 2614455a82aSLinus Walleij break; 2624455a82aSLinus Walleij } 2634455a82aSLinus Walleij return -ENOTSUPP; 2644455a82aSLinus Walleij } 2654455a82aSLinus Walleij 26612262befSBruno Randolf static int sch311x_gpio_probe(struct platform_device *pdev) 26712262befSBruno Randolf { 268ab128afcSNizam Haider struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev); 26912262befSBruno Randolf struct sch311x_gpio_priv *priv; 27012262befSBruno Randolf struct sch311x_gpio_block *block; 27112262befSBruno Randolf int err, i; 27212262befSBruno Randolf 27312262befSBruno Randolf /* we can register all GPIO data registers at once */ 27413441457SWilliam Breathitt Gray if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6, 27513441457SWilliam Breathitt Gray DRV_NAME)) { 27612262befSBruno Randolf dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n", 27712262befSBruno Randolf pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5); 27812262befSBruno Randolf return -EBUSY; 27912262befSBruno Randolf } 28012262befSBruno Randolf 28112262befSBruno Randolf priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 28212262befSBruno Randolf if (!priv) 28312262befSBruno Randolf return -ENOMEM; 28412262befSBruno Randolf 28512262befSBruno Randolf platform_set_drvdata(pdev, priv); 28612262befSBruno Randolf 28712262befSBruno Randolf for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { 28812262befSBruno Randolf block = &priv->blocks[i]; 28912262befSBruno Randolf 29012262befSBruno Randolf spin_lock_init(&block->lock); 29112262befSBruno Randolf 29212262befSBruno Randolf block->chip.label = DRV_NAME; 29312262befSBruno Randolf block->chip.owner = THIS_MODULE; 29412262befSBruno Randolf block->chip.request = sch311x_gpio_request; 29512262befSBruno Randolf block->chip.free = sch311x_gpio_free; 29612262befSBruno Randolf block->chip.direction_input = sch311x_gpio_direction_in; 29712262befSBruno Randolf block->chip.direction_output = sch311x_gpio_direction_out; 298f9e03b0eSLinus Walleij block->chip.get_direction = sch311x_gpio_get_direction; 2994455a82aSLinus Walleij block->chip.set_config = sch311x_gpio_set_config; 30012262befSBruno Randolf block->chip.get = sch311x_gpio_get; 30112262befSBruno Randolf block->chip.set = sch311x_gpio_set; 30212262befSBruno Randolf block->chip.ngpio = 8; 30358383c78SLinus Walleij block->chip.parent = &pdev->dev; 30412262befSBruno Randolf block->chip.base = sch311x_gpio_blocks[i].base; 30512262befSBruno Randolf block->config_regs = sch311x_gpio_blocks[i].config_regs; 30612262befSBruno Randolf block->data_reg = sch311x_gpio_blocks[i].data_reg; 30712262befSBruno Randolf block->runtime_reg = pdata->runtime_reg; 30812262befSBruno Randolf 3098ca7f1faSLinus Walleij err = gpiochip_add_data(&block->chip, block); 31012262befSBruno Randolf if (err < 0) { 31112262befSBruno Randolf dev_err(&pdev->dev, 31212262befSBruno Randolf "Could not register gpiochip, %d\n", err); 31312262befSBruno Randolf goto exit_err; 31412262befSBruno Randolf } 31512262befSBruno Randolf dev_info(&pdev->dev, 31612262befSBruno Randolf "SMSC SCH311x GPIO block %d registered.\n", i); 31712262befSBruno Randolf } 31812262befSBruno Randolf 31912262befSBruno Randolf return 0; 32012262befSBruno Randolf 32112262befSBruno Randolf exit_err: 32212262befSBruno Randolf /* release already registered chips */ 32312262befSBruno Randolf for (--i; i >= 0; i--) 32412262befSBruno Randolf gpiochip_remove(&priv->blocks[i].chip); 32512262befSBruno Randolf return err; 32612262befSBruno Randolf } 32712262befSBruno Randolf 32812262befSBruno Randolf static int sch311x_gpio_remove(struct platform_device *pdev) 32912262befSBruno Randolf { 33012262befSBruno Randolf struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev); 3319f5132aeSabdoulaye berthe int i; 33212262befSBruno Randolf 33312262befSBruno Randolf for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { 3349f5132aeSabdoulaye berthe gpiochip_remove(&priv->blocks[i].chip); 33512262befSBruno Randolf dev_info(&pdev->dev, 33612262befSBruno Randolf "SMSC SCH311x GPIO block %d unregistered.\n", i); 33712262befSBruno Randolf } 33812262befSBruno Randolf return 0; 33912262befSBruno Randolf } 34012262befSBruno Randolf 34112262befSBruno Randolf static struct platform_driver sch311x_gpio_driver = { 34212262befSBruno Randolf .driver.name = DRV_NAME, 34312262befSBruno Randolf .probe = sch311x_gpio_probe, 34412262befSBruno Randolf .remove = sch311x_gpio_remove, 34512262befSBruno Randolf }; 34612262befSBruno Randolf 34712262befSBruno Randolf 34812262befSBruno Randolf /* 34912262befSBruno Randolf * Init & exit routines 35012262befSBruno Randolf */ 35112262befSBruno Randolf 35212262befSBruno Randolf static int __init sch311x_detect(int sio_config_port, unsigned short *addr) 35312262befSBruno Randolf { 35412262befSBruno Randolf int err = 0, reg; 35512262befSBruno Randolf unsigned short base_addr; 356*eb452a84SLinus Walleij u8 dev_id; 35712262befSBruno Randolf 35812262befSBruno Randolf err = sch311x_sio_enter(sio_config_port); 35912262befSBruno Randolf if (err) 36012262befSBruno Randolf return err; 36112262befSBruno Randolf 3627e9fcc9dSAxel Lin /* Check device ID. */ 36312262befSBruno Randolf reg = sch311x_sio_inb(sio_config_port, 0x20); 3647e9fcc9dSAxel Lin switch (reg) { 3657e9fcc9dSAxel Lin case 0x7c: /* SCH3112 */ 3667e9fcc9dSAxel Lin dev_id = 2; 3677e9fcc9dSAxel Lin break; 3687e9fcc9dSAxel Lin case 0x7d: /* SCH3114 */ 3697e9fcc9dSAxel Lin dev_id = 4; 3707e9fcc9dSAxel Lin break; 3717e9fcc9dSAxel Lin case 0x7f: /* SCH3116 */ 3727e9fcc9dSAxel Lin dev_id = 6; 3737e9fcc9dSAxel Lin break; 3747e9fcc9dSAxel Lin default: 37512262befSBruno Randolf err = -ENODEV; 37612262befSBruno Randolf goto exit; 37712262befSBruno Randolf } 37812262befSBruno Randolf 37912262befSBruno Randolf /* Select logical device A (runtime registers) */ 38012262befSBruno Randolf sch311x_sio_outb(sio_config_port, 0x07, 0x0a); 38112262befSBruno Randolf 38212262befSBruno Randolf /* Check if Logical Device Register is currently active */ 38312262befSBruno Randolf if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0) 38412262befSBruno Randolf pr_info("Seems that LDN 0x0a is not active...\n"); 38512262befSBruno Randolf 38612262befSBruno Randolf /* Get the base address of the runtime registers */ 38712262befSBruno Randolf base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) | 38812262befSBruno Randolf sch311x_sio_inb(sio_config_port, 0x61); 38912262befSBruno Randolf if (!base_addr) { 39012262befSBruno Randolf pr_err("Base address not set\n"); 39112262befSBruno Randolf err = -ENODEV; 39212262befSBruno Randolf goto exit; 39312262befSBruno Randolf } 39412262befSBruno Randolf *addr = base_addr; 39512262befSBruno Randolf 39612262befSBruno Randolf pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr); 39712262befSBruno Randolf 39812262befSBruno Randolf exit: 39912262befSBruno Randolf sch311x_sio_exit(sio_config_port); 40012262befSBruno Randolf return err; 40112262befSBruno Randolf } 40212262befSBruno Randolf 40312262befSBruno Randolf static int __init sch311x_gpio_pdev_add(const unsigned short addr) 40412262befSBruno Randolf { 40512262befSBruno Randolf struct sch311x_pdev_data pdata; 40612262befSBruno Randolf int err; 40712262befSBruno Randolf 40812262befSBruno Randolf pdata.runtime_reg = addr; 40912262befSBruno Randolf 41012262befSBruno Randolf sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1); 41112262befSBruno Randolf if (!sch311x_gpio_pdev) 41212262befSBruno Randolf return -ENOMEM; 41312262befSBruno Randolf 41412262befSBruno Randolf err = platform_device_add_data(sch311x_gpio_pdev, 41512262befSBruno Randolf &pdata, sizeof(pdata)); 41612262befSBruno Randolf if (err) { 41712262befSBruno Randolf pr_err(DRV_NAME "Platform data allocation failed\n"); 41812262befSBruno Randolf goto err; 41912262befSBruno Randolf } 42012262befSBruno Randolf 42112262befSBruno Randolf err = platform_device_add(sch311x_gpio_pdev); 42212262befSBruno Randolf if (err) { 42312262befSBruno Randolf pr_err(DRV_NAME "Device addition failed\n"); 42412262befSBruno Randolf goto err; 42512262befSBruno Randolf } 42612262befSBruno Randolf return 0; 42712262befSBruno Randolf 42812262befSBruno Randolf err: 42912262befSBruno Randolf platform_device_put(sch311x_gpio_pdev); 43012262befSBruno Randolf return err; 43112262befSBruno Randolf } 43212262befSBruno Randolf 43312262befSBruno Randolf static int __init sch311x_gpio_init(void) 43412262befSBruno Randolf { 43512262befSBruno Randolf int err, i; 43612262befSBruno Randolf unsigned short addr = 0; 43712262befSBruno Randolf 43812262befSBruno Randolf for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++) 43912262befSBruno Randolf if (sch311x_detect(sch311x_ioports[i], &addr) == 0) 44012262befSBruno Randolf break; 44112262befSBruno Randolf 44212262befSBruno Randolf if (!addr) 44312262befSBruno Randolf return -ENODEV; 44412262befSBruno Randolf 44512262befSBruno Randolf err = platform_driver_register(&sch311x_gpio_driver); 44612262befSBruno Randolf if (err) 44712262befSBruno Randolf return err; 44812262befSBruno Randolf 44912262befSBruno Randolf err = sch311x_gpio_pdev_add(addr); 45012262befSBruno Randolf if (err) 45112262befSBruno Randolf goto unreg_platform_driver; 45212262befSBruno Randolf 45312262befSBruno Randolf return 0; 45412262befSBruno Randolf 45512262befSBruno Randolf unreg_platform_driver: 45612262befSBruno Randolf platform_driver_unregister(&sch311x_gpio_driver); 45712262befSBruno Randolf return err; 45812262befSBruno Randolf } 45912262befSBruno Randolf 46012262befSBruno Randolf static void __exit sch311x_gpio_exit(void) 46112262befSBruno Randolf { 46212262befSBruno Randolf platform_device_unregister(sch311x_gpio_pdev); 46312262befSBruno Randolf platform_driver_unregister(&sch311x_gpio_driver); 46412262befSBruno Randolf } 46512262befSBruno Randolf 46612262befSBruno Randolf module_init(sch311x_gpio_init); 46712262befSBruno Randolf module_exit(sch311x_gpio_exit); 46812262befSBruno Randolf 46912262befSBruno Randolf MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>"); 47012262befSBruno Randolf MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver"); 47112262befSBruno Randolf MODULE_LICENSE("GPL"); 47212262befSBruno Randolf MODULE_ALIAS("platform:gpio-sch311x"); 473