18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Original author: 68c2ecf20Sopenharmony_ci * Ben Collins <bcollins@ubuntu.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Additional work by: 98c2ecf20Sopenharmony_ci * John Brooks <john.brooks@bluecherry.net> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "solo6x10.h" 168c2ecf20Sopenharmony_ci#include "solo6x10-tw28.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DEFAULT_HDELAY_NTSC (32 - 8) 198c2ecf20Sopenharmony_ci#define DEFAULT_HACTIVE_NTSC (720 + 16) 208c2ecf20Sopenharmony_ci#define DEFAULT_VDELAY_NTSC (7 - 2) 218c2ecf20Sopenharmony_ci#define DEFAULT_VACTIVE_NTSC (240 + 4) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DEFAULT_HDELAY_PAL (32 + 4) 248c2ecf20Sopenharmony_ci#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL) 258c2ecf20Sopenharmony_ci#define DEFAULT_VDELAY_PAL (6) 268c2ecf20Sopenharmony_ci#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic const u8 tbl_tw2864_ntsc_template[] = { 308c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ 318c2ecf20Sopenharmony_ci 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, 328c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ 338c2ecf20Sopenharmony_ci 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, 348c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ 358c2ecf20Sopenharmony_ci 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, 368c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ 378c2ecf20Sopenharmony_ci 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, 388c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 398c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 408c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 418c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 428c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 438c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 448c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ 458c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, 468c2ecf20Sopenharmony_ci 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 478c2ecf20Sopenharmony_ci 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, 488c2ecf20Sopenharmony_ci 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ 498c2ecf20Sopenharmony_ci 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01, 508c2ecf20Sopenharmony_ci 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ 518c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, 528c2ecf20Sopenharmony_ci 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ 538c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 548c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 558c2ecf20Sopenharmony_ci 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, 568c2ecf20Sopenharmony_ci 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ 578c2ecf20Sopenharmony_ci 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, 588c2ecf20Sopenharmony_ci 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 598c2ecf20Sopenharmony_ci 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 608c2ecf20Sopenharmony_ci 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ 618c2ecf20Sopenharmony_ci 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const u8 tbl_tw2864_pal_template[] = { 658c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ 668c2ecf20Sopenharmony_ci 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, 678c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ 688c2ecf20Sopenharmony_ci 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, 698c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ 708c2ecf20Sopenharmony_ci 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, 718c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ 728c2ecf20Sopenharmony_ci 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, 738c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 748c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 758c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 768c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 778c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 788c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 798c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ 808c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, 818c2ecf20Sopenharmony_ci 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 828c2ecf20Sopenharmony_ci 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, 838c2ecf20Sopenharmony_ci 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ 848c2ecf20Sopenharmony_ci 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01, 858c2ecf20Sopenharmony_ci 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ 868c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, 878c2ecf20Sopenharmony_ci 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ 888c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 898c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 908c2ecf20Sopenharmony_ci 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, 918c2ecf20Sopenharmony_ci 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ 928c2ecf20Sopenharmony_ci 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, 938c2ecf20Sopenharmony_ci 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 948c2ecf20Sopenharmony_ci 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 958c2ecf20Sopenharmony_ci 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */ 968c2ecf20Sopenharmony_ci 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const u8 tbl_tw2865_ntsc_template[] = { 1008c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ 1018c2ecf20Sopenharmony_ci 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, 1028c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ 1038c2ecf20Sopenharmony_ci 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, 1048c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ 1058c2ecf20Sopenharmony_ci 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, 1068c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ 1078c2ecf20Sopenharmony_ci 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, 1088c2ecf20Sopenharmony_ci 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */ 1098c2ecf20Sopenharmony_ci 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 1108c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 1118c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1128c2ecf20Sopenharmony_ci 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 1138c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, 1148c2ecf20Sopenharmony_ci 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ 1158c2ecf20Sopenharmony_ci 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, 1168c2ecf20Sopenharmony_ci 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 1178c2ecf20Sopenharmony_ci 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, 1188c2ecf20Sopenharmony_ci 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ 1198c2ecf20Sopenharmony_ci 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, 1208c2ecf20Sopenharmony_ci 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */ 1218c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, 1228c2ecf20Sopenharmony_ci 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ 1238c2ecf20Sopenharmony_ci 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8, 1248c2ecf20Sopenharmony_ci 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 1258c2ecf20Sopenharmony_ci 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, 1268c2ecf20Sopenharmony_ci 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ 1278c2ecf20Sopenharmony_ci 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, 1288c2ecf20Sopenharmony_ci 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 1298c2ecf20Sopenharmony_ci 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 1308c2ecf20Sopenharmony_ci 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ 1318c2ecf20Sopenharmony_ci 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const u8 tbl_tw2865_pal_template[] = { 1358c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ 1368c2ecf20Sopenharmony_ci 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, 1378c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ 1388c2ecf20Sopenharmony_ci 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, 1398c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ 1408c2ecf20Sopenharmony_ci 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, 1418c2ecf20Sopenharmony_ci 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ 1428c2ecf20Sopenharmony_ci 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, 1438c2ecf20Sopenharmony_ci 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */ 1448c2ecf20Sopenharmony_ci 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 1458c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 1468c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1478c2ecf20Sopenharmony_ci 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 1488c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, 1498c2ecf20Sopenharmony_ci 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ 1508c2ecf20Sopenharmony_ci 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, 1518c2ecf20Sopenharmony_ci 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 1528c2ecf20Sopenharmony_ci 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, 1538c2ecf20Sopenharmony_ci 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ 1548c2ecf20Sopenharmony_ci 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, 1558c2ecf20Sopenharmony_ci 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */ 1568c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, 1578c2ecf20Sopenharmony_ci 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ 1588c2ecf20Sopenharmony_ci 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8, 1598c2ecf20Sopenharmony_ci 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 1608c2ecf20Sopenharmony_ci 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, 1618c2ecf20Sopenharmony_ci 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ 1628c2ecf20Sopenharmony_ci 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, 1638c2ecf20Sopenharmony_ci 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 1648c2ecf20Sopenharmony_ci 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 1658c2ecf20Sopenharmony_ci 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */ 1668c2ecf20Sopenharmony_ci 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id))) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off, 1728c2ecf20Sopenharmony_ci u8 tw_off) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_id)) 1758c2ecf20Sopenharmony_ci return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 1768c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_id), 1778c2ecf20Sopenharmony_ci tw6x_off); 1788c2ecf20Sopenharmony_ci else 1798c2ecf20Sopenharmony_ci return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 1808c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_id), 1818c2ecf20Sopenharmony_ci tw_off); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void tw_writebyte(struct solo_dev *solo_dev, int chip_id, 1858c2ecf20Sopenharmony_ci u8 tw6x_off, u8 tw_off, u8 val) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_id)) 1888c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, 1898c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_id), 1908c2ecf20Sopenharmony_ci tw6x_off, val); 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, 1938c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_id), 1948c2ecf20Sopenharmony_ci tw_off, val); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off, 1988c2ecf20Sopenharmony_ci u8 val) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int i; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 2038c2ecf20Sopenharmony_ci u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (rval == val) 2068c2ecf20Sopenharmony_ci return; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val); 2098c2ecf20Sopenharmony_ci msleep_interruptible(1); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */ 2138c2ecf20Sopenharmony_ci/* addr, off, val); */ 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci u8 tbl_tw2865_common[256]; 2198c2ecf20Sopenharmony_ci int i; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) 2228c2ecf20Sopenharmony_ci memcpy(tbl_tw2865_common, tbl_tw2865_pal_template, 2238c2ecf20Sopenharmony_ci sizeof(tbl_tw2865_common)); 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template, 2268c2ecf20Sopenharmony_ci sizeof(tbl_tw2865_common)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* ALINK Mode */ 2298c2ecf20Sopenharmony_ci if (solo_dev->nr_chans == 4) { 2308c2ecf20Sopenharmony_ci tbl_tw2865_common[0xd2] = 0x01; 2318c2ecf20Sopenharmony_ci tbl_tw2865_common[0xcf] = 0x00; 2328c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 8) { 2338c2ecf20Sopenharmony_ci tbl_tw2865_common[0xd2] = 0x02; 2348c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 2358c2ecf20Sopenharmony_ci tbl_tw2865_common[0xcf] = 0x80; 2368c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 16) { 2378c2ecf20Sopenharmony_ci tbl_tw2865_common[0xd2] = 0x03; 2388c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 2398c2ecf20Sopenharmony_ci tbl_tw2865_common[0xcf] = 0x83; 2408c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) 2418c2ecf20Sopenharmony_ci tbl_tw2865_common[0xcf] = 0x83; 2428c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) 2438c2ecf20Sopenharmony_ci tbl_tw2865_common[0xcf] = 0x80; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci for (i = 0; i < 0xff; i++) { 2478c2ecf20Sopenharmony_ci /* Skip read only registers */ 2488c2ecf20Sopenharmony_ci switch (i) { 2498c2ecf20Sopenharmony_ci case 0xb8 ... 0xc1: 2508c2ecf20Sopenharmony_ci case 0xc4 ... 0xc7: 2518c2ecf20Sopenharmony_ci case 0xfd: 2528c2ecf20Sopenharmony_ci continue; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci switch (i & ~0x30) { 2558c2ecf20Sopenharmony_ci case 0x00: 2568c2ecf20Sopenharmony_ci case 0x0c ... 0x0d: 2578c2ecf20Sopenharmony_ci continue; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci tw_write_and_verify(solo_dev, dev_addr, i, 2618c2ecf20Sopenharmony_ci tbl_tw2865_common[i]); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u8 tbl_tw2864_common[256]; 2708c2ecf20Sopenharmony_ci int i; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) 2738c2ecf20Sopenharmony_ci memcpy(tbl_tw2864_common, tbl_tw2864_pal_template, 2748c2ecf20Sopenharmony_ci sizeof(tbl_tw2864_common)); 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template, 2778c2ecf20Sopenharmony_ci sizeof(tbl_tw2864_common)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (solo_dev->tw2865 == 0) { 2808c2ecf20Sopenharmony_ci /* IRQ Mode */ 2818c2ecf20Sopenharmony_ci if (solo_dev->nr_chans == 4) { 2828c2ecf20Sopenharmony_ci tbl_tw2864_common[0xd2] = 0x01; 2838c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x00; 2848c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 8) { 2858c2ecf20Sopenharmony_ci tbl_tw2864_common[0xd2] = 0x02; 2868c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) 2878c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x43; 2888c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 2898c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x40; 2908c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 16) { 2918c2ecf20Sopenharmony_ci tbl_tw2864_common[0xd2] = 0x03; 2928c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) 2938c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x43; 2948c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 2958c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x43; 2968c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) 2978c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x43; 2988c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) 2998c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x40; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci /* ALINK Mode. Assumes that the first tw28xx is a 3038c2ecf20Sopenharmony_ci * 2865 and these are in cascade. */ 3048c2ecf20Sopenharmony_ci for (i = 0; i <= 4; i++) 3058c2ecf20Sopenharmony_ci tbl_tw2864_common[0x08 | i << 4] = 0x12; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (solo_dev->nr_chans == 8) { 3088c2ecf20Sopenharmony_ci tbl_tw2864_common[0xd2] = 0x02; 3098c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 3108c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x80; 3118c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 16) { 3128c2ecf20Sopenharmony_ci tbl_tw2864_common[0xd2] = 0x03; 3138c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 3148c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x83; 3158c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) 3168c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x83; 3178c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) 3188c2ecf20Sopenharmony_ci tbl_tw2864_common[0xcf] = 0x80; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci for (i = 0; i < 0xff; i++) { 3238c2ecf20Sopenharmony_ci /* Skip read only registers */ 3248c2ecf20Sopenharmony_ci switch (i) { 3258c2ecf20Sopenharmony_ci case 0xb8 ... 0xc1: 3268c2ecf20Sopenharmony_ci case 0xfd: 3278c2ecf20Sopenharmony_ci continue; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci switch (i & ~0x30) { 3308c2ecf20Sopenharmony_ci case 0x00: 3318c2ecf20Sopenharmony_ci case 0x0c: 3328c2ecf20Sopenharmony_ci case 0x0d: 3338c2ecf20Sopenharmony_ci continue; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci tw_write_and_verify(solo_dev, dev_addr, i, 3378c2ecf20Sopenharmony_ci tbl_tw2864_common[i]); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci u8 tbl_ntsc_tw2815_common[] = { 3468c2ecf20Sopenharmony_ci 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80, 3478c2ecf20Sopenharmony_ci 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11, 3488c2ecf20Sopenharmony_ci }; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci u8 tbl_pal_tw2815_common[] = { 3518c2ecf20Sopenharmony_ci 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80, 3528c2ecf20Sopenharmony_ci 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11, 3538c2ecf20Sopenharmony_ci }; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci u8 tbl_tw2815_sfr[] = { 3568c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */ 3578c2ecf20Sopenharmony_ci 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00, 3588c2ecf20Sopenharmony_ci 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */ 3598c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00, 3608c2ecf20Sopenharmony_ci 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */ 3618c2ecf20Sopenharmony_ci 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88, 3628c2ecf20Sopenharmony_ci 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */ 3638c2ecf20Sopenharmony_ci }; 3648c2ecf20Sopenharmony_ci u8 *tbl_tw2815_common; 3658c2ecf20Sopenharmony_ci int i; 3668c2ecf20Sopenharmony_ci int ch; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x06] = 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Horizontal Delay Control */ 3718c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff; 3728c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Horizontal Active Control */ 3758c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff; 3768c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x06] |= 3778c2ecf20Sopenharmony_ci ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Vertical Delay Control */ 3808c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff; 3818c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x06] |= 3828c2ecf20Sopenharmony_ci ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Vertical Active Control */ 3858c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff; 3868c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common[0x06] |= 3878c2ecf20Sopenharmony_ci ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x06] = 0; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Horizontal Delay Control */ 3928c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff; 3938c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Horizontal Active Control */ 3968c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff; 3978c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x06] |= 3988c2ecf20Sopenharmony_ci ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Vertical Delay Control */ 4018c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff; 4028c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x06] |= 4038c2ecf20Sopenharmony_ci ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Vertical Active Control */ 4068c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff; 4078c2ecf20Sopenharmony_ci tbl_pal_tw2815_common[0x06] |= 4088c2ecf20Sopenharmony_ci ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci tbl_tw2815_common = 4118c2ecf20Sopenharmony_ci (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ? 4128c2ecf20Sopenharmony_ci tbl_ntsc_tw2815_common : tbl_pal_tw2815_common; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* Dual ITU-R BT.656 format */ 4158c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] |= 0x04; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Audio configuration */ 4188c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (solo_dev->nr_chans == 4) { 4218c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x63 - 0x40] |= 1; 4228c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6; 4238c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 8) { 4248c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x63 - 0x40] |= 2; 4258c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) 4268c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; 4278c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 4288c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; 4298c2ecf20Sopenharmony_ci } else if (solo_dev->nr_chans == 16) { 4308c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x63 - 0x40] |= 3; 4318c2ecf20Sopenharmony_ci if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) 4328c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; 4338c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) 4348c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; 4358c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) 4368c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; 4378c2ecf20Sopenharmony_ci else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) 4388c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Output mode of R_ADATM pin (0 mixing, 1 record) */ 4428c2ecf20Sopenharmony_ci /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* 8KHz, used to be 16KHz, but changed for remote client compat */ 4458c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2; 4468c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Playback of right channel */ 4498c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Reserved value (XXX ??) */ 4528c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* Analog output gain and mix ratio playback on full */ 4558c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x70 - 0x40] |= 0xff; 4568c2ecf20Sopenharmony_ci /* Select playback audio and mute all except */ 4578c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x71 - 0x40] |= 0x10; 4588c2ecf20Sopenharmony_ci tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* End of audio configuration */ 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci for (ch = 0; ch < 4; ch++) { 4638c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] &= ~3; 4648c2ecf20Sopenharmony_ci switch (ch) { 4658c2ecf20Sopenharmony_ci case 0: 4668c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] |= 0x21; 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci case 1: 4698c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] |= 0x20; 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci case 2: 4728c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] |= 0x23; 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci case 3: 4758c2ecf20Sopenharmony_ci tbl_tw2815_common[0x0d] |= 0x22; 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci for (i = 0; i < 0x0f; i++) { 4808c2ecf20Sopenharmony_ci if (i == 0x00) 4818c2ecf20Sopenharmony_ci continue; /* read-only */ 4828c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, 4838c2ecf20Sopenharmony_ci dev_addr, (ch * 0x10) + i, 4848c2ecf20Sopenharmony_ci tbl_tw2815_common[i]); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci for (i = 0x40; i < 0x76; i++) { 4898c2ecf20Sopenharmony_ci /* Skip read-only and nop registers */ 4908c2ecf20Sopenharmony_ci if (i == 0x40 || i == 0x59 || i == 0x5a || 4918c2ecf20Sopenharmony_ci i == 0x5d || i == 0x5e || i == 0x5f) 4928c2ecf20Sopenharmony_ci continue; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i, 4958c2ecf20Sopenharmony_ci tbl_tw2815_sfr[i - 0x40]); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci#define FIRST_ACTIVE_LINE 0x0008 5028c2ecf20Sopenharmony_ci#define LAST_ACTIVE_LINE 0x0102 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void saa712x_write_regs(struct solo_dev *dev, const u8 *vals, 5058c2ecf20Sopenharmony_ci int start, int n) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci for (; start < n; start++, vals++) { 5088c2ecf20Sopenharmony_ci /* Skip read-only registers */ 5098c2ecf20Sopenharmony_ci switch (start) { 5108c2ecf20Sopenharmony_ci /* case 0x00 ... 0x25: */ 5118c2ecf20Sopenharmony_ci case 0x2e ... 0x37: 5128c2ecf20Sopenharmony_ci case 0x60: 5138c2ecf20Sopenharmony_ci case 0x7d: 5148c2ecf20Sopenharmony_ci continue; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci#define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \ 5218c2ecf20Sopenharmony_ci | ((FIRST_ACTIVE_LINE & 0x100) >> 4)) 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void saa712x_setup(struct solo_dev *dev) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci const int reg_start = 0x26; 5268c2ecf20Sopenharmony_ci static const u8 saa7128_regs_ntsc[] = { 5278c2ecf20Sopenharmony_ci /* :0x26 */ 5288c2ecf20Sopenharmony_ci 0x0d, 0x00, 5298c2ecf20Sopenharmony_ci /* :0x28 */ 5308c2ecf20Sopenharmony_ci 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 5318c2ecf20Sopenharmony_ci /* :0x2e XXX: read-only */ 5328c2ecf20Sopenharmony_ci 0x00, 0x00, 5338c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5348c2ecf20Sopenharmony_ci /* :0x38 */ 5358c2ecf20Sopenharmony_ci 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 5368c2ecf20Sopenharmony_ci /* :0x40 */ 5378c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18, 5388c2ecf20Sopenharmony_ci 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f, 5398c2ecf20Sopenharmony_ci /* :0x50 */ 5408c2ecf20Sopenharmony_ci 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06, 5418c2ecf20Sopenharmony_ci 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e, 5428c2ecf20Sopenharmony_ci /* :0x60 */ 5438c2ecf20Sopenharmony_ci 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77, 5448c2ecf20Sopenharmony_ci 0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00, 5458c2ecf20Sopenharmony_ci /* :0x70 */ 5468c2ecf20Sopenharmony_ci 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00, 5478c2ecf20Sopenharmony_ci 0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff, 5488c2ecf20Sopenharmony_ci SAA712x_reg7c, 0x00, 0xff, 0xff, 5498c2ecf20Sopenharmony_ci }, saa7128_regs_pal[] = { 5508c2ecf20Sopenharmony_ci /* :0x26 */ 5518c2ecf20Sopenharmony_ci 0x0d, 0x00, 5528c2ecf20Sopenharmony_ci /* :0x28 */ 5538c2ecf20Sopenharmony_ci 0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 5548c2ecf20Sopenharmony_ci /* :0x2e XXX: read-only */ 5558c2ecf20Sopenharmony_ci 0x00, 0x00, 5568c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5578c2ecf20Sopenharmony_ci /* :0x38 */ 5588c2ecf20Sopenharmony_ci 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 5598c2ecf20Sopenharmony_ci /* :0x40 */ 5608c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18, 5618c2ecf20Sopenharmony_ci 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f, 5628c2ecf20Sopenharmony_ci /* :0x50 */ 5638c2ecf20Sopenharmony_ci 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06, 5648c2ecf20Sopenharmony_ci 0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e, 5658c2ecf20Sopenharmony_ci /* :0x60 */ 5668c2ecf20Sopenharmony_ci 0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77, 5678c2ecf20Sopenharmony_ci 0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00, 5688c2ecf20Sopenharmony_ci /* :0x70 */ 5698c2ecf20Sopenharmony_ci 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00, 5708c2ecf20Sopenharmony_ci 0x00, 0x00, 0x12, 0x30, 5718c2ecf20Sopenharmony_ci SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff, 5728c2ecf20Sopenharmony_ci }; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (dev->video_type == SOLO_VO_FMT_TYPE_PAL) 5758c2ecf20Sopenharmony_ci saa712x_write_regs(dev, saa7128_regs_pal, reg_start, 5768c2ecf20Sopenharmony_ci sizeof(saa7128_regs_pal)); 5778c2ecf20Sopenharmony_ci else 5788c2ecf20Sopenharmony_ci saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start, 5798c2ecf20Sopenharmony_ci sizeof(saa7128_regs_ntsc)); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ciint solo_tw28_init(struct solo_dev *solo_dev) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci int i; 5858c2ecf20Sopenharmony_ci u8 value; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci solo_dev->tw28_cnt = 0; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* Detect techwell chip type(s) */ 5908c2ecf20Sopenharmony_ci for (i = 0; i < solo_dev->nr_chans / 4; i++) { 5918c2ecf20Sopenharmony_ci value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 5928c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(i), 0xFF); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci switch (value >> 3) { 5958c2ecf20Sopenharmony_ci case 0x18: 5968c2ecf20Sopenharmony_ci solo_dev->tw2865 |= 1 << i; 5978c2ecf20Sopenharmony_ci solo_dev->tw28_cnt++; 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci case 0x0c: 6008c2ecf20Sopenharmony_ci case 0x0d: 6018c2ecf20Sopenharmony_ci solo_dev->tw2864 |= 1 << i; 6028c2ecf20Sopenharmony_ci solo_dev->tw28_cnt++; 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci default: 6058c2ecf20Sopenharmony_ci value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 6068c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(i), 6078c2ecf20Sopenharmony_ci 0x59); 6088c2ecf20Sopenharmony_ci if ((value >> 3) == 0x04) { 6098c2ecf20Sopenharmony_ci solo_dev->tw2815 |= 1 << i; 6108c2ecf20Sopenharmony_ci solo_dev->tw28_cnt++; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) { 6168c2ecf20Sopenharmony_ci dev_err(&solo_dev->pdev->dev, 6178c2ecf20Sopenharmony_ci "Could not initialize any techwell chips\n"); 6188c2ecf20Sopenharmony_ci return -EINVAL; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci saa712x_setup(solo_dev); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci for (i = 0; i < solo_dev->tw28_cnt; i++) { 6248c2ecf20Sopenharmony_ci if ((solo_dev->tw2865 & (1 << i))) 6258c2ecf20Sopenharmony_ci tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); 6268c2ecf20Sopenharmony_ci else if ((solo_dev->tw2864 & (1 << i))) 6278c2ecf20Sopenharmony_ci tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); 6288c2ecf20Sopenharmony_ci else 6298c2ecf20Sopenharmony_ci tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* 6368c2ecf20Sopenharmony_ci * We accessed the video status signal in the Techwell chip through 6378c2ecf20Sopenharmony_ci * iic/i2c because the video status reported by register REG_VI_STATUS1 6388c2ecf20Sopenharmony_ci * (address 0x012C) of the SOLO6010 chip doesn't give the correct video 6398c2ecf20Sopenharmony_ci * status signal values. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ciint tw28_get_video_status(struct solo_dev *solo_dev, u8 ch) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci u8 val, chip_num; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Get the right chip and on-chip channel */ 6468c2ecf20Sopenharmony_ci chip_num = ch / 4; 6478c2ecf20Sopenharmony_ci ch %= 4; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR, 6508c2ecf20Sopenharmony_ci TW_AV_STAT_ADDR) & 0x0f; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return val & (1 << ch) ? 1 : 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci#if 0 6568c2ecf20Sopenharmony_ci/* Status of audio from up to 4 techwell chips are combined into 1 variable. 6578c2ecf20Sopenharmony_ci * See techwell datasheet for details. */ 6588c2ecf20Sopenharmony_ciu16 tw28_get_audio_status(struct solo_dev *solo_dev) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci u8 val; 6618c2ecf20Sopenharmony_ci u16 status = 0; 6628c2ecf20Sopenharmony_ci int i; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci for (i = 0; i < solo_dev->tw28_cnt; i++) { 6658c2ecf20Sopenharmony_ci val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR, 6668c2ecf20Sopenharmony_ci TW_AV_STAT_ADDR) & 0xf0) >> 4; 6678c2ecf20Sopenharmony_ci status |= val << (i * 4); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return status; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci#endif 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cibool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci return is_tw286x(solo_dev, ch / 4); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ciint tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, 6808c2ecf20Sopenharmony_ci s32 val) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci char sval; 6838c2ecf20Sopenharmony_ci u8 chip_num; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Get the right chip and on-chip channel */ 6868c2ecf20Sopenharmony_ci chip_num = ch / 4; 6878c2ecf20Sopenharmony_ci ch %= 4; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (val > 255 || val < 0) 6908c2ecf20Sopenharmony_ci return -ERANGE; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci switch (ctrl) { 6938c2ecf20Sopenharmony_ci case V4L2_CID_SHARPNESS: 6948c2ecf20Sopenharmony_ci /* Only 286x has sharpness */ 6958c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) { 6968c2ecf20Sopenharmony_ci u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 6978c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_num), 6988c2ecf20Sopenharmony_ci TW286x_SHARPNESS(chip_num)); 6998c2ecf20Sopenharmony_ci v &= 0xf0; 7008c2ecf20Sopenharmony_ci v |= val; 7018c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, 7028c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_num), 7038c2ecf20Sopenharmony_ci TW286x_SHARPNESS(chip_num), v); 7048c2ecf20Sopenharmony_ci } else { 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 7108c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) 7118c2ecf20Sopenharmony_ci sval = val - 128; 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci sval = (char)val; 7148c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), 7158c2ecf20Sopenharmony_ci TW_HUE_ADDR(ch), sval); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 7208c2ecf20Sopenharmony_ci /* 286x chips have a U and V component for saturation */ 7218c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) { 7228c2ecf20Sopenharmony_ci solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, 7238c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_num), 7248c2ecf20Sopenharmony_ci TW286x_SATURATIONU_ADDR(ch), val); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch), 7278c2ecf20Sopenharmony_ci TW_SATURATION_ADDR(ch), val); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 7328c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch), 7338c2ecf20Sopenharmony_ci TW_CONTRAST_ADDR(ch), val); 7348c2ecf20Sopenharmony_ci break; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 7378c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) 7388c2ecf20Sopenharmony_ci sval = val - 128; 7398c2ecf20Sopenharmony_ci else 7408c2ecf20Sopenharmony_ci sval = (char)val; 7418c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch), 7428c2ecf20Sopenharmony_ci TW_BRIGHTNESS_ADDR(ch), sval); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci default: 7468c2ecf20Sopenharmony_ci return -EINVAL; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ciint tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, 7538c2ecf20Sopenharmony_ci s32 *val) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci u8 rval, chip_num; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* Get the right chip and on-chip channel */ 7588c2ecf20Sopenharmony_ci chip_num = ch / 4; 7598c2ecf20Sopenharmony_ci ch %= 4; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci switch (ctrl) { 7628c2ecf20Sopenharmony_ci case V4L2_CID_SHARPNESS: 7638c2ecf20Sopenharmony_ci /* Only 286x has sharpness */ 7648c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) { 7658c2ecf20Sopenharmony_ci rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, 7668c2ecf20Sopenharmony_ci TW_CHIP_OFFSET_ADDR(chip_num), 7678c2ecf20Sopenharmony_ci TW286x_SHARPNESS(chip_num)); 7688c2ecf20Sopenharmony_ci *val = rval & 0x0f; 7698c2ecf20Sopenharmony_ci } else 7708c2ecf20Sopenharmony_ci *val = 0; 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci case V4L2_CID_HUE: 7738c2ecf20Sopenharmony_ci rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), 7748c2ecf20Sopenharmony_ci TW_HUE_ADDR(ch)); 7758c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) 7768c2ecf20Sopenharmony_ci *val = (s32)((char)rval) + 128; 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci *val = rval; 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 7818c2ecf20Sopenharmony_ci *val = tw_readbyte(solo_dev, chip_num, 7828c2ecf20Sopenharmony_ci TW286x_SATURATIONU_ADDR(ch), 7838c2ecf20Sopenharmony_ci TW_SATURATION_ADDR(ch)); 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 7868c2ecf20Sopenharmony_ci *val = tw_readbyte(solo_dev, chip_num, 7878c2ecf20Sopenharmony_ci TW286x_CONTRAST_ADDR(ch), 7888c2ecf20Sopenharmony_ci TW_CONTRAST_ADDR(ch)); 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 7918c2ecf20Sopenharmony_ci rval = tw_readbyte(solo_dev, chip_num, 7928c2ecf20Sopenharmony_ci TW286x_BRIGHTNESS_ADDR(ch), 7938c2ecf20Sopenharmony_ci TW_BRIGHTNESS_ADDR(ch)); 7948c2ecf20Sopenharmony_ci if (is_tw286x(solo_dev, chip_num)) 7958c2ecf20Sopenharmony_ci *val = (s32)((char)rval) + 128; 7968c2ecf20Sopenharmony_ci else 7978c2ecf20Sopenharmony_ci *val = rval; 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci default: 8008c2ecf20Sopenharmony_ci return -EINVAL; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci#if 0 8078c2ecf20Sopenharmony_ci/* 8088c2ecf20Sopenharmony_ci * For audio output volume, the output channel is only 1. In this case we 8098c2ecf20Sopenharmony_ci * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used 8108c2ecf20Sopenharmony_ci * is the base address of the techwell chip. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_civoid tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci unsigned int val; 8158c2ecf20Sopenharmony_ci unsigned int chip_num; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci chip_num = (solo_dev->nr_chans - 1) / 4; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, 8208c2ecf20Sopenharmony_ci TW_AUDIO_OUTPUT_VOL_ADDR); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci u_val = (val & 0x0f) | (u_val << 4); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, 8258c2ecf20Sopenharmony_ci TW_AUDIO_OUTPUT_VOL_ADDR, u_val); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci#endif 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciu8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci u8 val; 8328c2ecf20Sopenharmony_ci u8 chip_num; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Get the right chip and on-chip channel */ 8358c2ecf20Sopenharmony_ci chip_num = ch / 4; 8368c2ecf20Sopenharmony_ci ch %= 4; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci val = tw_readbyte(solo_dev, chip_num, 8398c2ecf20Sopenharmony_ci TW286x_AUDIO_INPUT_GAIN_ADDR(ch), 8408c2ecf20Sopenharmony_ci TW_AUDIO_INPUT_GAIN_ADDR(ch)); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return (ch % 2) ? (val >> 4) : (val & 0x0f); 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_civoid tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci u8 old_val; 8488c2ecf20Sopenharmony_ci u8 chip_num; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Get the right chip and on-chip channel */ 8518c2ecf20Sopenharmony_ci chip_num = ch / 4; 8528c2ecf20Sopenharmony_ci ch %= 4; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci old_val = tw_readbyte(solo_dev, chip_num, 8558c2ecf20Sopenharmony_ci TW286x_AUDIO_INPUT_GAIN_ADDR(ch), 8568c2ecf20Sopenharmony_ci TW_AUDIO_INPUT_GAIN_ADDR(ch)); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) | 8598c2ecf20Sopenharmony_ci ((ch % 2) ? (val << 4) : val); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch), 8628c2ecf20Sopenharmony_ci TW_AUDIO_INPUT_GAIN_ADDR(ch), val); 8638c2ecf20Sopenharmony_ci} 864