xref: /linux/drivers/gpio/gpio-sch311x.c (revision eb452a84ece6b84e22c53abdd49ff018d189ae8a)
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