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