forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.1 KiB
156 lines
3.1 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Silicon Labs C2 port Linux support for Eurotech Duramar 2150 |
|
* |
|
* Copyright (c) 2008 Rodolfo Giometti <[email protected]> |
|
* Copyright (c) 2008 Eurotech S.p.A. <[email protected]> |
|
*/ |
|
|
|
#include <linux/errno.h> |
|
#include <linux/init.h> |
|
#include <linux/kernel.h> |
|
#include <linux/module.h> |
|
#include <linux/delay.h> |
|
#include <linux/io.h> |
|
#include <linux/ioport.h> |
|
#include <linux/c2port.h> |
|
|
|
#define DATA_PORT 0x325 |
|
#define DIR_PORT 0x326 |
|
#define C2D (1 << 0) |
|
#define C2CK (1 << 1) |
|
|
|
static DEFINE_MUTEX(update_lock); |
|
|
|
/* |
|
* C2 port operations |
|
*/ |
|
|
|
static void duramar2150_c2port_access(struct c2port_device *dev, int status) |
|
{ |
|
u8 v; |
|
|
|
mutex_lock(&update_lock); |
|
|
|
v = inb(DIR_PORT); |
|
|
|
/* 0 = input, 1 = output */ |
|
if (status) |
|
outb(v | (C2D | C2CK), DIR_PORT); |
|
else |
|
/* When access is "off" is important that both lines are set |
|
* as inputs or hi-impedance */ |
|
outb(v & ~(C2D | C2CK), DIR_PORT); |
|
|
|
mutex_unlock(&update_lock); |
|
} |
|
|
|
static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir) |
|
{ |
|
u8 v; |
|
|
|
mutex_lock(&update_lock); |
|
|
|
v = inb(DIR_PORT); |
|
|
|
if (dir) |
|
outb(v & ~C2D, DIR_PORT); |
|
else |
|
outb(v | C2D, DIR_PORT); |
|
|
|
mutex_unlock(&update_lock); |
|
} |
|
|
|
static int duramar2150_c2port_c2d_get(struct c2port_device *dev) |
|
{ |
|
return inb(DATA_PORT) & C2D; |
|
} |
|
|
|
static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status) |
|
{ |
|
u8 v; |
|
|
|
mutex_lock(&update_lock); |
|
|
|
v = inb(DATA_PORT); |
|
|
|
if (status) |
|
outb(v | C2D, DATA_PORT); |
|
else |
|
outb(v & ~C2D, DATA_PORT); |
|
|
|
mutex_unlock(&update_lock); |
|
} |
|
|
|
static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status) |
|
{ |
|
u8 v; |
|
|
|
mutex_lock(&update_lock); |
|
|
|
v = inb(DATA_PORT); |
|
|
|
if (status) |
|
outb(v | C2CK, DATA_PORT); |
|
else |
|
outb(v & ~C2CK, DATA_PORT); |
|
|
|
mutex_unlock(&update_lock); |
|
} |
|
|
|
static struct c2port_ops duramar2150_c2port_ops = { |
|
.block_size = 512, /* bytes */ |
|
.blocks_num = 30, /* total flash size: 15360 bytes */ |
|
|
|
.access = duramar2150_c2port_access, |
|
.c2d_dir = duramar2150_c2port_c2d_dir, |
|
.c2d_get = duramar2150_c2port_c2d_get, |
|
.c2d_set = duramar2150_c2port_c2d_set, |
|
.c2ck_set = duramar2150_c2port_c2ck_set, |
|
}; |
|
|
|
static struct c2port_device *duramar2150_c2port_dev; |
|
|
|
/* |
|
* Module stuff |
|
*/ |
|
|
|
static int __init duramar2150_c2port_init(void) |
|
{ |
|
struct resource *res; |
|
int ret = 0; |
|
|
|
res = request_region(0x325, 2, "c2port"); |
|
if (!res) |
|
return -EBUSY; |
|
|
|
duramar2150_c2port_dev = c2port_device_register("uc", |
|
&duramar2150_c2port_ops, NULL); |
|
if (IS_ERR(duramar2150_c2port_dev)) { |
|
ret = PTR_ERR(duramar2150_c2port_dev); |
|
goto free_region; |
|
} |
|
|
|
return 0; |
|
|
|
free_region: |
|
release_region(0x325, 2); |
|
return ret; |
|
} |
|
|
|
static void __exit duramar2150_c2port_exit(void) |
|
{ |
|
/* Setup the GPIOs as input by default (access = 0) */ |
|
duramar2150_c2port_access(duramar2150_c2port_dev, 0); |
|
|
|
c2port_device_unregister(duramar2150_c2port_dev); |
|
|
|
release_region(0x325, 2); |
|
} |
|
|
|
module_init(duramar2150_c2port_init); |
|
module_exit(duramar2150_c2port_exit); |
|
|
|
MODULE_AUTHOR("Rodolfo Giometti <[email protected]>"); |
|
MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150"); |
|
MODULE_LICENSE("GPL");
|
|
|