11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atmdev.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sonet.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
1460063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "uPD98402.h"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(format,args...)
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uPD98402_priv {
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct k_sonet_stats sonet_stats;/* link diagnostics */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char framing;		/* SONET/SDH framing */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int loop_mode;			/* loopback mode */
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg)
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sonet_stats tmp;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	int error = 0;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (zero && !error) {
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* unused fields are reported as -1, but we must not "adjust"
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   them */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error ? -EFAULT : 0;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_framing(struct atm_dev *dev,unsigned char framing)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static const unsigned char sonet[] = { 1,2,3,0 };
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static const unsigned char sdh[] = { 1,0,0,2 };
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *set;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (framing) {
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_FRAME_SONET:
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set = sonet;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_FRAME_SDH:
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set = sdh;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&PRIV(dev)->lock, flags);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(set[0],C11T);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(set[1],C12T);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(set[2],C13T);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] <<
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    uPD98402_MDR_SS_SHIFT),MDR);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&PRIV(dev)->lock, flags);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_sense(struct atm_dev *dev,u8 __user *arg)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char s[3];
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&PRIV(dev)->lock, flags);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s[0] = GET(C11R);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s[1] = GET(C12R);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s[2] = GET(C13R);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&PRIV(dev)->lock, flags);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_loopback(struct atm_dev *dev,int mode)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char mode_reg;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    uPD98402_MDR_RPLP);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (__ATM_LM_XTLOC(mode)) {
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __ATM_LM_NONE:
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __ATM_LM_PHY:
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode_reg |= uPD98402_MDR_TPLP;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __ATM_LM_ATM:
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode_reg |= uPD98402_MDR_ALP;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (__ATM_LM_XTRMT(mode)) {
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __ATM_LM_NONE:
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __ATM_LM_PHY:
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode_reg |= uPD98402_MDR_RPLP;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(mode_reg,MDR);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PRIV(dev)->loop_mode = mode;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_GETSTATZ:
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                case SONET_GETSTAT:
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return fetch_stats(dev,arg, cmd == SONET_GETSTATZ);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_SETFRAMING:
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return set_framing(dev, (int)(unsigned long)arg);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_GETFRAMING:
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return put_user(PRIV(dev)->framing,(int __user *)arg) ?
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    -EFAULT : 0;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SONET_GETFRSENSE:
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return get_sense(dev,arg);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case ATM_SETLOOP:
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return set_loopback(dev, (int)(unsigned long)arg);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case ATM_GETLOOP:
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ?
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    -EFAULT : 0;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case ATM_QUERYLOOP:
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    ATM_LM_RMT_PHY,(int __user *)arg) ? -EFAULT : 0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOIOCTLCMD;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ADD_LIMITED(s,v) \
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void stat_event(struct atm_dev *dev)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char events;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	events = GET(PCR);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ADD_LIMITED
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void uPD98402_int(struct atm_dev *dev)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned long silence = 0;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char reason;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((reason = GET(PICR))) {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reason & uPD98402_INT_LOS)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_NOTICE "%s(itf %d): signal lost\n",
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dev->type,dev->number);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reason & uPD98402_INT_PFM) stat_event(dev);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reason & uPD98402_INT_PCO) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(void) GET(PCOCR); /* clear interrupt cause */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			atomic_add(GET(HECCT),
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    &PRIV(dev)->sonet_stats.uncorr_hcs);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((reason & uPD98402_INT_RFO) &&
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (time_after(jiffies, silence) || silence == 0)) {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "%s(itf %d): uPD98402 receive "
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    "FIFO overflow\n",dev->type,dev->number);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			silence = (jiffies+HZ/2)|1;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uPD98402_start(struct atm_dev *dev)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("phy_start\n");
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->dev_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&PRIV(dev)->lock);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) GET(PCR); /* clear performance events */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) GET(PCOCR); /* clear overflows */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(~uPD98402_PCO_HECC,PCOMR);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) GET(PICR); /* clear interrupts */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  uPD98402_INT_LOS),PIMR); /* enable them */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int uPD98402_stop(struct atm_dev *dev)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* let SAR driver worry about stopping interrupts */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(PRIV(dev));
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct atmphy_ops uPD98402_ops = {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start		= uPD98402_start,
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl		= uPD98402_ioctl,
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.interrupt	= uPD98402_int,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop		= uPD98402_stop,
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint uPD98402_init(struct atm_dev *dev)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDPRINTK("phy_init\n");
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->phy = &uPD98402_ops;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(uPD98402_init);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __init int uPD98402_module_init(void)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(uPD98402_module_init);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* module_exit not defined so not unloadable */
266