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