1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
265131cd5SRodolfo Giometti /*
365131cd5SRodolfo Giometti  *  Silicon Labs C2 port Linux support for Eurotech Duramar 2150
465131cd5SRodolfo Giometti  *
565131cd5SRodolfo Giometti  *  Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
665131cd5SRodolfo Giometti  *  Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it>
765131cd5SRodolfo Giometti  */
865131cd5SRodolfo Giometti 
965131cd5SRodolfo Giometti #include <linux/errno.h>
1065131cd5SRodolfo Giometti #include <linux/init.h>
1165131cd5SRodolfo Giometti #include <linux/kernel.h>
1265131cd5SRodolfo Giometti #include <linux/module.h>
1365131cd5SRodolfo Giometti #include <linux/delay.h>
1465131cd5SRodolfo Giometti #include <linux/io.h>
15ecd9d34aSPaul Gortmaker #include <linux/ioport.h>
1665131cd5SRodolfo Giometti #include <linux/c2port.h>
1765131cd5SRodolfo Giometti 
1865131cd5SRodolfo Giometti #define DATA_PORT	0x325
1965131cd5SRodolfo Giometti #define DIR_PORT	0x326
2065131cd5SRodolfo Giometti #define    C2D		   (1 << 0)
2165131cd5SRodolfo Giometti #define    C2CK		   (1 << 1)
2265131cd5SRodolfo Giometti 
2365131cd5SRodolfo Giometti static DEFINE_MUTEX(update_lock);
2465131cd5SRodolfo Giometti 
2565131cd5SRodolfo Giometti /*
2665131cd5SRodolfo Giometti  * C2 port operations
2765131cd5SRodolfo Giometti  */
2865131cd5SRodolfo Giometti 
duramar2150_c2port_access(struct c2port_device * dev,int status)2965131cd5SRodolfo Giometti static void duramar2150_c2port_access(struct c2port_device *dev, int status)
3065131cd5SRodolfo Giometti {
3165131cd5SRodolfo Giometti 	u8 v;
3265131cd5SRodolfo Giometti 
3365131cd5SRodolfo Giometti 	mutex_lock(&update_lock);
3465131cd5SRodolfo Giometti 
3565131cd5SRodolfo Giometti 	v = inb(DIR_PORT);
3665131cd5SRodolfo Giometti 
3765131cd5SRodolfo Giometti 	/* 0 = input, 1 = output */
3865131cd5SRodolfo Giometti 	if (status)
3965131cd5SRodolfo Giometti 		outb(v | (C2D | C2CK), DIR_PORT);
4065131cd5SRodolfo Giometti 	else
4165131cd5SRodolfo Giometti 		/* When access is "off" is important that both lines are set
4225985edcSLucas De Marchi 		 * as inputs or hi-impedance */
4365131cd5SRodolfo Giometti 		outb(v & ~(C2D | C2CK), DIR_PORT);
4465131cd5SRodolfo Giometti 
4565131cd5SRodolfo Giometti 	mutex_unlock(&update_lock);
4665131cd5SRodolfo Giometti }
4765131cd5SRodolfo Giometti 
duramar2150_c2port_c2d_dir(struct c2port_device * dev,int dir)4865131cd5SRodolfo Giometti static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir)
4965131cd5SRodolfo Giometti {
5065131cd5SRodolfo Giometti 	u8 v;
5165131cd5SRodolfo Giometti 
5265131cd5SRodolfo Giometti 	mutex_lock(&update_lock);
5365131cd5SRodolfo Giometti 
5465131cd5SRodolfo Giometti 	v = inb(DIR_PORT);
5565131cd5SRodolfo Giometti 
5665131cd5SRodolfo Giometti 	if (dir)
5765131cd5SRodolfo Giometti 		outb(v & ~C2D, DIR_PORT);
5865131cd5SRodolfo Giometti 	else
5965131cd5SRodolfo Giometti 		outb(v | C2D, DIR_PORT);
6065131cd5SRodolfo Giometti 
6165131cd5SRodolfo Giometti 	mutex_unlock(&update_lock);
6265131cd5SRodolfo Giometti }
6365131cd5SRodolfo Giometti 
duramar2150_c2port_c2d_get(struct c2port_device * dev)6465131cd5SRodolfo Giometti static int duramar2150_c2port_c2d_get(struct c2port_device *dev)
6565131cd5SRodolfo Giometti {
6665131cd5SRodolfo Giometti 	return inb(DATA_PORT) & C2D;
6765131cd5SRodolfo Giometti }
6865131cd5SRodolfo Giometti 
duramar2150_c2port_c2d_set(struct c2port_device * dev,int status)6965131cd5SRodolfo Giometti static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status)
7065131cd5SRodolfo Giometti {
7165131cd5SRodolfo Giometti 	u8 v;
7265131cd5SRodolfo Giometti 
7365131cd5SRodolfo Giometti 	mutex_lock(&update_lock);
7465131cd5SRodolfo Giometti 
7565131cd5SRodolfo Giometti 	v = inb(DATA_PORT);
7665131cd5SRodolfo Giometti 
7765131cd5SRodolfo Giometti 	if (status)
7865131cd5SRodolfo Giometti 		outb(v | C2D, DATA_PORT);
7965131cd5SRodolfo Giometti 	else
8065131cd5SRodolfo Giometti 		outb(v & ~C2D, DATA_PORT);
8165131cd5SRodolfo Giometti 
8265131cd5SRodolfo Giometti 	mutex_unlock(&update_lock);
8365131cd5SRodolfo Giometti }
8465131cd5SRodolfo Giometti 
duramar2150_c2port_c2ck_set(struct c2port_device * dev,int status)8565131cd5SRodolfo Giometti static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status)
8665131cd5SRodolfo Giometti {
8765131cd5SRodolfo Giometti 	u8 v;
8865131cd5SRodolfo Giometti 
8965131cd5SRodolfo Giometti 	mutex_lock(&update_lock);
9065131cd5SRodolfo Giometti 
9165131cd5SRodolfo Giometti 	v = inb(DATA_PORT);
9265131cd5SRodolfo Giometti 
9365131cd5SRodolfo Giometti 	if (status)
9465131cd5SRodolfo Giometti 		outb(v | C2CK, DATA_PORT);
9565131cd5SRodolfo Giometti 	else
9665131cd5SRodolfo Giometti 		outb(v & ~C2CK, DATA_PORT);
9765131cd5SRodolfo Giometti 
9865131cd5SRodolfo Giometti 	mutex_unlock(&update_lock);
9965131cd5SRodolfo Giometti }
10065131cd5SRodolfo Giometti 
10165131cd5SRodolfo Giometti static struct c2port_ops duramar2150_c2port_ops = {
10265131cd5SRodolfo Giometti 	.block_size	= 512,	/* bytes */
10365131cd5SRodolfo Giometti 	.blocks_num	= 30,	/* total flash size: 15360 bytes */
10465131cd5SRodolfo Giometti 
10565131cd5SRodolfo Giometti 	.access		= duramar2150_c2port_access,
10665131cd5SRodolfo Giometti 	.c2d_dir	= duramar2150_c2port_c2d_dir,
10765131cd5SRodolfo Giometti 	.c2d_get	= duramar2150_c2port_c2d_get,
10865131cd5SRodolfo Giometti 	.c2d_set	= duramar2150_c2port_c2d_set,
10965131cd5SRodolfo Giometti 	.c2ck_set	= duramar2150_c2port_c2ck_set,
11065131cd5SRodolfo Giometti };
11165131cd5SRodolfo Giometti 
11265131cd5SRodolfo Giometti static struct c2port_device *duramar2150_c2port_dev;
11365131cd5SRodolfo Giometti 
11465131cd5SRodolfo Giometti /*
11565131cd5SRodolfo Giometti  * Module stuff
11665131cd5SRodolfo Giometti  */
11765131cd5SRodolfo Giometti 
duramar2150_c2port_init(void)11865131cd5SRodolfo Giometti static int __init duramar2150_c2port_init(void)
11965131cd5SRodolfo Giometti {
12065131cd5SRodolfo Giometti 	struct resource *res;
12165131cd5SRodolfo Giometti 	int ret = 0;
12265131cd5SRodolfo Giometti 
12365131cd5SRodolfo Giometti 	res = request_region(0x325, 2, "c2port");
12465131cd5SRodolfo Giometti 	if (!res)
12565131cd5SRodolfo Giometti 		return -EBUSY;
12665131cd5SRodolfo Giometti 
12765131cd5SRodolfo Giometti 	duramar2150_c2port_dev = c2port_device_register("uc",
12865131cd5SRodolfo Giometti 					&duramar2150_c2port_ops, NULL);
1298128a31eSDan Carpenter 	if (IS_ERR(duramar2150_c2port_dev)) {
1308128a31eSDan Carpenter 		ret = PTR_ERR(duramar2150_c2port_dev);
13165131cd5SRodolfo Giometti 		goto free_region;
13265131cd5SRodolfo Giometti 	}
13365131cd5SRodolfo Giometti 
13465131cd5SRodolfo Giometti 	return 0;
13565131cd5SRodolfo Giometti 
13665131cd5SRodolfo Giometti free_region:
13765131cd5SRodolfo Giometti 	release_region(0x325, 2);
13865131cd5SRodolfo Giometti 	return ret;
13965131cd5SRodolfo Giometti }
14065131cd5SRodolfo Giometti 
duramar2150_c2port_exit(void)14165131cd5SRodolfo Giometti static void __exit duramar2150_c2port_exit(void)
14265131cd5SRodolfo Giometti {
14365131cd5SRodolfo Giometti 	/* Setup the GPIOs as input by default (access = 0) */
14465131cd5SRodolfo Giometti 	duramar2150_c2port_access(duramar2150_c2port_dev, 0);
14565131cd5SRodolfo Giometti 
14665131cd5SRodolfo Giometti 	c2port_device_unregister(duramar2150_c2port_dev);
14765131cd5SRodolfo Giometti 
14865131cd5SRodolfo Giometti 	release_region(0x325, 2);
14965131cd5SRodolfo Giometti }
15065131cd5SRodolfo Giometti 
15165131cd5SRodolfo Giometti module_init(duramar2150_c2port_init);
15265131cd5SRodolfo Giometti module_exit(duramar2150_c2port_exit);
15365131cd5SRodolfo Giometti 
15465131cd5SRodolfo Giometti MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
15565131cd5SRodolfo Giometti MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150");
15665131cd5SRodolfo Giometti MODULE_LICENSE("GPL");
157