brintos

brintos / linux-shallow public Read only

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