1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel 8254 Programmable Interval Timer 4 * Copyright (C) William Breathitt Gray 5 */ 6 #include <linux/bitfield.h> 7 #include <linux/bits.h> 8 #include <linux/counter.h> 9 #include <linux/device.h> 10 #include <linux/err.h> 11 #include <linux/export.h> 12 #include <linux/i8254.h> 13 #include <linux/limits.h> 14 #include <linux/module.h> 15 #include <linux/mutex.h> 16 #include <linux/regmap.h> 17 18 #include <asm/unaligned.h> 19 20 #define I8254_COUNTER_REG(_counter) (_counter) 21 #define I8254_CONTROL_REG 0x3 22 23 #define I8254_SC GENMASK(7, 6) 24 #define I8254_RW GENMASK(5, 4) 25 #define I8254_M GENMASK(3, 1) 26 #define I8254_CONTROL(_sc, _rw, _m) \ 27 (u8_encode_bits(_sc, I8254_SC) | u8_encode_bits(_rw, I8254_RW) | \ 28 u8_encode_bits(_m, I8254_M)) 29 30 #define I8254_RW_TWO_BYTE 0x3 31 #define I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT 0 32 #define I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT 1 33 #define I8254_MODE_RATE_GENERATOR 2 34 #define I8254_MODE_SQUARE_WAVE_MODE 3 35 #define I8254_MODE_SOFTWARE_TRIGGERED_STROBE 4 36 #define I8254_MODE_HARDWARE_TRIGGERED_STROBE 5 37 38 #define I8254_COUNTER_LATCH(_counter) I8254_CONTROL(_counter, 0x0, 0x0) 39 #define I8254_PROGRAM_COUNTER(_counter, _mode) I8254_CONTROL(_counter, I8254_RW_TWO_BYTE, _mode) 40 41 #define I8254_NUM_COUNTERS 3 42 43 /** 44 * struct i8254 - I8254 device private data structure 45 * @lock: synchronization lock to prevent I/O race conditions 46 * @preset: array of Counter Register states 47 * @out_mode: array of mode configuration states 48 * @map: Regmap for the device 49 */ 50 struct i8254 { 51 struct mutex lock; 52 u16 preset[I8254_NUM_COUNTERS]; 53 u8 out_mode[I8254_NUM_COUNTERS]; 54 struct regmap *map; 55 }; 56 57 static int i8254_count_read(struct counter_device *const counter, struct counter_count *const count, 58 u64 *const val) 59 { 60 struct i8254 *const priv = counter_priv(counter); 61 int ret; 62 u8 value[2]; 63 64 mutex_lock(&priv->lock); 65 66 ret = regmap_write(priv->map, I8254_CONTROL_REG, I8254_COUNTER_LATCH(count->id)); 67 if (ret) { 68 mutex_unlock(&priv->lock); 69 return ret; 70 } 71 ret = regmap_noinc_read(priv->map, I8254_COUNTER_REG(count->id), value, sizeof(value)); 72 if (ret) { 73 mutex_unlock(&priv->lock); 74 return ret; 75 } 76 77 mutex_unlock(&priv->lock); 78 79 *val = get_unaligned_le16(value); 80 81 return ret; 82 } 83 84 static int i8254_function_read(struct counter_device *const counter, 85 struct counter_count *const count, 86 enum counter_function *const function) 87 { 88 *function = COUNTER_FUNCTION_DECREASE; 89 return 0; 90 } 91 92 #define I8254_SYNAPSES_PER_COUNT 2 93 #define I8254_SIGNAL_ID_CLK 0 94 #define I8254_SIGNAL_ID_GATE 1 95 96 static int i8254_action_read(struct counter_device *const counter, 97 struct counter_count *const count, 98 struct counter_synapse *const synapse, 99 enum counter_synapse_action *const action) 100 { 101 struct i8254 *const priv = counter_priv(counter); 102 103 switch (synapse->signal->id % I8254_SYNAPSES_PER_COUNT) { 104 case I8254_SIGNAL_ID_CLK: 105 *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE; 106 return 0; 107 case I8254_SIGNAL_ID_GATE: 108 switch (priv->out_mode[count->id]) { 109 case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT: 110 case I8254_MODE_RATE_GENERATOR: 111 case I8254_MODE_SQUARE_WAVE_MODE: 112 case I8254_MODE_HARDWARE_TRIGGERED_STROBE: 113 *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; 114 return 0; 115 default: 116 *action = COUNTER_SYNAPSE_ACTION_NONE; 117 return 0; 118 } 119 default: 120 /* should never reach this path */ 121 return -EINVAL; 122 } 123 } 124 125 static int i8254_count_ceiling_read(struct counter_device *const counter, 126 struct counter_count *const count, u64 *const ceiling) 127 { 128 struct i8254 *const priv = counter_priv(counter); 129 130 mutex_lock(&priv->lock); 131 132 switch (priv->out_mode[count->id]) { 133 case I8254_MODE_RATE_GENERATOR: 134 /* Rate Generator decrements 0 by one and the counter "wraps around" */ 135 *ceiling = (priv->preset[count->id] == 0) ? U16_MAX : priv->preset[count->id]; 136 break; 137 case I8254_MODE_SQUARE_WAVE_MODE: 138 if (priv->preset[count->id] % 2) 139 *ceiling = priv->preset[count->id] - 1; 140 else if (priv->preset[count->id] == 0) 141 /* Square Wave Mode decrements 0 by two and the counter "wraps around" */ 142 *ceiling = U16_MAX - 1; 143 else 144 *ceiling = priv->preset[count->id]; 145 break; 146 default: 147 *ceiling = U16_MAX; 148 break; 149 } 150 151 mutex_unlock(&priv->lock); 152 153 return 0; 154 } 155 156 static int i8254_count_mode_read(struct counter_device *const counter, 157 struct counter_count *const count, 158 enum counter_count_mode *const count_mode) 159 { 160 const struct i8254 *const priv = counter_priv(counter); 161 162 switch (priv->out_mode[count->id]) { 163 case I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT: 164 *count_mode = COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT; 165 return 0; 166 case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT: 167 *count_mode = COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT; 168 return 0; 169 case I8254_MODE_RATE_GENERATOR: 170 *count_mode = COUNTER_COUNT_MODE_RATE_GENERATOR; 171 return 0; 172 case I8254_MODE_SQUARE_WAVE_MODE: 173 *count_mode = COUNTER_COUNT_MODE_SQUARE_WAVE_MODE; 174 return 0; 175 case I8254_MODE_SOFTWARE_TRIGGERED_STROBE: 176 *count_mode = COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE; 177 return 0; 178 case I8254_MODE_HARDWARE_TRIGGERED_STROBE: 179 *count_mode = COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE; 180 return 0; 181 default: 182 /* should never reach this path */ 183 return -EINVAL; 184 } 185 } 186 187 static int i8254_count_mode_write(struct counter_device *const counter, 188 struct counter_count *const count, 189 const enum counter_count_mode count_mode) 190 { 191 struct i8254 *const priv = counter_priv(counter); 192 u8 out_mode; 193 int ret; 194 195 switch (count_mode) { 196 case COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT: 197 out_mode = I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT; 198 break; 199 case COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT: 200 out_mode = I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT; 201 break; 202 case COUNTER_COUNT_MODE_RATE_GENERATOR: 203 out_mode = I8254_MODE_RATE_GENERATOR; 204 break; 205 case COUNTER_COUNT_MODE_SQUARE_WAVE_MODE: 206 out_mode = I8254_MODE_SQUARE_WAVE_MODE; 207 break; 208 case COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE: 209 out_mode = I8254_MODE_SOFTWARE_TRIGGERED_STROBE; 210 break; 211 case COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE: 212 out_mode = I8254_MODE_HARDWARE_TRIGGERED_STROBE; 213 break; 214 default: 215 /* should never reach this path */ 216 return -EINVAL; 217 } 218 219 mutex_lock(&priv->lock); 220 221 /* Counter Register is cleared when the counter is programmed */ 222 priv->preset[count->id] = 0; 223 priv->out_mode[count->id] = out_mode; 224 ret = regmap_write(priv->map, I8254_CONTROL_REG, 225 I8254_PROGRAM_COUNTER(count->id, out_mode)); 226 227 mutex_unlock(&priv->lock); 228 229 return ret; 230 } 231 232 static int i8254_count_floor_read(struct counter_device *const counter, 233 struct counter_count *const count, u64 *const floor) 234 { 235 struct i8254 *const priv = counter_priv(counter); 236 237 mutex_lock(&priv->lock); 238 239 switch (priv->out_mode[count->id]) { 240 case I8254_MODE_RATE_GENERATOR: 241 /* counter is always reloaded after 1, but 0 is a possible reload value */ 242 *floor = (priv->preset[count->id] == 0) ? 0 : 1; 243 break; 244 case I8254_MODE_SQUARE_WAVE_MODE: 245 /* counter is always reloaded after 2 for even preset values */ 246 *floor = (priv->preset[count->id] % 2 || priv->preset[count->id] == 0) ? 0 : 2; 247 break; 248 default: 249 *floor = 0; 250 break; 251 } 252 253 mutex_unlock(&priv->lock); 254 255 return 0; 256 } 257 258 static int i8254_count_preset_read(struct counter_device *const counter, 259 struct counter_count *const count, u64 *const preset) 260 { 261 const struct i8254 *const priv = counter_priv(counter); 262 263 *preset = priv->preset[count->id]; 264 265 return 0; 266 } 267 268 static int i8254_count_preset_write(struct counter_device *const counter, 269 struct counter_count *const count, const u64 preset) 270 { 271 struct i8254 *const priv = counter_priv(counter); 272 int ret; 273 u8 value[2]; 274 275 if (preset > U16_MAX) 276 return -ERANGE; 277 278 mutex_lock(&priv->lock); 279 280 if (priv->out_mode[count->id] == I8254_MODE_RATE_GENERATOR || 281 priv->out_mode[count->id] == I8254_MODE_SQUARE_WAVE_MODE) { 282 if (preset == 1) { 283 mutex_unlock(&priv->lock); 284 return -EINVAL; 285 } 286 } 287 288 priv->preset[count->id] = preset; 289 290 put_unaligned_le16(preset, value); 291 ret = regmap_noinc_write(priv->map, I8254_COUNTER_REG(count->id), value, 2); 292 293 mutex_unlock(&priv->lock); 294 295 return ret; 296 } 297 298 static int i8254_init_hw(struct regmap *const map) 299 { 300 unsigned long i; 301 int ret; 302 303 for (i = 0; i < I8254_NUM_COUNTERS; i++) { 304 /* Initialize each counter to Mode 0 */ 305 ret = regmap_write(map, I8254_CONTROL_REG, 306 I8254_PROGRAM_COUNTER(i, I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT)); 307 if (ret) 308 return ret; 309 } 310 311 return 0; 312 } 313 314 static const struct counter_ops i8254_ops = { 315 .count_read = i8254_count_read, 316 .function_read = i8254_function_read, 317 .action_read = i8254_action_read, 318 }; 319 320 #define I8254_SIGNAL(_id, _name) { \ 321 .id = (_id), \ 322 .name = (_name), \ 323 } 324 325 static struct counter_signal i8254_signals[] = { 326 I8254_SIGNAL(0, "CLK 0"), I8254_SIGNAL(1, "GATE 0"), 327 I8254_SIGNAL(2, "CLK 1"), I8254_SIGNAL(3, "GATE 1"), 328 I8254_SIGNAL(4, "CLK 2"), I8254_SIGNAL(5, "GATE 2"), 329 }; 330 331 static const enum counter_synapse_action i8254_clk_actions[] = { 332 COUNTER_SYNAPSE_ACTION_FALLING_EDGE, 333 }; 334 static const enum counter_synapse_action i8254_gate_actions[] = { 335 COUNTER_SYNAPSE_ACTION_NONE, 336 COUNTER_SYNAPSE_ACTION_RISING_EDGE, 337 }; 338 339 #define I8254_SYNAPSES_BASE(_id) ((_id) * I8254_SYNAPSES_PER_COUNT) 340 #define I8254_SYNAPSE_CLK(_id) { \ 341 .actions_list = i8254_clk_actions, \ 342 .num_actions = ARRAY_SIZE(i8254_clk_actions), \ 343 .signal = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 0], \ 344 } 345 #define I8254_SYNAPSE_GATE(_id) { \ 346 .actions_list = i8254_gate_actions, \ 347 .num_actions = ARRAY_SIZE(i8254_gate_actions), \ 348 .signal = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 1], \ 349 } 350 351 static struct counter_synapse i8254_synapses[] = { 352 I8254_SYNAPSE_CLK(0), I8254_SYNAPSE_GATE(0), 353 I8254_SYNAPSE_CLK(1), I8254_SYNAPSE_GATE(1), 354 I8254_SYNAPSE_CLK(2), I8254_SYNAPSE_GATE(2), 355 }; 356 357 static const enum counter_function i8254_functions_list[] = { 358 COUNTER_FUNCTION_DECREASE, 359 }; 360 361 static const enum counter_count_mode i8254_count_modes[] = { 362 COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT, 363 COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT, 364 COUNTER_COUNT_MODE_RATE_GENERATOR, 365 COUNTER_COUNT_MODE_SQUARE_WAVE_MODE, 366 COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE, 367 COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE, 368 }; 369 370 static DEFINE_COUNTER_AVAILABLE(i8254_count_modes_available, i8254_count_modes); 371 372 static struct counter_comp i8254_count_ext[] = { 373 COUNTER_COMP_CEILING(i8254_count_ceiling_read, NULL), 374 COUNTER_COMP_COUNT_MODE(i8254_count_mode_read, i8254_count_mode_write, 375 i8254_count_modes_available), 376 COUNTER_COMP_FLOOR(i8254_count_floor_read, NULL), 377 COUNTER_COMP_PRESET(i8254_count_preset_read, i8254_count_preset_write), 378 }; 379 380 #define I8254_COUNT(_id, _name) { \ 381 .id = (_id), \ 382 .name = (_name), \ 383 .functions_list = i8254_functions_list, \ 384 .num_functions = ARRAY_SIZE(i8254_functions_list), \ 385 .synapses = &i8254_synapses[I8254_SYNAPSES_BASE(_id)], \ 386 .num_synapses = I8254_SYNAPSES_PER_COUNT, \ 387 .ext = i8254_count_ext, \ 388 .num_ext = ARRAY_SIZE(i8254_count_ext) \ 389 } 390 391 static struct counter_count i8254_counts[I8254_NUM_COUNTERS] = { 392 I8254_COUNT(0, "Counter 0"), I8254_COUNT(1, "Counter 1"), I8254_COUNT(2, "Counter 2"), 393 }; 394 395 /** 396 * devm_i8254_regmap_register - Register an i8254 Counter device 397 * @dev: device that is registering this i8254 Counter device 398 * @config: configuration for i8254_regmap_config 399 * 400 * Registers an Intel 8254 Programmable Interval Timer Counter device. Returns 0 on success and 401 * negative error number on failure. 402 */ 403 int devm_i8254_regmap_register(struct device *const dev, 404 const struct i8254_regmap_config *const config) 405 { 406 struct counter_device *counter; 407 struct i8254 *priv; 408 int err; 409 410 if (!config->parent) 411 return -EINVAL; 412 413 if (!config->map) 414 return -EINVAL; 415 416 counter = devm_counter_alloc(dev, sizeof(*priv)); 417 if (!counter) 418 return -ENOMEM; 419 priv = counter_priv(counter); 420 priv->map = config->map; 421 422 counter->name = dev_name(config->parent); 423 counter->parent = config->parent; 424 counter->ops = &i8254_ops; 425 counter->counts = i8254_counts; 426 counter->num_counts = ARRAY_SIZE(i8254_counts); 427 counter->signals = i8254_signals; 428 counter->num_signals = ARRAY_SIZE(i8254_signals); 429 430 mutex_init(&priv->lock); 431 432 err = i8254_init_hw(priv->map); 433 if (err) 434 return err; 435 436 err = devm_counter_add(dev, counter); 437 if (err < 0) 438 return dev_err_probe(dev, err, "Failed to add counter\n"); 439 440 return 0; 441 } 442 EXPORT_SYMBOL_NS_GPL(devm_i8254_regmap_register, I8254); 443 444 MODULE_AUTHOR("William Breathitt Gray"); 445 MODULE_DESCRIPTION("Intel 8254 Programmable Interval Timer"); 446 MODULE_LICENSE("GPL"); 447 MODULE_IMPORT_NS(COUNTER); 448