12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
212262befSBruno Randolf /*
312262befSBruno Randolf * GPIO driver for the SMSC SCH311x Super-I/O chips
412262befSBruno Randolf *
512262befSBruno Randolf * Copyright (C) 2013 Bruno Randolf <br1@einfach.org>
612262befSBruno Randolf *
712262befSBruno Randolf * SuperIO functions and chip detection:
812262befSBruno Randolf * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
912262befSBruno Randolf */
1012262befSBruno Randolf
1113441457SWilliam Breathitt Gray #include <linux/ioport.h>
1212262befSBruno Randolf #include <linux/module.h>
1312262befSBruno Randolf #include <linux/kernel.h>
1412262befSBruno Randolf #include <linux/init.h>
1512262befSBruno Randolf #include <linux/platform_device.h>
1630467c19SLinus Walleij #include <linux/gpio/driver.h>
1712262befSBruno Randolf #include <linux/bitops.h>
18523639e6SLinus Walleij #include <linux/io.h>
1912262befSBruno Randolf
2012262befSBruno Randolf #define DRV_NAME "gpio-sch311x"
2112262befSBruno Randolf
224a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_DIR BIT(0)
234a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_INVERT BIT(1)
244a2398d7SLinus Walleij #define SCH311X_GPIO_CONF_OPEN_DRAIN BIT(7)
2512262befSBruno Randolf
2612262befSBruno Randolf #define SIO_CONFIG_KEY_ENTER 0x55
2712262befSBruno Randolf #define SIO_CONFIG_KEY_EXIT 0xaa
2812262befSBruno Randolf
2912262befSBruno Randolf #define GP1 0x4b
3012262befSBruno Randolf
3112262befSBruno Randolf static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e };
3212262befSBruno Randolf
3312262befSBruno Randolf static struct platform_device *sch311x_gpio_pdev;
3412262befSBruno Randolf
3512262befSBruno Randolf struct sch311x_pdev_data { /* platform device data */
3612262befSBruno Randolf unsigned short runtime_reg; /* runtime register base address */
3712262befSBruno Randolf };
3812262befSBruno Randolf
3912262befSBruno Randolf struct sch311x_gpio_block { /* one GPIO block runtime data */
4012262befSBruno Randolf struct gpio_chip chip;
4112262befSBruno Randolf unsigned short data_reg; /* from definition below */
4212262befSBruno Randolf unsigned short *config_regs; /* pointer to definition below */
4312262befSBruno Randolf unsigned short runtime_reg; /* runtime register */
4412262befSBruno Randolf spinlock_t lock; /* lock for this GPIO block */
4512262befSBruno Randolf };
4612262befSBruno Randolf
4712262befSBruno Randolf struct sch311x_gpio_priv { /* driver private data */
4812262befSBruno Randolf struct sch311x_gpio_block blocks[6];
4912262befSBruno Randolf };
5012262befSBruno Randolf
5112262befSBruno Randolf struct sch311x_gpio_block_def { /* register address definitions */
5212262befSBruno Randolf unsigned short data_reg;
5312262befSBruno Randolf unsigned short config_regs[8];
5412262befSBruno Randolf unsigned short base;
5512262befSBruno Randolf };
5612262befSBruno Randolf
5712262befSBruno Randolf /* Note: some GPIOs are not available, these are marked with 0x00 */
5812262befSBruno Randolf
5912262befSBruno Randolf static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
6012262befSBruno Randolf {
6112262befSBruno Randolf .data_reg = 0x4b, /* GP1 */
6212262befSBruno Randolf .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b},
6312262befSBruno Randolf .base = 10,
6412262befSBruno Randolf },
6512262befSBruno Randolf {
6612262befSBruno Randolf .data_reg = 0x4c, /* GP2 */
6712262befSBruno Randolf .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32},
6812262befSBruno Randolf .base = 20,
6912262befSBruno Randolf },
7012262befSBruno Randolf {
7112262befSBruno Randolf .data_reg = 0x4d, /* GP3 */
7212262befSBruno Randolf .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a},
7312262befSBruno Randolf .base = 30,
7412262befSBruno Randolf },
7512262befSBruno Randolf {
7612262befSBruno Randolf .data_reg = 0x4e, /* GP4 */
7712262befSBruno Randolf .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73},
7812262befSBruno Randolf .base = 40,
7912262befSBruno Randolf },
8012262befSBruno Randolf {
8112262befSBruno Randolf .data_reg = 0x4f, /* GP5 */
8212262befSBruno Randolf .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46},
8312262befSBruno Randolf .base = 50,
8412262befSBruno Randolf },
8512262befSBruno Randolf {
8612262befSBruno Randolf .data_reg = 0x50, /* GP6 */
8712262befSBruno Randolf .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59},
8812262befSBruno Randolf .base = 60,
8912262befSBruno Randolf },
9012262befSBruno Randolf };
9112262befSBruno Randolf
9212262befSBruno Randolf /*
9312262befSBruno Randolf * Super-IO functions
9412262befSBruno Randolf */
9512262befSBruno Randolf
sch311x_sio_enter(int sio_config_port)9612262befSBruno Randolf static inline int sch311x_sio_enter(int sio_config_port)
9712262befSBruno Randolf {
9812262befSBruno Randolf /* Don't step on other drivers' I/O space by accident. */
9912262befSBruno Randolf if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
10012262befSBruno Randolf pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
10112262befSBruno Randolf sio_config_port);
10212262befSBruno Randolf return -EBUSY;
10312262befSBruno Randolf }
10412262befSBruno Randolf
10512262befSBruno Randolf outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
10612262befSBruno Randolf return 0;
10712262befSBruno Randolf }
10812262befSBruno Randolf
sch311x_sio_exit(int sio_config_port)10912262befSBruno Randolf static inline void sch311x_sio_exit(int sio_config_port)
11012262befSBruno Randolf {
11112262befSBruno Randolf outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
11212262befSBruno Randolf release_region(sio_config_port, 2);
11312262befSBruno Randolf }
11412262befSBruno Randolf
sch311x_sio_inb(int sio_config_port,int reg)11512262befSBruno Randolf static inline int sch311x_sio_inb(int sio_config_port, int reg)
11612262befSBruno Randolf {
11712262befSBruno Randolf outb(reg, sio_config_port);
11812262befSBruno Randolf return inb(sio_config_port + 1);
11912262befSBruno Randolf }
12012262befSBruno Randolf
sch311x_sio_outb(int sio_config_port,int reg,int val)12112262befSBruno Randolf static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
12212262befSBruno Randolf {
12312262befSBruno Randolf outb(reg, sio_config_port);
12412262befSBruno Randolf outb(val, sio_config_port + 1);
12512262befSBruno Randolf }
12612262befSBruno Randolf
12712262befSBruno Randolf
12812262befSBruno Randolf /*
12912262befSBruno Randolf * GPIO functions
13012262befSBruno Randolf */
13112262befSBruno Randolf
sch311x_gpio_request(struct gpio_chip * chip,unsigned offset)13212262befSBruno Randolf static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
13312262befSBruno Randolf {
1348ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
13512262befSBruno Randolf
13612262befSBruno Randolf if (block->config_regs[offset] == 0) /* GPIO is not available */
13712262befSBruno Randolf return -ENODEV;
13812262befSBruno Randolf
13912262befSBruno Randolf if (!request_region(block->runtime_reg + block->config_regs[offset],
14012262befSBruno Randolf 1, DRV_NAME)) {
14158383c78SLinus Walleij dev_err(chip->parent, "Failed to request region 0x%04x.\n",
14212262befSBruno Randolf block->runtime_reg + block->config_regs[offset]);
14312262befSBruno Randolf return -EBUSY;
14412262befSBruno Randolf }
14512262befSBruno Randolf return 0;
14612262befSBruno Randolf }
14712262befSBruno Randolf
sch311x_gpio_free(struct gpio_chip * chip,unsigned offset)14812262befSBruno Randolf static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
14912262befSBruno Randolf {
1508ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
15112262befSBruno Randolf
15212262befSBruno Randolf if (block->config_regs[offset] == 0) /* GPIO is not available */
15312262befSBruno Randolf return;
15412262befSBruno Randolf
15512262befSBruno Randolf release_region(block->runtime_reg + block->config_regs[offset], 1);
15612262befSBruno Randolf }
15712262befSBruno Randolf
sch311x_gpio_get(struct gpio_chip * chip,unsigned offset)15812262befSBruno Randolf static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
15912262befSBruno Randolf {
1608ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
161eb452a84SLinus Walleij u8 data;
16212262befSBruno Randolf
16312262befSBruno Randolf spin_lock(&block->lock);
16412262befSBruno Randolf data = inb(block->runtime_reg + block->data_reg);
16512262befSBruno Randolf spin_unlock(&block->lock);
16612262befSBruno Randolf
16712262befSBruno Randolf return !!(data & BIT(offset));
16812262befSBruno Randolf }
16912262befSBruno Randolf
__sch311x_gpio_set(struct sch311x_gpio_block * block,unsigned offset,int value)17012262befSBruno Randolf static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
17112262befSBruno Randolf unsigned offset, int value)
17212262befSBruno Randolf {
173eb452a84SLinus Walleij u8 data = inb(block->runtime_reg + block->data_reg);
17412262befSBruno Randolf if (value)
17512262befSBruno Randolf data |= BIT(offset);
17612262befSBruno Randolf else
17712262befSBruno Randolf data &= ~BIT(offset);
17812262befSBruno Randolf outb(data, block->runtime_reg + block->data_reg);
17912262befSBruno Randolf }
18012262befSBruno Randolf
sch311x_gpio_set(struct gpio_chip * chip,unsigned offset,int value)18112262befSBruno Randolf static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
18212262befSBruno Randolf int value)
18312262befSBruno Randolf {
1848ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
18512262befSBruno Randolf
18612262befSBruno Randolf spin_lock(&block->lock);
18712262befSBruno Randolf __sch311x_gpio_set(block, offset, value);
18812262befSBruno Randolf spin_unlock(&block->lock);
18912262befSBruno Randolf }
19012262befSBruno Randolf
sch311x_gpio_direction_in(struct gpio_chip * chip,unsigned offset)19112262befSBruno Randolf static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
19212262befSBruno Randolf {
1938ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
194eb452a84SLinus Walleij u8 data;
19512262befSBruno Randolf
19612262befSBruno Randolf spin_lock(&block->lock);
1974a2398d7SLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]);
1984a2398d7SLinus Walleij data |= SCH311X_GPIO_CONF_DIR;
1994a2398d7SLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]);
20012262befSBruno Randolf spin_unlock(&block->lock);
20112262befSBruno Randolf
20212262befSBruno Randolf return 0;
20312262befSBruno Randolf }
20412262befSBruno Randolf
sch311x_gpio_direction_out(struct gpio_chip * chip,unsigned offset,int value)20512262befSBruno Randolf static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
20612262befSBruno Randolf int value)
20712262befSBruno Randolf {
2088ca7f1faSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
209eb452a84SLinus Walleij u8 data;
21012262befSBruno Randolf
21112262befSBruno Randolf spin_lock(&block->lock);
21212262befSBruno Randolf
2134a2398d7SLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]);
2144a2398d7SLinus Walleij data &= ~SCH311X_GPIO_CONF_DIR;
2154a2398d7SLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]);
21612262befSBruno Randolf __sch311x_gpio_set(block, offset, value);
21712262befSBruno Randolf
21812262befSBruno Randolf spin_unlock(&block->lock);
21912262befSBruno Randolf return 0;
22012262befSBruno Randolf }
22112262befSBruno Randolf
sch311x_gpio_get_direction(struct gpio_chip * chip,unsigned offset)222f9e03b0eSLinus Walleij static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
223f9e03b0eSLinus Walleij {
224f9e03b0eSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
225eb452a84SLinus Walleij u8 data;
226f9e03b0eSLinus Walleij
227f9e03b0eSLinus Walleij spin_lock(&block->lock);
228f9e03b0eSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]);
229f9e03b0eSLinus Walleij spin_unlock(&block->lock);
230f9e03b0eSLinus Walleij
231e42615ecSMatti Vaittinen if (data & SCH311X_GPIO_CONF_DIR)
232e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN;
233e42615ecSMatti Vaittinen
234e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT;
235f9e03b0eSLinus Walleij }
236f9e03b0eSLinus Walleij
sch311x_gpio_set_config(struct gpio_chip * chip,unsigned offset,unsigned long config)2374455a82aSLinus Walleij static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
2384455a82aSLinus Walleij unsigned long config)
2394455a82aSLinus Walleij {
2404455a82aSLinus Walleij struct sch311x_gpio_block *block = gpiochip_get_data(chip);
2414455a82aSLinus Walleij enum pin_config_param param = pinconf_to_config_param(config);
242eb452a84SLinus Walleij u8 data;
2434455a82aSLinus Walleij
2444455a82aSLinus Walleij switch (param) {
2454455a82aSLinus Walleij case PIN_CONFIG_DRIVE_OPEN_DRAIN:
2464455a82aSLinus Walleij spin_lock(&block->lock);
2474455a82aSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]);
2484455a82aSLinus Walleij data |= SCH311X_GPIO_CONF_OPEN_DRAIN;
2494455a82aSLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]);
2504455a82aSLinus Walleij spin_unlock(&block->lock);
2514455a82aSLinus Walleij return 0;
2524455a82aSLinus Walleij case PIN_CONFIG_DRIVE_PUSH_PULL:
2534455a82aSLinus Walleij spin_lock(&block->lock);
2544455a82aSLinus Walleij data = inb(block->runtime_reg + block->config_regs[offset]);
2554455a82aSLinus Walleij data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN;
2564455a82aSLinus Walleij outb(data, block->runtime_reg + block->config_regs[offset]);
2574455a82aSLinus Walleij spin_unlock(&block->lock);
2584455a82aSLinus Walleij return 0;
2594455a82aSLinus Walleij default:
2604455a82aSLinus Walleij break;
2614455a82aSLinus Walleij }
2624455a82aSLinus Walleij return -ENOTSUPP;
2634455a82aSLinus Walleij }
2644455a82aSLinus Walleij
sch311x_gpio_probe(struct platform_device * pdev)26512262befSBruno Randolf static int sch311x_gpio_probe(struct platform_device *pdev)
26612262befSBruno Randolf {
267ab128afcSNizam Haider struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
26812262befSBruno Randolf struct sch311x_gpio_priv *priv;
26912262befSBruno Randolf struct sch311x_gpio_block *block;
27012262befSBruno Randolf int err, i;
27112262befSBruno Randolf
27212262befSBruno Randolf /* we can register all GPIO data registers at once */
27313441457SWilliam Breathitt Gray if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6,
27413441457SWilliam Breathitt Gray DRV_NAME)) {
27512262befSBruno Randolf dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
27612262befSBruno Randolf pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
27712262befSBruno Randolf return -EBUSY;
27812262befSBruno Randolf }
27912262befSBruno Randolf
28012262befSBruno Randolf priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
28112262befSBruno Randolf if (!priv)
28212262befSBruno Randolf return -ENOMEM;
28312262befSBruno Randolf
28412262befSBruno Randolf for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
28512262befSBruno Randolf block = &priv->blocks[i];
28612262befSBruno Randolf
28712262befSBruno Randolf spin_lock_init(&block->lock);
28812262befSBruno Randolf
28912262befSBruno Randolf block->chip.label = DRV_NAME;
29012262befSBruno Randolf block->chip.owner = THIS_MODULE;
29112262befSBruno Randolf block->chip.request = sch311x_gpio_request;
29212262befSBruno Randolf block->chip.free = sch311x_gpio_free;
29312262befSBruno Randolf block->chip.direction_input = sch311x_gpio_direction_in;
29412262befSBruno Randolf block->chip.direction_output = sch311x_gpio_direction_out;
295f9e03b0eSLinus Walleij block->chip.get_direction = sch311x_gpio_get_direction;
2964455a82aSLinus Walleij block->chip.set_config = sch311x_gpio_set_config;
29712262befSBruno Randolf block->chip.get = sch311x_gpio_get;
29812262befSBruno Randolf block->chip.set = sch311x_gpio_set;
29912262befSBruno Randolf block->chip.ngpio = 8;
30058383c78SLinus Walleij block->chip.parent = &pdev->dev;
30112262befSBruno Randolf block->chip.base = sch311x_gpio_blocks[i].base;
30212262befSBruno Randolf block->config_regs = sch311x_gpio_blocks[i].config_regs;
30312262befSBruno Randolf block->data_reg = sch311x_gpio_blocks[i].data_reg;
30412262befSBruno Randolf block->runtime_reg = pdata->runtime_reg;
30512262befSBruno Randolf
306*4cf381bfSAndrew Davis err = devm_gpiochip_add_data(&pdev->dev, &block->chip, block);
30712262befSBruno Randolf if (err < 0) {
30812262befSBruno Randolf dev_err(&pdev->dev,
30912262befSBruno Randolf "Could not register gpiochip, %d\n", err);
310*4cf381bfSAndrew Davis return err;
31112262befSBruno Randolf }
31212262befSBruno Randolf dev_info(&pdev->dev,
31312262befSBruno Randolf "SMSC SCH311x GPIO block %d registered.\n", i);
31412262befSBruno Randolf }
31512262befSBruno Randolf
31612262befSBruno Randolf return 0;
31712262befSBruno Randolf }
31812262befSBruno Randolf
31912262befSBruno Randolf static struct platform_driver sch311x_gpio_driver = {
32012262befSBruno Randolf .driver.name = DRV_NAME,
32112262befSBruno Randolf .probe = sch311x_gpio_probe,
32212262befSBruno Randolf };
32312262befSBruno Randolf
32412262befSBruno Randolf
32512262befSBruno Randolf /*
32612262befSBruno Randolf * Init & exit routines
32712262befSBruno Randolf */
32812262befSBruno Randolf
sch311x_detect(int sio_config_port,unsigned short * addr)32912262befSBruno Randolf static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
33012262befSBruno Randolf {
33112262befSBruno Randolf int err = 0, reg;
33212262befSBruno Randolf unsigned short base_addr;
333eb452a84SLinus Walleij u8 dev_id;
33412262befSBruno Randolf
33512262befSBruno Randolf err = sch311x_sio_enter(sio_config_port);
33612262befSBruno Randolf if (err)
33712262befSBruno Randolf return err;
33812262befSBruno Randolf
3397e9fcc9dSAxel Lin /* Check device ID. */
34012262befSBruno Randolf reg = sch311x_sio_inb(sio_config_port, 0x20);
3417e9fcc9dSAxel Lin switch (reg) {
3427e9fcc9dSAxel Lin case 0x7c: /* SCH3112 */
3437e9fcc9dSAxel Lin dev_id = 2;
3447e9fcc9dSAxel Lin break;
3457e9fcc9dSAxel Lin case 0x7d: /* SCH3114 */
3467e9fcc9dSAxel Lin dev_id = 4;
3477e9fcc9dSAxel Lin break;
3487e9fcc9dSAxel Lin case 0x7f: /* SCH3116 */
3497e9fcc9dSAxel Lin dev_id = 6;
3507e9fcc9dSAxel Lin break;
3517e9fcc9dSAxel Lin default:
35212262befSBruno Randolf err = -ENODEV;
35312262befSBruno Randolf goto exit;
35412262befSBruno Randolf }
35512262befSBruno Randolf
35612262befSBruno Randolf /* Select logical device A (runtime registers) */
35712262befSBruno Randolf sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
35812262befSBruno Randolf
35912262befSBruno Randolf /* Check if Logical Device Register is currently active */
36012262befSBruno Randolf if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
36112262befSBruno Randolf pr_info("Seems that LDN 0x0a is not active...\n");
36212262befSBruno Randolf
36312262befSBruno Randolf /* Get the base address of the runtime registers */
36412262befSBruno Randolf base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
36512262befSBruno Randolf sch311x_sio_inb(sio_config_port, 0x61);
36612262befSBruno Randolf if (!base_addr) {
36712262befSBruno Randolf pr_err("Base address not set\n");
36812262befSBruno Randolf err = -ENODEV;
36912262befSBruno Randolf goto exit;
37012262befSBruno Randolf }
37112262befSBruno Randolf *addr = base_addr;
37212262befSBruno Randolf
37312262befSBruno Randolf pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
37412262befSBruno Randolf
37512262befSBruno Randolf exit:
37612262befSBruno Randolf sch311x_sio_exit(sio_config_port);
37712262befSBruno Randolf return err;
37812262befSBruno Randolf }
37912262befSBruno Randolf
sch311x_gpio_pdev_add(const unsigned short addr)38012262befSBruno Randolf static int __init sch311x_gpio_pdev_add(const unsigned short addr)
38112262befSBruno Randolf {
38212262befSBruno Randolf struct sch311x_pdev_data pdata;
38312262befSBruno Randolf int err;
38412262befSBruno Randolf
38512262befSBruno Randolf pdata.runtime_reg = addr;
38612262befSBruno Randolf
38712262befSBruno Randolf sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
38812262befSBruno Randolf if (!sch311x_gpio_pdev)
38912262befSBruno Randolf return -ENOMEM;
39012262befSBruno Randolf
39112262befSBruno Randolf err = platform_device_add_data(sch311x_gpio_pdev,
39212262befSBruno Randolf &pdata, sizeof(pdata));
39312262befSBruno Randolf if (err) {
39412262befSBruno Randolf pr_err(DRV_NAME "Platform data allocation failed\n");
39512262befSBruno Randolf goto err;
39612262befSBruno Randolf }
39712262befSBruno Randolf
39812262befSBruno Randolf err = platform_device_add(sch311x_gpio_pdev);
39912262befSBruno Randolf if (err) {
40012262befSBruno Randolf pr_err(DRV_NAME "Device addition failed\n");
40112262befSBruno Randolf goto err;
40212262befSBruno Randolf }
40312262befSBruno Randolf return 0;
40412262befSBruno Randolf
40512262befSBruno Randolf err:
40612262befSBruno Randolf platform_device_put(sch311x_gpio_pdev);
40712262befSBruno Randolf return err;
40812262befSBruno Randolf }
40912262befSBruno Randolf
sch311x_gpio_init(void)41012262befSBruno Randolf static int __init sch311x_gpio_init(void)
41112262befSBruno Randolf {
41212262befSBruno Randolf int err, i;
41312262befSBruno Randolf unsigned short addr = 0;
41412262befSBruno Randolf
41512262befSBruno Randolf for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
41612262befSBruno Randolf if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
41712262befSBruno Randolf break;
41812262befSBruno Randolf
41912262befSBruno Randolf if (!addr)
42012262befSBruno Randolf return -ENODEV;
42112262befSBruno Randolf
42212262befSBruno Randolf err = platform_driver_register(&sch311x_gpio_driver);
42312262befSBruno Randolf if (err)
42412262befSBruno Randolf return err;
42512262befSBruno Randolf
42612262befSBruno Randolf err = sch311x_gpio_pdev_add(addr);
42712262befSBruno Randolf if (err)
42812262befSBruno Randolf goto unreg_platform_driver;
42912262befSBruno Randolf
43012262befSBruno Randolf return 0;
43112262befSBruno Randolf
43212262befSBruno Randolf unreg_platform_driver:
43312262befSBruno Randolf platform_driver_unregister(&sch311x_gpio_driver);
43412262befSBruno Randolf return err;
43512262befSBruno Randolf }
43612262befSBruno Randolf
sch311x_gpio_exit(void)43712262befSBruno Randolf static void __exit sch311x_gpio_exit(void)
43812262befSBruno Randolf {
43912262befSBruno Randolf platform_device_unregister(sch311x_gpio_pdev);
44012262befSBruno Randolf platform_driver_unregister(&sch311x_gpio_driver);
44112262befSBruno Randolf }
44212262befSBruno Randolf
44312262befSBruno Randolf module_init(sch311x_gpio_init);
44412262befSBruno Randolf module_exit(sch311x_gpio_exit);
44512262befSBruno Randolf
44612262befSBruno Randolf MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
44712262befSBruno Randolf MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
44812262befSBruno Randolf MODULE_LICENSE("GPL");
44912262befSBruno Randolf MODULE_ALIAS("platform:gpio-sch311x");
450