1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Silicon Labs C2 port Linux support for Eurotech Duramar 2150 |
4 | * |
5 | * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it> |
6 | * Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it> |
7 | */ |
8 | |
9 | #include <linux/errno.h> |
10 | #include <linux/init.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/io.h> |
15 | #include <linux/ioport.h> |
16 | #include <linux/c2port.h> |
17 | |
18 | #define DATA_PORT 0x325 |
19 | #define DIR_PORT 0x326 |
20 | #define C2D (1 << 0) |
21 | #define C2CK (1 << 1) |
22 | |
23 | static DEFINE_MUTEX(update_lock); |
24 | |
25 | /* |
26 | * C2 port operations |
27 | */ |
28 | |
29 | static void duramar2150_c2port_access(struct c2port_device *dev, int status) |
30 | { |
31 | u8 v; |
32 | |
33 | mutex_lock(&update_lock); |
34 | |
35 | v = inb(DIR_PORT); |
36 | |
37 | /* 0 = input, 1 = output */ |
38 | if (status) |
39 | outb(value: v | (C2D | C2CK), DIR_PORT); |
40 | else |
41 | /* When access is "off" is important that both lines are set |
42 | * as inputs or hi-impedance */ |
43 | outb(value: v & ~(C2D | C2CK), DIR_PORT); |
44 | |
45 | mutex_unlock(lock: &update_lock); |
46 | } |
47 | |
48 | static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir) |
49 | { |
50 | u8 v; |
51 | |
52 | mutex_lock(&update_lock); |
53 | |
54 | v = inb(DIR_PORT); |
55 | |
56 | if (dir) |
57 | outb(value: v & ~C2D, DIR_PORT); |
58 | else |
59 | outb(value: v | C2D, DIR_PORT); |
60 | |
61 | mutex_unlock(lock: &update_lock); |
62 | } |
63 | |
64 | static int duramar2150_c2port_c2d_get(struct c2port_device *dev) |
65 | { |
66 | return inb(DATA_PORT) & C2D; |
67 | } |
68 | |
69 | static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status) |
70 | { |
71 | u8 v; |
72 | |
73 | mutex_lock(&update_lock); |
74 | |
75 | v = inb(DATA_PORT); |
76 | |
77 | if (status) |
78 | outb(value: v | C2D, DATA_PORT); |
79 | else |
80 | outb(value: v & ~C2D, DATA_PORT); |
81 | |
82 | mutex_unlock(lock: &update_lock); |
83 | } |
84 | |
85 | static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status) |
86 | { |
87 | u8 v; |
88 | |
89 | mutex_lock(&update_lock); |
90 | |
91 | v = inb(DATA_PORT); |
92 | |
93 | if (status) |
94 | outb(value: v | C2CK, DATA_PORT); |
95 | else |
96 | outb(value: v & ~C2CK, DATA_PORT); |
97 | |
98 | mutex_unlock(lock: &update_lock); |
99 | } |
100 | |
101 | static struct c2port_ops duramar2150_c2port_ops = { |
102 | .block_size = 512, /* bytes */ |
103 | .blocks_num = 30, /* total flash size: 15360 bytes */ |
104 | |
105 | .access = duramar2150_c2port_access, |
106 | .c2d_dir = duramar2150_c2port_c2d_dir, |
107 | .c2d_get = duramar2150_c2port_c2d_get, |
108 | .c2d_set = duramar2150_c2port_c2d_set, |
109 | .c2ck_set = duramar2150_c2port_c2ck_set, |
110 | }; |
111 | |
112 | static struct c2port_device *duramar2150_c2port_dev; |
113 | |
114 | /* |
115 | * Module stuff |
116 | */ |
117 | |
118 | static int __init duramar2150_c2port_init(void) |
119 | { |
120 | struct resource *res; |
121 | int ret = 0; |
122 | |
123 | res = request_region(0x325, 2, "c2port" ); |
124 | if (!res) |
125 | return -EBUSY; |
126 | |
127 | duramar2150_c2port_dev = c2port_device_register(name: "uc" , |
128 | ops: &duramar2150_c2port_ops, NULL); |
129 | if (IS_ERR(ptr: duramar2150_c2port_dev)) { |
130 | ret = PTR_ERR(ptr: duramar2150_c2port_dev); |
131 | goto free_region; |
132 | } |
133 | |
134 | return 0; |
135 | |
136 | free_region: |
137 | release_region(0x325, 2); |
138 | return ret; |
139 | } |
140 | |
141 | static void __exit duramar2150_c2port_exit(void) |
142 | { |
143 | /* Setup the GPIOs as input by default (access = 0) */ |
144 | duramar2150_c2port_access(dev: duramar2150_c2port_dev, status: 0); |
145 | |
146 | c2port_device_unregister(dev: duramar2150_c2port_dev); |
147 | |
148 | release_region(0x325, 2); |
149 | } |
150 | |
151 | module_init(duramar2150_c2port_init); |
152 | module_exit(duramar2150_c2port_exit); |
153 | |
154 | MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>" ); |
155 | MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150" ); |
156 | MODULE_LICENSE("GPL" ); |
157 | |