0001
0002
0003
0004
0005
0006 #include <linux/bitmap.h>
0007 #include <linux/err.h>
0008 #include <linux/export.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/types.h>
0013
0014 #include "gpio-i8255.h"
0015
0016 #define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0)
0017 #define I8255_CONTROL_PORTB_DIRECTION BIT(1)
0018 #define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3)
0019 #define I8255_CONTROL_PORTA_DIRECTION BIT(4)
0020 #define I8255_CONTROL_MODE_SET BIT(7)
0021 #define I8255_PORTA 0
0022 #define I8255_PORTB 1
0023 #define I8255_PORTC 2
0024
0025 static int i8255_get_port(struct i8255 __iomem *const ppi,
0026 const unsigned long io_port, const unsigned long mask)
0027 {
0028 const unsigned long bank = io_port / 3;
0029 const unsigned long ppi_port = io_port % 3;
0030
0031 return ioread8(&ppi[bank].port[ppi_port]) & mask;
0032 }
0033
0034 static u8 i8255_direction_mask(const unsigned long offset)
0035 {
0036 const unsigned long port_offset = offset % 8;
0037 const unsigned long io_port = offset / 8;
0038 const unsigned long ppi_port = io_port % 3;
0039
0040 switch (ppi_port) {
0041 case I8255_PORTA:
0042 return I8255_CONTROL_PORTA_DIRECTION;
0043 case I8255_PORTB:
0044 return I8255_CONTROL_PORTB_DIRECTION;
0045 case I8255_PORTC:
0046
0047 if (port_offset >= 4)
0048 return I8255_CONTROL_PORTC_UPPER_DIRECTION;
0049 return I8255_CONTROL_PORTC_LOWER_DIRECTION;
0050 default:
0051
0052 return 0;
0053 }
0054 }
0055
0056 static void i8255_set_port(struct i8255 __iomem *const ppi,
0057 struct i8255_state *const state,
0058 const unsigned long io_port,
0059 const unsigned long mask, const unsigned long bits)
0060 {
0061 const unsigned long bank = io_port / 3;
0062 const unsigned long ppi_port = io_port % 3;
0063 unsigned long flags;
0064 unsigned long out_state;
0065
0066 spin_lock_irqsave(&state[bank].lock, flags);
0067
0068 out_state = ioread8(&ppi[bank].port[ppi_port]);
0069 out_state = (out_state & ~mask) | (bits & mask);
0070 iowrite8(out_state, &ppi[bank].port[ppi_port]);
0071
0072 spin_unlock_irqrestore(&state[bank].lock, flags);
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 void i8255_direction_input(struct i8255 __iomem *const ppi,
0086 struct i8255_state *const state,
0087 const unsigned long offset)
0088 {
0089 const unsigned long io_port = offset / 8;
0090 const unsigned long bank = io_port / 3;
0091 unsigned long flags;
0092
0093 spin_lock_irqsave(&state[bank].lock, flags);
0094
0095 state[bank].control_state |= I8255_CONTROL_MODE_SET;
0096 state[bank].control_state |= i8255_direction_mask(offset);
0097
0098 iowrite8(state[bank].control_state, &ppi[bank].control);
0099
0100 spin_unlock_irqrestore(&state[bank].lock, flags);
0101 }
0102 EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255);
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116 void i8255_direction_output(struct i8255 __iomem *const ppi,
0117 struct i8255_state *const state,
0118 const unsigned long offset,
0119 const unsigned long value)
0120 {
0121 const unsigned long io_port = offset / 8;
0122 const unsigned long bank = io_port / 3;
0123 unsigned long flags;
0124
0125 spin_lock_irqsave(&state[bank].lock, flags);
0126
0127 state[bank].control_state |= I8255_CONTROL_MODE_SET;
0128 state[bank].control_state &= ~i8255_direction_mask(offset);
0129
0130 iowrite8(state[bank].control_state, &ppi[bank].control);
0131
0132 spin_unlock_irqrestore(&state[bank].lock, flags);
0133
0134 i8255_set(ppi, state, offset, value);
0135 }
0136 EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
0147 {
0148 const unsigned long io_port = offset / 8;
0149 const unsigned long offset_mask = BIT(offset % 8);
0150
0151 return !!i8255_get_port(ppi, io_port, offset_mask);
0152 }
0153 EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
0154
0155
0156
0157
0158
0159
0160
0161
0162 int i8255_get_direction(const struct i8255_state *const state,
0163 const unsigned long offset)
0164 {
0165 const unsigned long io_port = offset / 8;
0166 const unsigned long bank = io_port / 3;
0167
0168 return !!(state[bank].control_state & i8255_direction_mask(offset));
0169 }
0170 EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 void i8255_get_multiple(struct i8255 __iomem *const ppi,
0183 const unsigned long *const mask,
0184 unsigned long *const bits, const unsigned long ngpio)
0185 {
0186 unsigned long offset;
0187 unsigned long port_mask;
0188 unsigned long io_port;
0189 unsigned long port_state;
0190
0191 bitmap_zero(bits, ngpio);
0192
0193 for_each_set_clump8(offset, port_mask, mask, ngpio) {
0194 io_port = offset / 8;
0195 port_state = i8255_get_port(ppi, io_port, port_mask);
0196
0197 bitmap_set_value8(bits, port_state, offset);
0198 }
0199 }
0200 EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
0201
0202
0203
0204
0205
0206
0207
0208
0209 void i8255_mode0_output(struct i8255 __iomem *const ppi)
0210 {
0211 iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
0212 }
0213 EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
0226 const unsigned long offset, const unsigned long value)
0227 {
0228 const unsigned long io_port = offset / 8;
0229 const unsigned long port_offset = offset % 8;
0230 const unsigned long mask = BIT(port_offset);
0231 const unsigned long bits = value << port_offset;
0232
0233 i8255_set_port(ppi, state, io_port, mask, bits);
0234 }
0235 EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248 void i8255_set_multiple(struct i8255 __iomem *const ppi,
0249 struct i8255_state *const state,
0250 const unsigned long *const mask,
0251 const unsigned long *const bits,
0252 const unsigned long ngpio)
0253 {
0254 unsigned long offset;
0255 unsigned long port_mask;
0256 unsigned long io_port;
0257 unsigned long value;
0258
0259 for_each_set_clump8(offset, port_mask, mask, ngpio) {
0260 io_port = offset / 8;
0261 value = bitmap_get_value8(bits, offset);
0262 i8255_set_port(ppi, state, io_port, port_mask, value);
0263 }
0264 }
0265 EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 void i8255_state_init(struct i8255_state *const state,
0276 const unsigned long nbanks)
0277 {
0278 unsigned long bank;
0279
0280 for (bank = 0; bank < nbanks; bank++)
0281 spin_lock_init(&state[bank].lock);
0282 }
0283 EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
0284
0285 MODULE_AUTHOR("William Breathitt Gray");
0286 MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface");
0287 MODULE_LICENSE("GPL");