^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Telecom Clock driver for Intel NetStructure(tm) MPCBL0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2005 Kontron Canada
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This program is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * it under the terms of the GNU General Public License as published by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * the Free Software Foundation; either version 2 of the License, or (at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * your option) any later version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * This program is distributed in the hope that it will be useful, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * NON INFRINGEMENT. See the GNU General Public License for more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * You should have received a copy of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * along with this program; if not, write to the Free Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Send feedback to <sebastien.bouchard@ca.kontron.com> and the current
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Maintainer <mark.gross@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Description : This is the TELECOM CLOCK module driver for the ATCA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * MPCBL0010 ATCA computer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/kernel.h> /* printk() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/fs.h> /* everything... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/errno.h> /* error codes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <asm/io.h> /* inb/outb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) MODULE_AUTHOR("Sebastien Bouchard <sebastien.bouchard@ca.kontron.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*Hardware Reset of the PLL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define RESET_ON 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define RESET_OFF 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* MODE SELECT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define NORMAL_MODE 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define HOLDOVER_MODE 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define FREERUN_MODE 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* FILTER SELECT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define FILTER_6HZ 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define FILTER_12HZ 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* SELECT REFERENCE FREQUENCY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define REF_CLK1_8kHz 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define REF_CLK2_19_44MHz 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Select primary or secondary redundant clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define PRIMARY_CLOCK 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define SECONDARY_CLOCK 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* CLOCK TRANSMISSION DEFINE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define CLK_8kHz 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define CLK_16_384MHz 0xfb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define CLK_1_544MHz 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define CLK_2_048MHz 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define CLK_4_096MHz 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define CLK_6_312MHz 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define CLK_8_192MHz 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define CLK_19_440MHz 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define CLK_8_592MHz 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define CLK_11_184MHz 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define CLK_34_368MHz 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define CLK_44_736MHz 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* RECEIVED REFERENCE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define AMC_B1 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define AMC_B2 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* HARDWARE SWITCHING DEFINE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define HW_ENABLE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define HW_DISABLE 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* HARDWARE SWITCHING MODE DEFINE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define PLL_HOLDOVER 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define LOST_CLOCK 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* ALARMS DEFINE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define UNLOCK_MASK 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define HOLDOVER_MASK 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define SEC_LOST_MASK 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define PRI_LOST_MASK 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* INTERRUPT CAUSE DEFINE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define PRI_LOS_01_MASK 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define PRI_LOS_10_MASK 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define SEC_LOS_01_MASK 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define SEC_LOS_10_MASK 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define HOLDOVER_01_MASK 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define HOLDOVER_10_MASK 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define UNLOCK_01_MASK 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define UNLOCK_10_MASK 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct tlclk_alarms {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __u32 lost_clocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) __u32 lost_primary_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) __u32 lost_secondary_clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) __u32 primary_clock_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) __u32 secondary_clock_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) __u32 switchover_primary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) __u32 switchover_secondary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) __u32 pll_holdover;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __u32 pll_end_holdover;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) __u32 pll_lost_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) __u32 pll_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Telecom clock I/O register definition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define TLCLK_BASE 0xa08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define TLCLK_REG0 TLCLK_BASE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define TLCLK_REG1 (TLCLK_BASE+1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define TLCLK_REG2 (TLCLK_BASE+2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define TLCLK_REG3 (TLCLK_BASE+3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define TLCLK_REG4 (TLCLK_BASE+4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define TLCLK_REG5 (TLCLK_BASE+5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define TLCLK_REG6 (TLCLK_BASE+6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define TLCLK_REG7 (TLCLK_BASE+7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define SET_PORT_BITS(port, mask, val) outb(((inb(port) & mask) | val), port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* 0 = Dynamic allocation of the major device number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define TLCLK_MAJOR 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* sysfs interface definition:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) Upon loading the driver will create a sysfs directory under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /sys/devices/platform/telco_clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) This directory exports the following interfaces. There operation is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) documented in the MCPBL0010 TPS under the Telecom Clock API section, 11.4.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) alarms :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) current_ref :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) received_ref_clk3a :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) received_ref_clk3b :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) enable_clk3a_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) enable_clk3b_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) enable_clka0_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) enable_clka1_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) enable_clkb0_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) enable_clkb1_output :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) filter_select :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) hardware_switching :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) hardware_switching_mode :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) telclock_version :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) mode_select :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) refalign :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) reset :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) select_amcb1_transmit_clock :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) select_amcb2_transmit_clock :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) select_redundant_clock :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) select_ref_frequency :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) All sysfs interfaces are integers in hex format, i.e echo 99 > refalign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) has the same effect as echo 0x99 > refalign.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static unsigned int telclk_interrupt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int int_events; /* Event that generate a interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int got_event; /* if events processing have been done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static void switchover_timeout(struct timer_list *t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static struct timer_list switchover_timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static unsigned long tlclk_timer_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static struct tlclk_alarms *alarm_events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static DEFINE_SPINLOCK(event_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static int tlclk_major = TLCLK_MAJOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static DECLARE_WAIT_QUEUE_HEAD(wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static unsigned long useflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static DEFINE_MUTEX(tlclk_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static int tlclk_open(struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) mutex_lock(&tlclk_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (test_and_set_bit(0, &useflags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) result = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* this legacy device is always one per system and it doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * know how to handle multiple concurrent clients.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Make sure there is no interrupt pending while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * initialising interrupt handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) inb(TLCLK_REG6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* This device is wired through the FPGA IO space of the ATCA blade
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * we can't share this IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) result = request_irq(telclk_interrupt, &tlclk_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 0, "telco_clock", tlclk_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (result == -EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) inb(TLCLK_REG6); /* Clear interrupt events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) mutex_unlock(&tlclk_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static int tlclk_release(struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) free_irq(telclk_interrupt, tlclk_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) clear_bit(0, &useflags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) loff_t *f_pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (count < sizeof(struct tlclk_alarms))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (mutex_lock_interruptible(&tlclk_mutex))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) wait_event_interruptible(wq, got_event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) mutex_unlock(&tlclk_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) memset(alarm_events, 0, sizeof(struct tlclk_alarms));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) got_event = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) mutex_unlock(&tlclk_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return sizeof(struct tlclk_alarms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static const struct file_operations tlclk_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .read = tlclk_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .open = tlclk_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .release = tlclk_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static struct miscdevice tlclk_miscdev = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .minor = MISC_DYNAMIC_MINOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .name = "telco_clock",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .fops = &tlclk_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static ssize_t show_current_ref(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) unsigned long ret_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ret_val = ((inb(TLCLK_REG1) & 0x08) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return sprintf(buf, "0x%lX\n", ret_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static DEVICE_ATTR(current_ref, S_IRUGO, show_current_ref, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static ssize_t show_telclock_version(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) unsigned long ret_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) ret_val = inb(TLCLK_REG5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return sprintf(buf, "0x%lX\n", ret_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static DEVICE_ATTR(telclock_version, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) show_telclock_version, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static ssize_t show_alarms(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) unsigned long ret_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ret_val = (inb(TLCLK_REG2) & 0xf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return sprintf(buf, "0x%lX\n", ret_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static ssize_t store_received_ref_clk3a(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) dev_dbg(d, ": tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) SET_PORT_BITS(TLCLK_REG1, 0xef, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static DEVICE_ATTR(received_ref_clk3a, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) store_received_ref_clk3a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static ssize_t store_received_ref_clk3b(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) dev_dbg(d, ": tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) SET_PORT_BITS(TLCLK_REG1, 0xdf, val << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static DEVICE_ATTR(received_ref_clk3b, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) store_received_ref_clk3b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static ssize_t store_enable_clk3b_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) dev_dbg(d, ": tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) SET_PORT_BITS(TLCLK_REG3, 0x7f, val << 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static DEVICE_ATTR(enable_clk3b_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) store_enable_clk3b_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static ssize_t store_enable_clk3a_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) SET_PORT_BITS(TLCLK_REG3, 0xbf, val << 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static DEVICE_ATTR(enable_clk3a_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) store_enable_clk3a_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static ssize_t store_enable_clkb1_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) SET_PORT_BITS(TLCLK_REG2, 0xf7, val << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static DEVICE_ATTR(enable_clkb1_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) store_enable_clkb1_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static ssize_t store_enable_clka1_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) SET_PORT_BITS(TLCLK_REG2, 0xfb, val << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static DEVICE_ATTR(enable_clka1_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) store_enable_clka1_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static ssize_t store_enable_clkb0_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) SET_PORT_BITS(TLCLK_REG2, 0xfd, val << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static DEVICE_ATTR(enable_clkb0_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) store_enable_clkb0_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static ssize_t store_enable_clka0_output(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) SET_PORT_BITS(TLCLK_REG2, 0xfe, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static DEVICE_ATTR(enable_clka0_output, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) store_enable_clka0_output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static ssize_t store_select_amcb2_transmit_clock(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x28);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) } else if (val >= CLK_8_592MHz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x38);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) case CLK_8_592MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) case CLK_11_184MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) case CLK_34_368MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) case CLK_44_736MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) SET_PORT_BITS(TLCLK_REG3, 0xc7, val << 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static DEVICE_ATTR(select_amcb2_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) store_select_amcb2_transmit_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static ssize_t store_select_amcb1_transmit_clock(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if ((val == CLK_8kHz) || (val == CLK_16_384MHz)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) SET_PORT_BITS(TLCLK_REG1, 0xfb, ~val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) } else if (val >= CLK_8_592MHz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) case CLK_8_592MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) case CLK_11_184MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) case CLK_34_368MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) case CLK_44_736MHz:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) SET_PORT_BITS(TLCLK_REG3, 0xf8, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) static DEVICE_ATTR(select_amcb1_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) store_select_amcb1_transmit_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static ssize_t store_select_redundant_clock(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) SET_PORT_BITS(TLCLK_REG1, 0xfe, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) static DEVICE_ATTR(select_redundant_clock, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) store_select_redundant_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static ssize_t store_select_ref_frequency(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) SET_PORT_BITS(TLCLK_REG1, 0xfd, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static DEVICE_ATTR(select_ref_frequency, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) store_select_ref_frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static ssize_t store_filter_select(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) SET_PORT_BITS(TLCLK_REG0, 0xfb, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static DEVICE_ATTR(filter_select, (S_IWUSR|S_IWGRP), NULL, store_filter_select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static ssize_t store_hardware_switching_mode(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) SET_PORT_BITS(TLCLK_REG0, 0xbf, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static DEVICE_ATTR(hardware_switching_mode, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) store_hardware_switching_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) static ssize_t store_hardware_switching(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) SET_PORT_BITS(TLCLK_REG0, 0x7f, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static DEVICE_ATTR(hardware_switching, (S_IWUSR|S_IWGRP), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) store_hardware_switching);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) static ssize_t store_refalign (struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) SET_PORT_BITS(TLCLK_REG0, 0xf7, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) SET_PORT_BITS(TLCLK_REG0, 0xf7, 0x08);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) SET_PORT_BITS(TLCLK_REG0, 0xf7, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) static DEVICE_ATTR(refalign, (S_IWUSR|S_IWGRP), NULL, store_refalign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static ssize_t store_mode_select (struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) SET_PORT_BITS(TLCLK_REG0, 0xcf, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) static DEVICE_ATTR(mode_select, (S_IWUSR|S_IWGRP), NULL, store_mode_select);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static ssize_t store_reset (struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) sscanf(buf, "%lX", &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) dev_dbg(d, "tmp = 0x%lX\n", tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) val = (unsigned char)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) SET_PORT_BITS(TLCLK_REG4, 0xfd, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) return strnlen(buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) static DEVICE_ATTR(reset, (S_IWUSR|S_IWGRP), NULL, store_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) static struct attribute *tlclk_sysfs_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) &dev_attr_current_ref.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) &dev_attr_telclock_version.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) &dev_attr_alarms.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) &dev_attr_received_ref_clk3a.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) &dev_attr_received_ref_clk3b.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) &dev_attr_enable_clk3a_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) &dev_attr_enable_clk3b_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) &dev_attr_enable_clkb1_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) &dev_attr_enable_clka1_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) &dev_attr_enable_clkb0_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) &dev_attr_enable_clka0_output.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) &dev_attr_select_amcb1_transmit_clock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) &dev_attr_select_amcb2_transmit_clock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) &dev_attr_select_redundant_clock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) &dev_attr_select_ref_frequency.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) &dev_attr_filter_select.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) &dev_attr_hardware_switching_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) &dev_attr_hardware_switching.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) &dev_attr_refalign.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) &dev_attr_mode_select.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) &dev_attr_reset.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) static const struct attribute_group tlclk_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) .name = NULL, /* put in device directory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) .attrs = tlclk_sysfs_entries,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) static struct platform_device *tlclk_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) static int __init tlclk_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) telclk_interrupt = (inb(TLCLK_REG7) & 0x0f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (!alarm_events) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) goto out1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) kfree(alarm_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) tlclk_major = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) /* Read telecom clock IRQ number (Set by BIOS) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) printk(KERN_ERR "tlclk: request_region 0x%X failed.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) TLCLK_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) goto out2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) printk(KERN_ERR "telclk_interrupt = 0x%x non-mcpbl0010 hw.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) telclk_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) goto out3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) timer_setup(&switchover_timer, switchover_timeout, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) ret = misc_register(&tlclk_miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) goto out3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) tlclk_device = platform_device_register_simple("telco_clock",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) -1, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (IS_ERR(tlclk_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) printk(KERN_ERR "tlclk: platform_device_register failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) ret = PTR_ERR(tlclk_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) goto out4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) ret = sysfs_create_group(&tlclk_device->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) &tlclk_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) printk(KERN_ERR "tlclk: failed to create sysfs device attributes.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) goto out5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) out5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) platform_device_unregister(tlclk_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) out4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) misc_deregister(&tlclk_miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) out3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) release_region(TLCLK_BASE, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) out2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) kfree(alarm_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) unregister_chrdev(tlclk_major, "telco_clock");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) out1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static void __exit tlclk_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) sysfs_remove_group(&tlclk_device->dev.kobj, &tlclk_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) platform_device_unregister(tlclk_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) misc_deregister(&tlclk_miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) unregister_chrdev(tlclk_major, "telco_clock");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) release_region(TLCLK_BASE, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) del_timer_sync(&switchover_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) kfree(alarm_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static void switchover_timeout(struct timer_list *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) unsigned long flags = tlclk_timer_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if ((flags & 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) alarm_events->switchover_primary++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) alarm_events->switchover_secondary++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) /* Alarm processing is done, wake up read task */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) del_timer(&switchover_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) got_event = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) wake_up(&wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) spin_lock_irqsave(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) /* Read and clear interrupt events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) int_events = inb(TLCLK_REG6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) /* Primary_Los changed from 0 to 1 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (int_events & PRI_LOS_01_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (inb(TLCLK_REG2) & SEC_LOST_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) alarm_events->lost_clocks++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) alarm_events->lost_primary_clock++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) /* Primary_Los changed from 1 to 0 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (int_events & PRI_LOS_10_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) alarm_events->primary_clock_back++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) SET_PORT_BITS(TLCLK_REG1, 0xFE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) /* Secondary_Los changed from 0 to 1 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (int_events & SEC_LOS_01_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) if (inb(TLCLK_REG2) & PRI_LOST_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) alarm_events->lost_clocks++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) alarm_events->lost_secondary_clock++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) /* Secondary_Los changed from 1 to 0 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (int_events & SEC_LOS_10_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) alarm_events->secondary_clock_back++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) SET_PORT_BITS(TLCLK_REG1, 0xFE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (int_events & HOLDOVER_10_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) alarm_events->pll_end_holdover++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) if (int_events & UNLOCK_01_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) alarm_events->pll_lost_sync++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if (int_events & UNLOCK_10_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) alarm_events->pll_sync++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) /* Holdover changed from 0 to 1 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (int_events & HOLDOVER_01_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) alarm_events->pll_holdover++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /* TIMEOUT in ~10ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) switchover_timer.expires = jiffies + msecs_to_jiffies(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) tlclk_timer_data = inb(TLCLK_REG1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) mod_timer(&switchover_timer, switchover_timer.expires);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) got_event = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) wake_up(&wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) spin_unlock_irqrestore(&event_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) module_init(tlclk_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) module_exit(tlclk_cleanup);