Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);