1703afc38a0e79b69ecc8529924848e020a586e70David Schleef/* 2703afc38a0e79b69ecc8529924848e020a586e70David Schleef comedi/drivers/8253.h 3703afc38a0e79b69ecc8529924848e020a586e70David Schleef Header file for 8253 4703afc38a0e79b69ecc8529924848e020a586e70David Schleef 5703afc38a0e79b69ecc8529924848e020a586e70David Schleef COMEDI - Linux Control and Measurement Device Interface 6703afc38a0e79b69ecc8529924848e020a586e70David Schleef Copyright (C) 2000 David A. Schleef <ds@schleef.org> 7703afc38a0e79b69ecc8529924848e020a586e70David Schleef 8703afc38a0e79b69ecc8529924848e020a586e70David Schleef This program is free software; you can redistribute it and/or modify 9703afc38a0e79b69ecc8529924848e020a586e70David Schleef it under the terms of the GNU General Public License as published by 10703afc38a0e79b69ecc8529924848e020a586e70David Schleef the Free Software Foundation; either version 2 of the License, or 11703afc38a0e79b69ecc8529924848e020a586e70David Schleef (at your option) any later version. 12703afc38a0e79b69ecc8529924848e020a586e70David Schleef 13703afc38a0e79b69ecc8529924848e020a586e70David Schleef This program is distributed in the hope that it will be useful, 14703afc38a0e79b69ecc8529924848e020a586e70David Schleef but WITHOUT ANY WARRANTY; without even the implied warranty of 15703afc38a0e79b69ecc8529924848e020a586e70David Schleef MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16703afc38a0e79b69ecc8529924848e020a586e70David Schleef GNU General Public License for more details. 17703afc38a0e79b69ecc8529924848e020a586e70David Schleef 18703afc38a0e79b69ecc8529924848e020a586e70David Schleef You should have received a copy of the GNU General Public License 19703afc38a0e79b69ecc8529924848e020a586e70David Schleef along with this program; if not, write to the Free Software 20703afc38a0e79b69ecc8529924848e020a586e70David Schleef Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21703afc38a0e79b69ecc8529924848e020a586e70David Schleef 22703afc38a0e79b69ecc8529924848e020a586e70David Schleef*/ 23703afc38a0e79b69ecc8529924848e020a586e70David Schleef 24703afc38a0e79b69ecc8529924848e020a586e70David Schleef#ifndef _8253_H 25703afc38a0e79b69ecc8529924848e020a586e70David Schleef#define _8253_H 26703afc38a0e79b69ecc8529924848e020a586e70David Schleef 27703afc38a0e79b69ecc8529924848e020a586e70David Schleef#include "../comedi.h" 28703afc38a0e79b69ecc8529924848e020a586e70David Schleef 29703afc38a0e79b69ecc8529924848e020a586e70David Schleef#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div 30703afc38a0e79b69ecc8529924848e020a586e70David Schleef 31703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base, 320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d1, 330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d2, 340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *nanosec, 350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral int round_mode) 36703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 37703afc38a0e79b69ecc8529924848e020a586e70David Schleef int divider; 38703afc38a0e79b69ecc8529924848e020a586e70David Schleef int div1, div2; 39703afc38a0e79b69ecc8529924848e020a586e70David Schleef int div1_glb, div2_glb, ns_glb; 40703afc38a0e79b69ecc8529924848e020a586e70David Schleef int div1_lub, div2_lub, ns_lub; 41703afc38a0e79b69ecc8529924848e020a586e70David Schleef int ns; 42703afc38a0e79b69ecc8529924848e020a586e70David Schleef 43703afc38a0e79b69ecc8529924848e020a586e70David Schleef divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base; 44703afc38a0e79b69ecc8529924848e020a586e70David Schleef 45703afc38a0e79b69ecc8529924848e020a586e70David Schleef /* find 2 integers 1<={x,y}<=65536 such that x*y is 46703afc38a0e79b69ecc8529924848e020a586e70David Schleef close to divider */ 47703afc38a0e79b69ecc8529924848e020a586e70David Schleef 48703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_lub = div2_lub = 0; 49703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_glb = div2_glb = 0; 50703afc38a0e79b69ecc8529924848e020a586e70David Schleef 51703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_glb = 0; 52703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_lub = 0xffffffff; 53703afc38a0e79b69ecc8529924848e020a586e70David Schleef 54703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = 0x10000; 55703afc38a0e79b69ecc8529924848e020a586e70David Schleef for (div1 = divider / 65536 + 1; div1 < div2; div1++) { 56703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = divider / div1; 57703afc38a0e79b69ecc8529924848e020a586e70David Schleef 58703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns = i8253_osc_base * div1 * div2; 59703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (ns <= *nanosec && ns > ns_glb) { 60703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_glb = ns; 61703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_glb = div1; 62703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2_glb = div2; 63703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 64703afc38a0e79b69ecc8529924848e020a586e70David Schleef 65703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2++; 66703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (div2 <= 65536) { 67703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns = i8253_osc_base * div1 * div2; 68703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (ns > *nanosec && ns < ns_lub) { 69703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_lub = ns; 70703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_lub = div1; 71703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2_lub = div2; 72703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 73703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 74703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 75703afc38a0e79b69ecc8529924848e020a586e70David Schleef 76703afc38a0e79b69ecc8529924848e020a586e70David Schleef *nanosec = div1_lub * div2_lub * i8253_osc_base; 77703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d1 = div1_lub & 0xffff; 78703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d2 = div2_lub & 0xffff; 79703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 80703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 81703afc38a0e79b69ecc8529924848e020a586e70David Schleef 82703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base, 830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d1, 840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d2, 850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *nanosec, 860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral int round_mode) 87703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 88703afc38a0e79b69ecc8529924848e020a586e70David Schleef int div1, div2; 89703afc38a0e79b69ecc8529924848e020a586e70David Schleef int base; 90703afc38a0e79b69ecc8529924848e020a586e70David Schleef 91703afc38a0e79b69ecc8529924848e020a586e70David Schleef for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) { 92703afc38a0e79b69ecc8529924848e020a586e70David Schleef base = i8253_osc_base * div1; 93703afc38a0e79b69ecc8529924848e020a586e70David Schleef round_mode &= TRIG_ROUND_MASK; 94703afc38a0e79b69ecc8529924848e020a586e70David Schleef switch (round_mode) { 95703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_NEAREST: 96703afc38a0e79b69ecc8529924848e020a586e70David Schleef default: 97703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = (*nanosec + base / 2) / base; 98703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 99703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_DOWN: 100703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = (*nanosec) / base; 101703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 102703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_UP: 103703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = (*nanosec + base - 1) / base; 104703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 105703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 106703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (div2 < 2) 107703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = 2; 108703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (div2 <= 65536) { 109703afc38a0e79b69ecc8529924848e020a586e70David Schleef *nanosec = div2 * base; 110703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d1 = div1 & 0xffff; 111703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d2 = div2 & 0xffff; 112703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 113703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 114703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 115703afc38a0e79b69ecc8529924848e020a586e70David Schleef 116703afc38a0e79b69ecc8529924848e020a586e70David Schleef /* shouldn't get here */ 117703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = 0x10000; 118703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = 0x10000; 119703afc38a0e79b69ecc8529924848e020a586e70David Schleef *nanosec = div1 * div2 * i8253_osc_base; 120703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d1 = div1 & 0xffff; 121703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d2 = div2 & 0xffff; 122703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 123703afc38a0e79b69ecc8529924848e020a586e70David Schleef 124703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base, 1250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d1, 1260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *d2, 1270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *nanosec, 1280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral int round_mode) 129703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 130703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int divider; 131703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int div1, div2; 132703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int div1_glb, div2_glb, ns_glb; 133703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int div1_lub, div2_lub, ns_lub; 134703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int ns; 135703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int start; 136703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int ns_low, ns_high; 137703afc38a0e79b69ecc8529924848e020a586e70David Schleef static const unsigned int max_count = 0x10000; 138703afc38a0e79b69ecc8529924848e020a586e70David Schleef /* exit early if everything is already correct (this can save time 139703afc38a0e79b69ecc8529924848e020a586e70David Schleef * since this function may be called repeatedly during command tests 140703afc38a0e79b69ecc8529924848e020a586e70David Schleef * and execution) */ 141703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = *d1 ? *d1 : max_count; 142703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = *d2 ? *d2 : max_count; 143703afc38a0e79b69ecc8529924848e020a586e70David Schleef divider = div1 * div2; 144703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (div1 * div2 * i8253_osc_base == *nanosec && 1450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral div1 > 1 && div1 <= max_count && div2 > 1 && div2 <= max_count && 1460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* check for overflow */ 1470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral divider > div1 && divider > div2 && 1480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral divider * i8253_osc_base > divider && 1490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral divider * i8253_osc_base > i8253_osc_base) { 150703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 151703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 152703afc38a0e79b69ecc8529924848e020a586e70David Schleef 153703afc38a0e79b69ecc8529924848e020a586e70David Schleef divider = *nanosec / i8253_osc_base; 154703afc38a0e79b69ecc8529924848e020a586e70David Schleef 155703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_lub = div2_lub = 0; 156703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_glb = div2_glb = 0; 157703afc38a0e79b69ecc8529924848e020a586e70David Schleef 158703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_glb = 0; 159703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_lub = 0xffffffff; 160703afc38a0e79b69ecc8529924848e020a586e70David Schleef 161703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = max_count; 162703afc38a0e79b69ecc8529924848e020a586e70David Schleef start = divider / div2; 163703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (start < 2) 164703afc38a0e79b69ecc8529924848e020a586e70David Schleef start = 2; 165703afc38a0e79b69ecc8529924848e020a586e70David Schleef for (div1 = start; div1 <= divider / div1 + 1 && div1 <= max_count; 1660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral div1++) { 167703afc38a0e79b69ecc8529924848e020a586e70David Schleef for (div2 = divider / div1; 1680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral div1 * div2 <= divider + div1 + 1 && div2 <= max_count; 1690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral div2++) { 170703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns = i8253_osc_base * div1 * div2; 171703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (ns <= *nanosec && ns > ns_glb) { 172703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_glb = ns; 173703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_glb = div1; 174703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2_glb = div2; 175703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 176703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (ns >= *nanosec && ns < ns_lub) { 177703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_lub = ns; 178703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1_lub = div1; 179703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2_lub = div2; 180703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 181703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 182703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 183703afc38a0e79b69ecc8529924848e020a586e70David Schleef 184703afc38a0e79b69ecc8529924848e020a586e70David Schleef round_mode &= TRIG_ROUND_MASK; 185703afc38a0e79b69ecc8529924848e020a586e70David Schleef switch (round_mode) { 186703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_NEAREST: 187703afc38a0e79b69ecc8529924848e020a586e70David Schleef default: 188703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_high = div1_lub * div2_lub * i8253_osc_base; 189703afc38a0e79b69ecc8529924848e020a586e70David Schleef ns_low = div1_glb * div2_glb * i8253_osc_base; 190703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (ns_high - *nanosec < *nanosec - ns_low) { 191703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = div1_lub; 192703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = div2_lub; 193703afc38a0e79b69ecc8529924848e020a586e70David Schleef } else { 194703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = div1_glb; 195703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = div2_glb; 196703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 197703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 198703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_UP: 199703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = div1_lub; 200703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = div2_lub; 201703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 202703afc38a0e79b69ecc8529924848e020a586e70David Schleef case TRIG_ROUND_DOWN: 203703afc38a0e79b69ecc8529924848e020a586e70David Schleef div1 = div1_glb; 204703afc38a0e79b69ecc8529924848e020a586e70David Schleef div2 = div2_glb; 205703afc38a0e79b69ecc8529924848e020a586e70David Schleef break; 206703afc38a0e79b69ecc8529924848e020a586e70David Schleef } 207703afc38a0e79b69ecc8529924848e020a586e70David Schleef 208703afc38a0e79b69ecc8529924848e020a586e70David Schleef *nanosec = div1 * div2 * i8253_osc_base; 209155b44aae0ed9a0f9aecc8c528ba5bc3b26f8377Greg Kroah-Hartman /* masking is done since counter maps zero to 0x10000 */ 210155b44aae0ed9a0f9aecc8c528ba5bc3b26f8377Greg Kroah-Hartman *d1 = div1 & 0xffff; 211703afc38a0e79b69ecc8529924848e020a586e70David Schleef *d2 = div2 & 0xffff; 212703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 213703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 214703afc38a0e79b69ecc8529924848e020a586e70David Schleef 215703afc38a0e79b69ecc8529924848e020a586e70David Schleef#ifndef CMDTEST 216703afc38a0e79b69ecc8529924848e020a586e70David Schleef/* i8254_load programs 8254 counter chip. It should also work for the 8253. 217a88e29cfd8e59c82cf63440117bd1d61761f0f87Graham M Howe * base_address is the lowest io address 218a88e29cfd8e59c82cf63440117bd1d61761f0f87Graham M Howe * for the chip (the address of counter 0). 219703afc38a0e79b69ecc8529924848e020a586e70David Schleef * counter_number is the counter you want to load (0,1 or 2) 220703afc38a0e79b69ecc8529924848e020a586e70David Schleef * count is the number to load into the counter. 221703afc38a0e79b69ecc8529924848e020a586e70David Schleef * 222703afc38a0e79b69ecc8529924848e020a586e70David Schleef * You probably want to use mode 2. 223703afc38a0e79b69ecc8529924848e020a586e70David Schleef * 224703afc38a0e79b69ecc8529924848e020a586e70David Schleef * Use i8254_mm_load() if you board uses memory-mapped io, it is 225703afc38a0e79b69ecc8529924848e020a586e70David Schleef * the same as i8254_load() except it uses writeb() instead of outb(). 226703afc38a0e79b69ecc8529924848e020a586e70David Schleef * 227703afc38a0e79b69ecc8529924848e020a586e70David Schleef * Neither i8254_load() or i8254_read() do their loading/reading 228703afc38a0e79b69ecc8529924848e020a586e70David Schleef * atomically. The 16 bit read/writes are performed with two successive 229703afc38a0e79b69ecc8529924848e020a586e70David Schleef * 8 bit read/writes. So if two parts of your driver do a load/read on 230703afc38a0e79b69ecc8529924848e020a586e70David Schleef * the same counter, it may be necessary to protect these functions 231703afc38a0e79b69ecc8529924848e020a586e70David Schleef * with a spinlock. 232703afc38a0e79b69ecc8529924848e020a586e70David Schleef * 233703afc38a0e79b69ecc8529924848e020a586e70David Schleef * FMH 234703afc38a0e79b69ecc8529924848e020a586e70David Schleef */ 235703afc38a0e79b69ecc8529924848e020a586e70David Schleef 236703afc38a0e79b69ecc8529924848e020a586e70David Schleef#define i8254_control_reg 3 237703afc38a0e79b69ecc8529924848e020a586e70David Schleef 238703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_load(unsigned long base_address, unsigned int regshift, 2390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, unsigned int count, 2400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int mode) 241703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 242703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 243703afc38a0e79b69ecc8529924848e020a586e70David Schleef 244703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 245703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 246703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (count > 0xffff) 247703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 248703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (mode > 5) 249703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 250703afc38a0e79b69ecc8529924848e020a586e70David Schleef if ((mode == 2 || mode == 3) && count == 1) 251703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 252703afc38a0e79b69ecc8529924848e020a586e70David Schleef 253703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 25467d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= 0x30; /* load low then high byte */ 25567d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= (mode << 1); /* set counter mode */ 256703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (i8254_control_reg << regshift)); 25767d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = count & 0xff; /* lsb of counter value */ 258703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (counter_number << regshift)); 25967d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = (count >> 8) & 0xff; /* msb of counter value */ 260703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (counter_number << regshift)); 261703afc38a0e79b69ecc8529924848e020a586e70David Schleef 262703afc38a0e79b69ecc8529924848e020a586e70David Schleef return 0; 263703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 264703afc38a0e79b69ecc8529924848e020a586e70David Schleef 265703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_mm_load(void *base_address, unsigned int regshift, 2660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, unsigned int count, 2670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int mode) 268703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 269703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 270703afc38a0e79b69ecc8529924848e020a586e70David Schleef 271703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 272703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 273703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (count > 0xffff) 274703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 275703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (mode > 5) 276703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 277703afc38a0e79b69ecc8529924848e020a586e70David Schleef if ((mode == 2 || mode == 3) && count == 1) 278703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 279703afc38a0e79b69ecc8529924848e020a586e70David Schleef 280703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 28167d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= 0x30; /* load low then high byte */ 28267d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= (mode << 1); /* set counter mode */ 283703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (i8254_control_reg << regshift)); 28467d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = count & 0xff; /* lsb of counter value */ 285703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (counter_number << regshift)); 28667d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = (count >> 8) & 0xff; /* msb of counter value */ 287703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (counter_number << regshift)); 288703afc38a0e79b69ecc8529924848e020a586e70David Schleef 289703afc38a0e79b69ecc8529924848e020a586e70David Schleef return 0; 290703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 291703afc38a0e79b69ecc8529924848e020a586e70David Schleef 292703afc38a0e79b69ecc8529924848e020a586e70David Schleef/* Returns 16 bit counter value, should work for 8253 also.*/ 293703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_read(unsigned long base_address, unsigned int regshift, 2940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number) 295703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 296703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 297703afc38a0e79b69ecc8529924848e020a586e70David Schleef int ret; 298703afc38a0e79b69ecc8529924848e020a586e70David Schleef 299703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 300703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 301703afc38a0e79b69ecc8529924848e020a586e70David Schleef 30267d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* latch counter */ 303703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 304703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (i8254_control_reg << regshift)); 305703afc38a0e79b69ecc8529924848e020a586e70David Schleef 30667d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* read lsb */ 307703afc38a0e79b69ecc8529924848e020a586e70David Schleef ret = inb(base_address + (counter_number << regshift)); 30867d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* read msb */ 309703afc38a0e79b69ecc8529924848e020a586e70David Schleef ret += inb(base_address + (counter_number << regshift)) << 8; 310703afc38a0e79b69ecc8529924848e020a586e70David Schleef 311703afc38a0e79b69ecc8529924848e020a586e70David Schleef return ret; 312703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 313703afc38a0e79b69ecc8529924848e020a586e70David Schleef 314703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_mm_read(void *base_address, unsigned int regshift, 3150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number) 316703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 317703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 318703afc38a0e79b69ecc8529924848e020a586e70David Schleef int ret; 319703afc38a0e79b69ecc8529924848e020a586e70David Schleef 320703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 321703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 322703afc38a0e79b69ecc8529924848e020a586e70David Schleef 32367d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* latch counter */ 324703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 325703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (i8254_control_reg << regshift)); 326703afc38a0e79b69ecc8529924848e020a586e70David Schleef 32767d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* read lsb */ 328703afc38a0e79b69ecc8529924848e020a586e70David Schleef ret = readb(base_address + (counter_number << regshift)); 32967d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton /* read msb */ 330703afc38a0e79b69ecc8529924848e020a586e70David Schleef ret += readb(base_address + (counter_number << regshift)) << 8; 331703afc38a0e79b69ecc8529924848e020a586e70David Schleef 332703afc38a0e79b69ecc8529924848e020a586e70David Schleef return ret; 333703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 334703afc38a0e79b69ecc8529924848e020a586e70David Schleef 335703afc38a0e79b69ecc8529924848e020a586e70David Schleef/* Loads 16 bit initial counter value, should work for 8253 also. */ 336703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline void i8254_write(unsigned long base_address, 3370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 3380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, unsigned int count) 339703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 340703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 341703afc38a0e79b69ecc8529924848e020a586e70David Schleef 342703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 343703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 344703afc38a0e79b69ecc8529924848e020a586e70David Schleef 34567d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = count & 0xff; /* lsb of counter value */ 346703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (counter_number << regshift)); 34767d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = (count >> 8) & 0xff; /* msb of counter value */ 348703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (counter_number << regshift)); 349703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 350703afc38a0e79b69ecc8529924848e020a586e70David Schleef 351703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline void i8254_mm_write(void *base_address, 3520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 3530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, 3540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int count) 355703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 356703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 357703afc38a0e79b69ecc8529924848e020a586e70David Schleef 358703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 359703afc38a0e79b69ecc8529924848e020a586e70David Schleef return; 360703afc38a0e79b69ecc8529924848e020a586e70David Schleef 36167d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = count & 0xff; /* lsb of counter value */ 362703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (counter_number << regshift)); 36367d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte = (count >> 8) & 0xff; /* msb of counter value */ 364703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (counter_number << regshift)); 365703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 366703afc38a0e79b69ecc8529924848e020a586e70David Schleef 367703afc38a0e79b69ecc8529924848e020a586e70David Schleef/* Set counter mode, should work for 8253 also. 368703afc38a0e79b69ecc8529924848e020a586e70David Schleef * Note: the 'mode' value is different to that for i8254_load() and comes 369703afc38a0e79b69ecc8529924848e020a586e70David Schleef * from the INSN_CONFIG_8254_SET_MODE command: 370703afc38a0e79b69ecc8529924848e020a586e70David Schleef * I8254_MODE0, I8254_MODE1, ..., I8254_MODE5 371703afc38a0e79b69ecc8529924848e020a586e70David Schleef * OR'ed with: 372703afc38a0e79b69ecc8529924848e020a586e70David Schleef * I8254_BCD, I8254_BINARY 373703afc38a0e79b69ecc8529924848e020a586e70David Schleef */ 374703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_set_mode(unsigned long base_address, 3750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 3760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, unsigned int mode) 377703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 378703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 379703afc38a0e79b69ecc8529924848e020a586e70David Schleef 380703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 381703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 382703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (mode > (I8254_MODE5 | I8254_BINARY)) 383703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 384703afc38a0e79b69ecc8529924848e020a586e70David Schleef 385703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 38667d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= 0x30; /* load low then high byte */ 38767d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= mode; /* set counter mode and BCD|binary */ 388703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(byte, base_address + (i8254_control_reg << regshift)); 389703afc38a0e79b69ecc8529924848e020a586e70David Schleef 390703afc38a0e79b69ecc8529924848e020a586e70David Schleef return 0; 391703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 392703afc38a0e79b69ecc8529924848e020a586e70David Schleef 393703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_mm_set_mode(void *base_address, 3940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 3950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number, 3960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int mode) 397703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 398703afc38a0e79b69ecc8529924848e020a586e70David Schleef unsigned int byte; 399703afc38a0e79b69ecc8529924848e020a586e70David Schleef 400703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (counter_number > 2) 401703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 402703afc38a0e79b69ecc8529924848e020a586e70David Schleef if (mode > (I8254_MODE5 | I8254_BINARY)) 403703afc38a0e79b69ecc8529924848e020a586e70David Schleef return -1; 404703afc38a0e79b69ecc8529924848e020a586e70David Schleef 405703afc38a0e79b69ecc8529924848e020a586e70David Schleef byte = counter_number << 6; 40667d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= 0x30; /* load low then high byte */ 40767d83b4fb96ab304a47ba5af9a99818b38c9fd3eBill Pemberton byte |= mode; /* set counter mode and BCD|binary */ 408703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(byte, base_address + (i8254_control_reg << regshift)); 409703afc38a0e79b69ecc8529924848e020a586e70David Schleef 410703afc38a0e79b69ecc8529924848e020a586e70David Schleef return 0; 411703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 412703afc38a0e79b69ecc8529924848e020a586e70David Schleef 413703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_status(unsigned long base_address, 4140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 4150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number) 416703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 417703afc38a0e79b69ecc8529924848e020a586e70David Schleef outb(0xE0 | (2 << counter_number), 4180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral base_address + (i8254_control_reg << regshift)); 419703afc38a0e79b69ecc8529924848e020a586e70David Schleef return inb(base_address + (counter_number << regshift)); 420703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 421703afc38a0e79b69ecc8529924848e020a586e70David Schleef 422703afc38a0e79b69ecc8529924848e020a586e70David Schleefstatic inline int i8254_mm_status(void *base_address, 4230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int regshift, 4240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int counter_number) 425703afc38a0e79b69ecc8529924848e020a586e70David Schleef{ 426703afc38a0e79b69ecc8529924848e020a586e70David Schleef writeb(0xE0 | (2 << counter_number), 4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral base_address + (i8254_control_reg << regshift)); 428703afc38a0e79b69ecc8529924848e020a586e70David Schleef return readb(base_address + (counter_number << regshift)); 429703afc38a0e79b69ecc8529924848e020a586e70David Schleef} 430703afc38a0e79b69ecc8529924848e020a586e70David Schleef 431703afc38a0e79b69ecc8529924848e020a586e70David Schleef#endif 432703afc38a0e79b69ecc8529924848e020a586e70David Schleef 433703afc38a0e79b69ecc8529924848e020a586e70David Schleef#endif 434