blob: 2d18a0fdf70d1a605c8953cfe0183ff264d1023c [file] [log] [blame]
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * Tuner "middleware" for Philips TEA5767 chip
10 *
Nicolas Pennequin357ffb32008-05-05 10:32:46 +000011 * Copyright (C) 2004 Jörg Hohensohn
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000012 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000013 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000017 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
Linus Nielsen Feltzingadec21a2005-08-13 17:34:10 +000022#include "config.h"
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000023#include <stdbool.h>
Jörg Hohensohn4adf9292004-10-17 23:24:18 +000024#include <string.h>
Jörg Hohensohnef8d5082004-10-19 08:20:38 +000025#include <stdlib.h>
26#include "kernel.h"
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000027#include "tuner.h" /* tuner abstraction interface */
Michael Sevakis7d759f62007-07-14 11:20:31 +000028#include "fmradio.h"
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000029#include "fmradio_i2c.h" /* physical interface driver */
30
Jörg Hohensohn4adf9292004-10-17 23:24:18 +000031#define I2C_ADR 0xC0
Dominik Riebeling76b2efb2006-10-23 19:48:42 +000032static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000033
Michael Sevakis7d759f62007-07-14 11:20:31 +000034static void tea5767_set_clear(int byte, unsigned char bits, int set)
35{
36 write_bytes[byte] &= ~bits;
37 if (set)
38 write_bytes[byte] |= bits;
39}
40
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000041/* tuner abstraction layer: set something to the tuner */
Michael Sevakis7d759f62007-07-14 11:20:31 +000042int tea5767_set(int setting, int value)
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000043{
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000044 switch(setting)
45 {
Jörg Hohensohnef8d5082004-10-19 08:20:38 +000046 case RADIO_SLEEP:
47 /* init values */
Dominik Riebeling76b2efb2006-10-23 19:48:42 +000048 write_bytes[0] |= (1<<7); /* mute */
Jens Arnold524b85f2005-09-24 09:06:31 +000049#if CONFIG_TUNER_XTAL == 32768
Dominik Riebeling76b2efb2006-10-23 19:48:42 +000050 /* 32.768kHz, soft mute, stereo noise cancelling */
51 write_bytes[3] |= (1<<4) | (1<<3) | (1<<1);
Linus Nielsen Feltzingadec21a2005-08-13 17:34:10 +000052#else
Dominik Riebeling76b2efb2006-10-23 19:48:42 +000053 /* soft mute, stereo noise cancelling */
54 write_bytes[3] |= (1<<3) | (1<<1);
Linus Nielsen Feltzingadec21a2005-08-13 17:34:10 +000055#endif
Dominik Riebeling76b2efb2006-10-23 19:48:42 +000056 /* sleep / standby mode */
Michael Sevakis7d759f62007-07-14 11:20:31 +000057 tea5767_set_clear(3, (1<<6), value);
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000058 break;
59
60 case RADIO_FREQUENCY:
Jörg Hohensohn4adf9292004-10-17 23:24:18 +000061 {
62 int n;
Jens Arnold524b85f2005-09-24 09:06:31 +000063#if CONFIG_TUNER_XTAL == 32768
64 n = (4 * (value - 225000) + 16384) / 32768;
Linus Nielsen Feltzingadec21a2005-08-13 17:34:10 +000065#else
Linus Nielsen Feltzingae1241b2005-08-24 09:15:13 +000066 n = (4 * (value - 225000)) / 50000;
Linus Nielsen Feltzingadec21a2005-08-13 17:34:10 +000067#endif
Jörg Hohensohn4adf9292004-10-17 23:24:18 +000068 write_bytes[0] = (write_bytes[0] & 0xC0) | (n >> 8);
Michael Sevakis7d759f62007-07-14 11:20:31 +000069 write_bytes[1] = n;
Jörg Hohensohn4adf9292004-10-17 23:24:18 +000070 }
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000071 break;
72
Michael Sevakisa2ee6a62007-03-16 14:40:40 +000073 case RADIO_SCAN_FREQUENCY:
Michael Sevakis7d759f62007-07-14 11:20:31 +000074 tea5767_set(RADIO_FREQUENCY, value);
Michael Sevakisa2ee6a62007-03-16 14:40:40 +000075 sleep(HZ/30);
Michael Sevakis7d759f62007-07-14 11:20:31 +000076 return tea5767_get(RADIO_TUNED);
Michael Sevakisa2ee6a62007-03-16 14:40:40 +000077
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000078 case RADIO_MUTE:
Michael Sevakis7d759f62007-07-14 11:20:31 +000079 tea5767_set_clear(0, 0x80, value);
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000080 break;
81
Michael Sevakis7d759f62007-07-14 11:20:31 +000082 case RADIO_REGION:
83 {
84 const struct tea5767_region_data *rd =
85 &tea5767_region_data[value];
86
87 tea5767_set_clear(4, (1<<6), rd->deemphasis);
88 tea5767_set_clear(3, (1<<5), rd->band);
89 break;
90 }
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000091 case RADIO_FORCE_MONO:
Michael Sevakis7d759f62007-07-14 11:20:31 +000092 tea5767_set_clear(2, 0x08, value);
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000093 break;
Jörg Hohensohn66942122004-10-18 07:58:59 +000094 default:
Michael Sevakisa2ee6a62007-03-16 14:40:40 +000095 return -1;
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +000096 }
Michael Sevakis7d759f62007-07-14 11:20:31 +000097
Jörg Hohensohn66942122004-10-18 07:58:59 +000098 fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
Michael Sevakisa2ee6a62007-03-16 14:40:40 +000099 return 1;
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000100}
101
102/* tuner abstraction layer: read something from the tuner */
Michael Sevakis7d759f62007-07-14 11:20:31 +0000103int tea5767_get(int setting)
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000104{
Jörg Hohensohn4adf9292004-10-17 23:24:18 +0000105 unsigned char read_bytes[5];
Jörg Hohensohn66942122004-10-18 07:58:59 +0000106 int val = -1; /* default for unsupported query */
Jörg Hohensohn4adf9292004-10-17 23:24:18 +0000107
108 fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes));
109
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000110 switch(setting)
111 {
112 case RADIO_PRESENT:
Jörg Hohensohn4adf9292004-10-17 23:24:18 +0000113 val = 1; /* true */
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000114 break;
115
Jörg Hohensohnef8d5082004-10-19 08:20:38 +0000116 case RADIO_TUNED:
117 val = 0;
118 if (read_bytes[0] & 0x80) /* ready */
119 {
120 val = read_bytes[2] & 0x7F; /* IF counter */
121 val = (abs(val - 0x36) < 2); /* close match */
122 }
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000123 break;
124
125 case RADIO_STEREO:
Jörg Hohensohn4adf9292004-10-17 23:24:18 +0000126 val = read_bytes[2] >> 7;
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000127 break;
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000128 }
Michael Sevakis7d759f62007-07-14 11:20:31 +0000129
Jörg Hohensohn8f8fbac2004-10-15 21:41:46 +0000130 return val;
131}
Michael Sevakisa2ee6a62007-03-16 14:40:40 +0000132
Michael Sevakis7d759f62007-07-14 11:20:31 +0000133void tea5767_dbg_info(struct tea5767_dbg_info *info)
Michael Sevakisa2ee6a62007-03-16 14:40:40 +0000134{
135 fmradio_i2c_read(I2C_ADR, info->read_regs, 5);
136 memcpy(info->write_regs, write_bytes, 5);
137}