1
/*******************************************************************************
2
Copyright (C) Marvell International Ltd. and its affiliates
4
This software file (the "File") is owned and distributed by Marvell
5
International Ltd. and/or its affiliates ("Marvell") under the following
6
alternative licensing terms. Once you have made an election to distribute the
7
File under one of the following license alternatives, please (i) delete this
8
introductory statement regarding license alternatives, (ii) delete the two
9
license alternatives that you have not elected to use and (iii) preserve the
10
Marvell copyright notice above.
12
********************************************************************************
13
Marvell Commercial License Option
15
If you received this File from Marvell and you have entered into a commercial
16
license agreement (a "Commercial License") with Marvell, the File is licensed
17
to you under the terms of the applicable Commercial License.
19
********************************************************************************
20
Marvell GPL License Option
22
If you received this File from Marvell, you may opt to use, redistribute and/or
23
modify this File in accordance with the terms and conditions of the General
24
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
25
available along with the File in the license.txt file or by writing to the Free
26
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
27
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
29
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
30
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
31
DISCLAIMED. The GPL License provides additional details about this warranty
33
********************************************************************************
34
Marvell BSD License Option
36
If you received this File from Marvell, you may opt to use, redistribute and/or
37
modify this File under the following licensing terms.
38
Redistribution and use in source and binary forms, with or without modification,
39
are permitted provided that the following conditions are met:
41
* Redistributions of source code must retain the above copyright notice,
42
this list of conditions and the following disclaimer.
44
* Redistributions in binary form must reproduce the above copyright
45
notice, this list of conditions and the following disclaimer in the
46
documentation and/or other materials provided with the distribution.
48
* Neither the name of Marvell nor the names of its contributors may be
49
used to endorse or promote products derived from this software without
50
specific prior written permission.
52
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63
******************************************************************************/
65
#include <linux/kernel.h>
66
#include <linux/module.h>
67
#include <linux/init.h>
68
#include <linux/sched.h>
69
#include <linux/telephony.h>
70
#include <linux/phonedev.h>
71
#include <linux/interrupt.h>
72
#include <linux/delay.h>
73
#include <linux/poll.h>
74
#include "gpp/mvGpp.h"
77
extern MV_U8 currRxSampleGet(MV_U8 ch);
78
extern MV_U8 currTxSampleGet(MV_U8 ch);
79
extern u32 mvVoiceIfType;
82
#ifdef CONFIG_MV_GTW_QOS
83
extern int mv_gtw_qos_tos_enable(void);
84
extern int mv_gtw_qos_tos_disable(void);
88
/***********************
89
* PHONE DRIVER'S STUFF *
90
***********************/
92
struct phone_device p;
94
unsigned int slic_dev;
98
unsigned char exception;
100
wait_queue_head_t poll_q;
101
wait_queue_head_t read_q;
102
wait_queue_head_t write_q;
103
MV_VOICE_IF_TYPE chType;
104
int cs; /* for daisy chain */
105
unsigned char rxActive, txActive, started;
108
static MV_PHONE mv_phone[MV_TDM_MAX_CHANNELS];
109
static char *cmdline = "dev0:fxs,dev1:fxs";
110
static int work_mode = DAISY_CHAIN_MODE;
111
static int interrupt_mode = INTERRUPT_TO_TDM;
112
static struct class *phone_class;
113
#define get_mp(ch) (&mv_phone[ch])
117
/* Forward declarations */
118
static int __init mp_init(void);
119
static void __exit mp_exit(void);
120
static int mp_open(struct phone_device *pdev, struct file *file_p);
121
static int mp_close(struct inode *inode, struct file *file_p);
122
static ssize_t mp_read(struct file * file_p, char __user *buf, size_t length, loff_t * ppos);
123
static ssize_t mp_write(struct file *file_p, const char __user *buf, size_t count, loff_t * ppos);
124
static unsigned int mp_poll(struct file *file_p, poll_table * wait);
125
static int mp_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, unsigned long arg);
126
static irqreturn_t mp_int_handler(int irq, void *dev_id);
127
static void mp_spi_write(unsigned char addr, unsigned char data, MV_PHONE *mp);
128
static void mp_spi_read(unsigned char addr, unsigned char *data, MV_PHONE *mp);
129
static int slicRingBackTone(unsigned int slicDev);
130
static int slicEventGet(unsigned char *offhook, MV_PHONE *mp);
131
static int slicBusyTone(unsigned int slicDev);
132
static void slicSetLineFeedControl(unsigned char val, unsigned int slicDev);
133
static void slicReversDcPolarity(unsigned int slicDev);
134
static int slicSpiTest(unsigned int loop, MV_PHONE *mp);
135
static int fxdevInterruptBits(unsigned char ch, MV_PHONE *mp);
136
static int mp_get_int(unsigned int* work_done);
137
static int mp_cmdline_config(char *s);
138
static int mp_parse_config(int ifNum);
139
static int mp_check_config(void);
147
module_init(mp_init);
148
module_exit(mp_exit);
149
MODULE_DESCRIPTION("Marvell Telephony Device Driver - www.marvell.com");
150
MODULE_AUTHOR("Tzachi Perelstein <tzachi@marvell.com>");
151
MODULE_LICENSE("GPL");
153
/* Driver's operations */
154
static struct file_operations mp_fops =
156
.owner = THIS_MODULE,
166
static int mp_parse_config(int ifNum)
169
int size = 3, i = 0, offset;
170
offset = BASE_ENV_PARAM_OFF + (DEV_ENV_PARAM_OFF * ifNum); /* start of requested type in cmdline */
172
if(ifNum < MV_TDM_MAX_CHANNELS)
175
type[i++] = cmdline[offset++];
177
if(!strcmp(type,"fxs"))
179
else if(!strcmp(type,"fxo"))
185
static int mp_cmdline_config(char *s)
191
__setup("mv_phone_config=", mp_cmdline_config);
194
static int mp_check_config(void)
197
#if defined(CONFIG_ARCH_FEROCEON_ORION)
200
boardId = mvBoardIdGet();
202
/* print board detection info */
204
case RD_88F5181L_VOIP_GE:
205
printk("Detected RD_88F5181L_VOIP_GE\n");
206
work_mode = DAISY_CHAIN_MODE;
207
interrupt_mode = INTERRUPT_TO_TDM;
210
case RD_88F5181L_VOIP_FE:
211
printk("Detected RD_88F5181L_VOIP_FE\n");
212
work_mode = DAISY_CHAIN_MODE;
213
interrupt_mode = INTERRUPT_TO_TDM;
215
case DB_88F5181L_DDR2_2XTDM:
216
printk("Detected DB_88F5181L_DDR2_2XTDM\n");
217
work_mode = DUAL_CHIP_SELECT_MODE;
218
interrupt_mode = INTERRUPT_TO_MPP;
222
case RD_88F5181L_VOIP_FXO_GE:
223
printk("Detected RD_88F5181L_VOIP_FXO_GE\n");
224
work_mode = DUAL_CHIP_SELECT_MODE;
225
interrupt_mode = INTERRUPT_TO_TDM;
227
/* set life line control mpp */
228
/*mvGppValueSet(0, MV_GPP11, MV_GPP11);*/
232
printk("Error, platform does not support telephony\n");
235
#elif defined(CONFIG_ARCH_FEROCEON_KW)
236
work_mode = DUAL_CHIP_SELECT_MODE;
237
interrupt_mode = INTERRUPT_TO_TDM;
238
mvBoardTdmLifeLineSet();
245
static int __init mp_init(void)
254
printk("Marvell Telephony Driver:\n");
256
if (MV_FALSE == mvCtrlPwrClckGet(TDM_UNIT_ID, 0))
258
printk("\nWarning Tdm is Powered Off\n");
262
/* check system configuration */
263
if(MV_ERROR == mp_check_config())
266
TRC_INIT(currRxSampleGet, currTxSampleGet, 0, 0);
267
TRC_REC("->%s\n",__FUNCTION__);
269
/* General TDM and SLIC init */
270
TRC_REC("tdm init\n");
271
mvTdmInit(work_mode, interrupt_mode);
272
mvTdmShowProperties();
274
phone_class = class_create(THIS_MODULE, "telephony");
275
if (IS_ERR(phone_class))
277
err = PTR_ERR(phone_class);
281
/* per channel init */
282
for(i=0; i<MV_TDM_MAX_CHANNELS; i++)
284
printk("Initializing channel %d\n",i);
285
TRC_REC("ch%d init\n",i);
287
mp->chType = mp_parse_config(i);
288
if(mp->chType == MV_ERROR)
290
printk("%s: error, unknown device type (check u-boot config)\n",__FUNCTION__);
293
#ifdef CONFIG_ARCH_FEROCEON_ORION
294
if((mvBoardIdGet() == RD_88F5181L_VOIP_FXO_GE) && (i != 0)) {
295
mpp0 = MV_REG_READ(MPP_CONTROL_REG0);
298
if(mp->chType == MV_FXO)
301
mvGppValueSet(0, MV_GPP3, MV_GPP3); /* reset daa */
302
mvGppValueSet(0, MV_GPP3, 0);
306
mvGppValueSet(0, MV_GPP3, 0); /* reset slic */
307
mvGppValueSet(0, MV_GPP3, MV_GPP3);
311
printk("Unit Type: %s\n",mp->chType == MV_FXO ? "FXO":"FXS");
312
mp->p.board = mp->ch = i;
313
mp->p.f_op = &mp_fops;
314
mp->p.open = mp_open;
317
if(interrupt_mode == INTERRUPT_TO_MPP)
319
mp->irq = mvBoardSlicGpioPinGet(i) + IRQ_GPP_START;
324
init_waitqueue_head(&mp->poll_q);
325
init_waitqueue_head(&mp->read_q);
326
init_waitqueue_head(&mp->write_q);
328
if(mvTdmChInit(&mp->p, i, &(mp->ch_info), mp->chType) == MV_OK)
336
printk("mvTdmChInit() failed !\n");
340
if(mp->chType == MV_FXS)
341
retval = initSlic(&(mp->slic_dev), mp->ch, work_mode, interrupt_mode);
343
retval = initDaa(&(mp->daa_dev), mp->ch, work_mode, interrupt_mode);
346
phone_register_device(&mp->p, PHONE_UNIT_ANY);
347
printk("phone%d registered\n",i);
350
printk("%s: Unable to initialize %s-%d\n",__FUNCTION__, mp->chType == 0 ? "FXO":"FXS", i);
352
sprintf(dev_name, "phone%d", unit);
353
device_create(phone_class, NULL, MKDEV(PHONE_MAJOR, unit), dev_name);
357
if (request_irq(MP_IRQ, mp_int_handler, IRQF_SHARED | IRQF_DISABLED, "mv-phone", &mv_phone[0])) {
358
printk("Failed to connect IRQ %d\n", MP_IRQ);
363
if(interrupt_mode == INTERRUPT_TO_MPP)
366
if (request_irq(mp->irq, mp_int_handler, IRQF_DISABLED, "mv-voice0", (&mv_phone[0])+1)) {
367
printk("Failed to connect IRQ %d\n", mp->irq);
372
if (request_irq(mp->irq, mp_int_handler, IRQF_DISABLED, "mv-voice1", (&mv_phone[0])+2)) {
373
printk("Failed to connect IRQ %d\n", mp->irq);
380
TRC_REC("<-%s\n",__FUNCTION__);
384
static void __exit mp_exit(void)
389
TRC_REC("->%s\n",__FUNCTION__);
391
free_irq(MP_IRQ, &mv_phone[0]);
392
TRC_REC("free irq %d\n",MP_IRQ);
394
for(i=0; i<MV_TDM_MAX_CHANNELS; i++) {
395
TRC_REC("ch%d remove\n",i);
397
mvTdmChRemove(mp->ch_info);
399
if(interrupt_mode == INTERRUPT_TO_MPP) {
400
free_irq(mp->irq, (&mv_phone[0]) + i + 1);
401
TRC_REC("free irq %d\n",mp->irq);
404
if(mp->chType == MV_FXS)
405
slicFreeChannel(mp->slic_dev);
407
daaFreeChannel(mp->daa_dev);
412
phone_unregister_device(&mp->p);
413
printk("phone%d removed\n",i);
416
TRC_REC("<-%s\n",__FUNCTION__);
421
static int mp_open(struct phone_device *p, struct file *file_p)
424
MV_PHONE *mp = get_mp(p->board);
426
file_p->private_data = mp;
428
printk("Opening phone channel %d - \n",mp->ch);
429
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
431
if (file_p->f_mode & FMODE_READ) {
436
printk("device is busy (read)\n");
441
if (file_p->f_mode & FMODE_WRITE) {
446
if (file_p->f_mode & FMODE_READ) {
449
printk("device is busy (write)\n");
454
/* enable FXO/FXS interrupts */
455
if(mp->chType == MV_FXS)
456
enableSlicInterrupts(mp->slic_dev);
458
enableDaaInterrupts(mp->daa_dev);
460
for (i = 0; i < MV_TDM_MAX_CHANNELS; i++)
470
MV_REG_WRITE(INT_STATUS_REG,0);
471
MV_REG_WRITE(INT_STATUS_MASK_REG,TDM_INT_SLIC);
477
if(mvTdmChStart(mp->ch_info) == MV_OK)
478
mp->rxActive = mp->txActive = 0;
480
printk("mvTdmChStart() failed !\n");
482
TRC_REC("<-%s\n",__FUNCTION__);
486
static int mp_close(struct inode *inode, struct file *file_p)
488
MV_PHONE *mp = file_p->private_data;
489
int i, stillRunning = 0;
492
printk("Closing Marvell phone%d device\n",mp->ch);
493
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
502
/* Clear cause and disable all interrupts */
504
TRC_REC("disable all ch%d interrupts\n",mp->ch);
505
for (i = 0; i < MV_TDM_MAX_CHANNELS; i++)
515
MV_REG_WRITE(INT_STATUS_MASK_REG,0);
516
MV_REG_WRITE(INT_STATUS_REG,0);
520
if(mvTdmChStop(mp->ch_info) == MV_OK)
521
mp->rxActive = mp->txActive = 0;
523
printk("mvTdmChStop() failed !\n");
526
/* disable FXO/FXS interrupts */
527
if(mp->chType == MV_FXS)
528
disableSlicInterrupts(mp->slic_dev);
530
disableDaaInterrupts(mp->daa_dev);
533
wake_up_interruptible(&mp->poll_q);
534
wake_up_interruptible(&mp->read_q);
535
wake_up_interruptible(&mp->write_q);
537
if (file_p->f_mode & FMODE_READ)
539
if (file_p->f_mode & FMODE_WRITE)
542
file_p->private_data = NULL;
544
TRC_REC("<-%s\n",__FUNCTION__);
549
static ssize_t mp_read(struct file * file_p, char __user *buf, size_t length, loff_t * ppos)
553
unsigned long count = 0;
554
unsigned int err = 0;
555
MV_PHONE *mp = file_p->private_data;
557
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
560
count = min(length, (size_t)MV_TDM_BUFF_SIZE);
564
status = mvTdmChRx(mp->ch_info, buf, count);
567
TRC_REC("rx is not active!\n");
568
status = MV_NOT_READY;
571
if (status == MV_NOT_READY)
573
if (file_p->f_flags & O_NONBLOCK)
575
TRC_REC("read not ready, try again\n");
585
interruptible_sleep_on(&mp->read_q);
586
if (signal_pending(current))
599
else if(status == MV_FAIL) {
600
TRC_REC("copy to user failed\n");
601
printk("%s: copy to user failed\n", __FUNCTION__);
605
TRC_REC("copy to user %dB ok\n",count);
608
} while (status == MV_NOT_READY);
610
TRC_REC("<-%s\n",__FUNCTION__);
611
return (err)?err:count;
614
static ssize_t mp_write(struct file *file_p, const char __user *buf, size_t length, loff_t * ppos)
618
unsigned long count = 0;
620
MV_PHONE *mp = file_p->private_data;
622
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
625
count = min(length, (size_t)MV_TDM_BUFF_SIZE);
630
status = mvTdmChTx(mp->ch_info, (MV_U8 *)buf, count);
633
TRC_REC("tx is not active!\n");
634
status = MV_NOT_READY;
637
if (status == MV_NOT_READY)
639
if (file_p->f_flags & O_NONBLOCK)
641
TRC_REC("write not ready, try again\n");
650
interruptible_sleep_on(&mp->write_q);
651
if (signal_pending(current))
663
else if(status == MV_FAIL) {
664
TRC_REC("copy from user failed\n");
665
printk("%s: copy from user failed\n",__FUNCTION__);
669
TRC_REC("copy from user %dB ok\n",count);
672
} while (status == MV_NOT_READY);
673
TRC_REC("<-%s\n",__FUNCTION__);
674
return (err)?err:count;
677
static unsigned int mp_poll(struct file *file_p, poll_table * wait)
680
unsigned int mask = 0;
681
MV_PHONE *mp = file_p->private_data;
683
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
685
poll_wait(file_p, &(mp->poll_q), wait);
689
if(mvTdmChRxReady(mp->ch_info)) {
690
mask |= POLLIN | POLLRDNORM; /* readable */
691
TRC_REC("poll can read\n");
696
if(mvTdmChTxReady(mp->ch_info)) {
697
mask |= POLLOUT | POLLWRNORM; /* writable */
698
TRC_REC("poll can write\n");
701
if(mp->exception == EXCEPTION_ON) {
702
mask |= POLLPRI; /* events */
703
TRC_REC("poll can get event\n");
708
TRC_REC("<-%s\n",__FUNCTION__);
712
static int mp_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, unsigned long arg)
716
MV_PHONE *mp = get_mp(iminor(inode) & 0xf);
718
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
720
/* check ioctls only root can use */
721
if (!capable(CAP_SYS_ADMIN)) {
727
if(interrupt_mode == INTERRUPT_TO_MPP)
728
disable_irq(mp->irq);
732
#ifdef CONFIG_MV_GTW_QOS
733
if(cmd == PHONE_REC_START || cmd == PHONE_PLAY_START) {
734
mv_gtw_qos_tos_enable();
736
if(cmd == PHONE_REC_STOP || cmd == PHONE_PLAY_STOP) {
737
mv_gtw_qos_tos_disable();
742
case PHONE_REC_START:
743
TRC_REC("PHONE_REC_START\n");
746
if(mvTdmChRxEnable(mp->ch_info) ==MV_OK)
748
else TRC_REC("failed\n");
750
TRC_REC("rec already active\n");
753
TRC_REC("PHONE_REC_STOP\n");
756
wake_up_interruptible(&mp->read_q);
758
case PHONE_PLAY_START:
759
TRC_REC("PHONE_PLAY_START\n");
762
if(mvTdmChTxEnable(mp->ch_info) == MV_OK)
764
else TRC_REC("failed\n");
766
TRC_REC("play already active\n");
768
case PHONE_PLAY_STOP:
769
TRC_REC("PHONE_PLAY_STOP\n");
772
wake_up_interruptible(&mp->write_q);
774
case PHONE_EXCEPTION:
776
union telephony_exception ex;
777
TRC_REC("PHONE_EXCEPTION\n");
779
if(mp->chType == MV_FXS)
782
slicEventGet(&offhook, mp);
784
TRC_REC("off hook\n");
785
ex.bits.hookstate = 1;
788
TRC_REC("on hook\n");
793
daaEventTypeGet(&eventType, mp->daa_dev);
794
mp->exception = EXCEPTION_OFF;
797
TRC_REC("Ring Detected\n");
798
ex.bits.pstn_ring = 1;
802
TRC_REC("Reverse Polarity Detected\n");
803
ex.bits.reverse_polarity = 1;
808
TRC_REC("Drop Out Detected\n");
809
ex.bits.drop_out = 1;
817
case PHONE_PSTN_SET_STATE:
818
TRC_REC("PHONE_PSTN_SET_STATE\n");
819
setPstnState(arg, mp->daa_dev);
821
case PHONE_SET_CID_STATE:
822
TRC_REC("PHONE_SET_CID_STATE\n");
823
setDaaCidState(arg, mp->daa_dev);
825
case PHONE_SET_REVERSE_POLARITY:
826
TRC_REC("PHONE_SET_REVERSE_POLARITY\n");
827
enableDaaReveresePolarity(arg, mp->daa_dev);
829
case PHONE_SET_DIGITAL_HYBRID:
830
TRC_REC("PHONE_SET_DIGITAL_HYBRID\n");
831
setDaaDigitalHybrid((unsigned int)arg, mp->daa_dev);
833
case PHONE_GET_LINE_VOLTAGE:
834
TRC_REC("PHONE_GET_LINE_VOLTAGE\n");
835
retval = daaGetLineVoltage(mp->daa_dev);
838
TRC_REC("PHONE_DIALTONE\n");
839
dialTone(mp->slic_dev);
842
TRC_REC("PHONE_BUSY\n");
843
slicBusyTone(mp->slic_dev);
846
TRC_REC("PHONE_CPT_STOP\n");
847
stopTone(mp->slic_dev);
849
case PHONE_RING_START:
850
TRC_REC("PHONE_RING_START\n");
851
activateRinging(mp->slic_dev);
853
case PHONE_RING_STOP:
854
TRC_REC("PHONE_RING_STOP\n");
855
stopRinging(mp->slic_dev);
857
case PHONE_RING_CADENCE:
858
TRC_REC("PHONE_RING_CADENCE\n");
859
slicRingCadence(arg, mp->slic_dev);
862
TRC_REC("PHONE_RINGBACK\n");
863
slicRingBackTone(mp->slic_dev);
865
case PHONE_PSTN_REVERSE_POLARITY: /* Timor */
866
TRC_REC("PHONE_PSTN_REVERSE_POLARITY\n");
867
slicReversDcPolarity(mp->slic_dev);
869
case PHONE_PSTN_SEND_NTT_CRA: /* Timor */
870
TRC_REC("PHONE_PSTN_SEND_NTT_CRA\n");
871
slicSendNTTCRATone(mp->slic_dev);
874
case PHONE_SET_LINE_FEED_CONTROL: /* Timor */
875
TRC_REC("PHONE_SET_LINE_FEED_CONTROL\n");
876
slicSetLineFeedControl((unsigned char)arg, mp->slic_dev);
879
case PHONE_MV_READ_SLIC_REG:
882
mp_spi_read(arg, (MV_U8*)&retval, mp);
884
printk("Driver is not configured to support this IOCTL\n");
888
case PHONE_MV_WRITE_SLIC_REG:
891
mp_spi_write((arg>>16)&0xff,arg&0xff, mp);
893
printk("Driver is not configured to support this IOCTL\n");
897
case PHONE_MV_READ_REG:
899
retval = *((unsigned int*)(0xf1000000|arg));
901
printk("Driver is not configured to support this IOCTL\n");
905
case PHONE_MV_WRITE_REG:
907
printk("not implemented yet\n");
909
printk("Driver is not configured to support this IOCTL\n");
913
case PHONE_MV_SPI_TEST:
915
slicSpiTest(10000, mp);
917
printk("Driver is not configured to support this IOCTL\n");
922
printk("mv_phone %s: unsupported IOCTL\n",__FUNCTION__);
925
TRC_REC("<-%s\n",__FUNCTION__);
928
if(interrupt_mode == INTERRUPT_TO_MPP)
937
** Two types of interrupts exists:
938
** (1) FXS/FXO async event (e.g. on/off-hook).
939
** (2) TDM sync 10ms event (data is ready for read+write)
941
static irqreturn_t mp_int_handler(int irq, void *dev_id)
943
MV_U32 work_done = 0;
945
MV_U8 wake_up_poll_q;
947
TRC_REC("->->->%s\n",__FUNCTION__);
948
if (!mp_get_int(&work_done))
950
for (i = 0; i < MV_TDM_MAX_CHANNELS; i++)
953
if (work_done & (MV_TDM_SLIC_INTR << MV_CHANNEL_INTR(i)))
955
TRC_REC("wake up for ex\n");
958
if (work_done & (MV_TDM_READ_INTR << MV_CHANNEL_INTR(i)))
961
TRC_REC("wake up for rd\n");
962
wake_up_interruptible(&mv_phone[i].read_q);
964
if (work_done & (MV_TDM_WRITE_INTR << MV_CHANNEL_INTR(i)))
967
TRC_REC("wake up for wr\n");
968
wake_up_interruptible(&mv_phone[i].write_q);
970
if (wake_up_poll_q) {
971
TRC_REC("wake up poll\n");
972
wake_up_interruptible(&mv_phone[i].poll_q);
976
TRC_REC("<-%s\n",__FUNCTION__);
980
static void mp_spi_write(unsigned char addr, unsigned char data, MV_PHONE *mp)
982
if(mp->chType == MV_FXS)
983
writeDirectReg(mp->slic_dev, addr, data);
985
writeDaaDirectReg(mp->daa_dev, addr, data);
990
static void mp_spi_read(unsigned char addr, unsigned char *data, MV_PHONE *mp)
992
if(mp->chType == MV_FXS)
993
*data = readDirectReg(mp->slic_dev, addr);
995
*data = readDaaDirectReg(mp->daa_dev, addr);
1000
static int slicEventGet(unsigned char *offhook, MV_PHONE *mp)
1005
TRC_REC("->%s ch%d\n",__FUNCTION__,mp->ch);
1008
mp_spi_read(68, &tmp, mp);
1010
/* hook state (0-on, 1-off) */
1011
*offhook = !(tmp & 4);
1014
TRC_REC("off-hook\n");
1016
TRC_REC("on-hook\n");
1017
mp->exception = EXCEPTION_OFF;
1018
TRC_REC("<-%s\n",__FUNCTION__);
1022
static int slicBusyTone(unsigned int slicDev)
1028
busyJapanTone(slicDev);
1034
static int slicRingBackTone(unsigned int slicDev)
1037
ringBackTone(slicDev);
1039
ringBackJapanTone(slicDev);
1044
static void slicSetLineFeedControl(unsigned char val, unsigned int slicDev) /* Timor */
1046
writeDirectReg(slicDev, LINE_STATE, val);
1050
static void slicReversDcPolarity(unsigned int slicDev) /* Timor */
1053
/* read value of On-Hook Line Voltage register */
1054
data = readDirectReg(slicDev, OFF_HOOK_V);
1055
/* toggle the VSGN bit - VTIPVRING polarity */
1056
writeDirectReg(slicDev, OFF_HOOK_V, data^0x40);
1061
static int slicSpiTest(unsigned int loop, MV_PHONE *mp)
1067
for(ch=0; ch<MV_TDM_MAX_CHANNELS; ch++)
1070
/*mvTdmSetCurrentUnit(mp->cs);*/
1071
printk("SPI channel %d Write/Read test %d loops... ",mp->ch,loop);
1077
mp_spi_write(2, w, mp);
1078
mp_spi_read(2, &r, mp);
1081
printk("SPI: Wrote %x, Read = %x ",w,r);
1098
static int mp_get_int(unsigned int *work_done)
1101
unsigned int cause, gppDataIn = 0, isFxInterrupt = 0;
1104
/* Read and clear cause */
1105
cause = MV_REG_READ(INT_STATUS_REG);
1106
MV_REG_WRITE(INT_STATUS_REG, ~cause);
1108
if(interrupt_mode == INTERRUPT_TO_MPP) {
1109
gppDataIn = MV_REG_READ(GPP_DATA_IN_REG(0));
1110
TRC_REC("->%s gppcause=0x%x\n",__FUNCTION__, gppDataIn);
1113
TRC_REC("->%s tdmcause=0x%x mask=0x%x\n",__FUNCTION__, cause, MV_REG_READ(INT_STATUS_MASK_REG));
1117
/* Refer only to unmasked bits */
1118
cause &= (MV_REG_READ(INT_STATUS_MASK_REG));
1119
isFxInterrupt = ((interrupt_mode == INTERRUPT_TO_MPP) ? (gppDataIn & (BIT8 | BIT9)) : (cause & SLIC_INT_BIT)) ;
1123
for (ch=0; ch<MV_TDM_MAX_CHANNELS; ch++)
1127
if (fxdevInterruptBits(ch, mp)) {
1128
mp->exception = EXCEPTION_ON;
1129
TRC_REC("ch%d voice unit interrupt\n",ch);
1130
*work_done |= MV_TDM_SLIC_INTR << MV_CHANNEL_INTR(ch);
1135
if(cause & DMA_ABORT_BIT)
1137
mvOsPrintf("%s: DMA data abort. Address: 0x%08x, Info: 0x%08x\n",
1138
__FUNCTION__, MV_REG_READ(DMA_ABORT_ADDR_REG), MV_REG_READ(DMA_ABORT_INFO_REG));
1139
*work_done |= MV_TDM_DMA_ABORT_INTR;
1142
for(ch=0; ch<MV_TDM_MAX_CHANNELS; ch++)
1147
if (cause & TDM_INT_RX(ch))
1149
if (cause & RX_BIT(ch))
1151
/* Give next buff to TDM and set curr buff as full */
1154
mvTdmChRxLow(mp->ch_info);
1157
if (cause & RX_OVERFLOW_BIT(ch))
1159
/*Channel Rx goes to idle*/
1160
if (likely(!mp->rxActive))
1162
MV_REG_WRITE(INT_STATUS_MASK_REG, MV_REG_READ(INT_STATUS_MASK_REG) & (~(TDM_INT_RX(mp->ch))));
1163
TRC_REC("ch %d: Rx stopped.\n",mp->ch);
1167
mvOsPrintf("ch %d: Rx overflow.\n",mp->ch);
1170
*work_done |= MV_TDM_READ_INTR << MV_CHANNEL_INTR(ch);
1173
if (cause & TDM_INT_TX(ch))
1175
/* Give next buff to TDM and set curr buff as empty */
1176
if (cause & TX_BIT(ch))
1179
mvTdmChTxLow(mp->ch_info);
1182
if(cause & TX_UNDERFLOW_BIT(ch))
1184
/*Channel Tx goes to idle*/
1185
if (likely(!mp->txActive))
1187
MV_REG_WRITE(INT_STATUS_MASK_REG, MV_REG_READ(INT_STATUS_MASK_REG) & (~(TDM_INT_TX(mp->ch))));
1188
TRC_REC("ch %d: Tx stopped.\n",mp->ch);
1192
mvOsPrintf("ch %d: Tx underflow.\n",mp->ch);
1195
*work_done |= MV_TDM_WRITE_INTR << MV_CHANNEL_INTR(ch);
1198
TRC_REC("<-%s\n",__FUNCTION__);
1199
return( (*work_done) ? 0 : 1 );
1203
static int fxdevInterruptBits(unsigned char ch, MV_PHONE *mp)
1206
TRC_REC("<-%s: %s\n",__FUNCTION__, mp->chType == MV_FXS ? "FXS":"FXO");
1208
if(mp->chType == MV_FXS)
1209
retVal = checkSlicInterrupts(mp->slic_dev);
1211
retVal = checkDaaInterrupts(mp->daa_dev);