1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2018 Gateworks Corporation
- */
- #include <linux/delay.h>
- #include <linux/hdmi.h>
- #include <linux/i2c.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/of_graph.h>
- #include <linux/platform_device.h>
- #include <linux/regulator/consumer.h>
- #include <linux/types.h>
- #include <linux/v4l2-dv-timings.h>
- #include <linux/videodev2.h>
- #include <media/v4l2-ctrls.h>
- #include <media/v4l2-device.h>
- #include <media/v4l2-dv-timings.h>
- #include <media/v4l2-event.h>
- #include <media/v4l2-fwnode.h>
- #include <media/i2c/tda1997x.h>
- #include <sound/core.h>
- #include <sound/pcm.h>
- #include <sound/pcm_params.h>
- #include <sound/soc.h>
- #include <dt-bindings/media/tda1997x.h>
- #include "tda1997x_regs.h"
- #define TDA1997X_MBUS_CODES 5
- /* debug level */
- static int debug;
- module_param(debug, int, 0644);
- MODULE_PARM_DESC(debug, "debug level (0-2)");
- /* Audio formats */
- static const char * const audtype_names[] = {
- "PCM", /* PCM Samples */
- "HBR", /* High Bit Rate Audio */
- "OBA", /* One-Bit Audio */
- "DST" /* Direct Stream Transfer */
- };
- /* Audio output port formats */
- enum audfmt_types {
- AUDFMT_TYPE_DISABLED = 0,
- AUDFMT_TYPE_I2S,
- AUDFMT_TYPE_SPDIF,
- };
- static const char * const audfmt_names[] = {
- "Disabled",
- "I2S",
- "SPDIF",
- };
- /* Video input formats */
- static const char * const hdmi_colorspace_names[] = {
- "RGB", "YUV422", "YUV444", "YUV420", "", "", "", "",
- };
- static const char * const hdmi_colorimetry_names[] = {
- "", "ITU601", "ITU709", "Extended",
- };
- static const char * const v4l2_quantization_names[] = {
- "Default",
- "Full Range (0-255)",
- "Limited Range (16-235)",
- };
- /* Video output port formats */
- static const char * const vidfmt_names[] = {
- "RGB444/YUV444", /* RGB/YUV444 16bit data bus, 8bpp */
- "YUV422 semi-planar", /* YUV422 16bit data base, 8bpp */
- "YUV422 CCIR656", /* BT656 (YUV 8bpp 2 clock per pixel) */
- "Invalid",
- };
- /*
- * Colorspace conversion matrices
- */
- struct color_matrix_coefs {
- const char *name;
- /* Input offsets */
- s16 offint1;
- s16 offint2;
- s16 offint3;
- /* Coeficients */
- s16 p11coef;
- s16 p12coef;
- s16 p13coef;
- s16 p21coef;
- s16 p22coef;
- s16 p23coef;
- s16 p31coef;
- s16 p32coef;
- s16 p33coef;
- /* Output offsets */
- s16 offout1;
- s16 offout2;
- s16 offout3;
- };
- enum {
- ITU709_RGBFULL,
- ITU601_RGBFULL,
- RGBLIMITED_RGBFULL,
- RGBLIMITED_ITU601,
- RGBLIMITED_ITU709,
- RGBFULL_ITU601,
- RGBFULL_ITU709,
- };
- /* NB: 4096 is 1.0 using fixed point numbers */
- static const struct color_matrix_coefs conv_matrix[] = {
- {
- "YUV709 -> RGB full",
- -256, -2048, -2048,
- 4769, -2183, -873,
- 4769, 7343, 0,
- 4769, 0, 8652,
- 0, 0, 0,
- },
- {
- "YUV601 -> RGB full",
- -256, -2048, -2048,
- 4769, -3330, -1602,
- 4769, 6538, 0,
- 4769, 0, 8264,
- 256, 256, 256,
- },
- {
- "RGB limited -> RGB full",
- -256, -256, -256,
- 0, 4769, 0,
- 0, 0, 4769,
- 4769, 0, 0,
- 0, 0, 0,
- },
- {
- "RGB limited -> ITU601",
- -256, -256, -256,
- 2404, 1225, 467,
- -1754, 2095, -341,
- -1388, -707, 2095,
- 256, 2048, 2048,
- },
- {
- "RGB limited -> ITU709",
- -256, -256, -256,
- 2918, 867, 295,
- -1894, 2087, -190,
- -1607, -477, 2087,
- 256, 2048, 2048,
- },
- {
- "RGB full -> ITU601",
- 0, 0, 0,
- 2065, 1052, 401,
- -1506, 1799, -293,
- -1192, -607, 1799,
- 256, 2048, 2048,
- },
- {
- "RGB full -> ITU709",
- 0, 0, 0,
- 2506, 745, 253,
- -1627, 1792, -163,
- -1380, -410, 1792,
- 256, 2048, 2048,
- },
- };
- static const struct v4l2_dv_timings_cap tda1997x_dv_timings_cap = {
- .type = V4L2_DV_BT_656_1120,
- /* keep this initialization for compatibility with GCC < 4.4.6 */
- .reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(
- 640, 1920, /* min/max width */
- 350, 1200, /* min/max height */
- 13000000, 165000000, /* min/max pixelclock */
- /* standards */
- V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
- V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
- /* capabilities */
- V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE |
- V4L2_DV_BT_CAP_REDUCED_BLANKING |
- V4L2_DV_BT_CAP_CUSTOM
- )
- };
- /* regulator supplies */
- static const char * const tda1997x_supply_name[] = {
- "DOVDD", /* Digital I/O supply */
- "DVDD", /* Digital Core supply */
- "AVDD", /* Analog supply */
- };
- #define TDA1997X_NUM_SUPPLIES ARRAY_SIZE(tda1997x_supply_name)
- enum tda1997x_type {
- TDA19971,
- TDA19973,
- };
- enum tda1997x_hdmi_pads {
- TDA1997X_PAD_SOURCE,
- TDA1997X_NUM_PADS,
- };
- struct tda1997x_chip_info {
- enum tda1997x_type type;
- const char *name;
- };
- struct tda1997x_state {
- const struct tda1997x_chip_info *info;
- struct tda1997x_platform_data pdata;
- struct i2c_client *client;
- struct i2c_client *client_cec;
- struct v4l2_subdev sd;
- struct regulator_bulk_data supplies[TDA1997X_NUM_SUPPLIES];
- struct media_pad pads[TDA1997X_NUM_PADS];
- struct mutex lock;
- struct mutex page_lock;
- char page;
- /* detected info from chip */
- int chip_revision;
- char port_30bit;
- char output_2p5;
- char tmdsb_clk;
- char tmdsb_soc;
- /* status info */
- char hdmi_status;
- char mptrw_in_progress;
- char activity_status;
- char input_detect[2];
- /* video */
- struct hdmi_avi_infoframe avi_infoframe;
- struct v4l2_hdmi_colorimetry colorimetry;
- u32 rgb_quantization_range;
- struct v4l2_dv_timings timings;
- int fps;
- const struct color_matrix_coefs *conv;
- u32 mbus_codes[TDA1997X_MBUS_CODES]; /* available modes */
- u32 mbus_code; /* current mode */
- u8 vid_fmt;
- /* controls */
- struct v4l2_ctrl_handler hdl;
- struct v4l2_ctrl *detect_tx_5v_ctrl;
- struct v4l2_ctrl *rgb_quantization_range_ctrl;
- /* audio */
- u8 audio_ch_alloc;
- int audio_samplerate;
- int audio_channels;
- int audio_samplesize;
- int audio_type;
- struct mutex audio_lock;
- struct snd_pcm_substream *audio_stream;
- /* EDID */
- struct {
- u8 edid[256];
- u32 present;
- unsigned int blocks;
- } edid;
- struct delayed_work delayed_work_enable_hpd;
- };
- static const struct v4l2_event tda1997x_ev_fmt = {
- .type = V4L2_EVENT_SOURCE_CHANGE,
- .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
- };
- static const struct tda1997x_chip_info tda1997x_chip_info[] = {
- [TDA19971] = {
- .type = TDA19971,
- .name = "tda19971",
- },
- [TDA19973] = {
- .type = TDA19973,
- .name = "tda19973",
- },
- };
- static inline struct tda1997x_state *to_state(struct v4l2_subdev *sd)
- {
- return container_of(sd, struct tda1997x_state, sd);
- }
- static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
- {
- return &container_of(ctrl->handler, struct tda1997x_state, hdl)->sd;
- }
- static int tda1997x_cec_read(struct v4l2_subdev *sd, u8 reg)
- {
- struct tda1997x_state *state = to_state(sd);
- int val;
- val = i2c_smbus_read_byte_data(state->client_cec, reg);
- if (val < 0) {
- v4l_err(state->client, "read reg error: reg=%2x\n", reg);
- val = -1;
- }
- return val;
- }
- static int tda1997x_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
- {
- struct tda1997x_state *state = to_state(sd);
- int ret = 0;
- ret = i2c_smbus_write_byte_data(state->client_cec, reg, val);
- if (ret < 0) {
- v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
- reg, val);
- ret = -1;
- }
- return ret;
- }
- /* -----------------------------------------------------------------------------
- * I2C transfer
- */
- static int tda1997x_setpage(struct v4l2_subdev *sd, u8 page)
- {
- struct tda1997x_state *state = to_state(sd);
- int ret;
- if (state->page != page) {
- ret = i2c_smbus_write_byte_data(state->client,
- REG_CURPAGE_00H, page);
- if (ret < 0) {
- v4l_err(state->client,
- "write reg error:reg=%2x,val=%2x\n",
- REG_CURPAGE_00H, page);
- return ret;
- }
- state->page = page;
- }
- return 0;
- }
- static inline int io_read(struct v4l2_subdev *sd, u16 reg)
- {
- struct tda1997x_state *state = to_state(sd);
- int val;
- mutex_lock(&state->page_lock);
- if (tda1997x_setpage(sd, reg >> 8)) {
- val = -1;
- goto out;
- }
- val = i2c_smbus_read_byte_data(state->client, reg&0xff);
- if (val < 0) {
- v4l_err(state->client, "read reg error: reg=%2x\n", reg & 0xff);
- val = -1;
- goto out;
- }
- out:
- mutex_unlock(&state->page_lock);
- return val;
- }
- static inline long io_read16(struct v4l2_subdev *sd, u16 reg)
- {
- int val;
- long lval = 0;
- val = io_read(sd, reg);
- if (val < 0)
- return val;
- lval |= (val << 8);
- val = io_read(sd, reg + 1);
- if (val < 0)
- return val;
- lval |= val;
- return lval;
- }
- static inline long io_read24(struct v4l2_subdev *sd, u16 reg)
- {
- int val;
- long lval = 0;
- val = io_read(sd, reg);
- if (val < 0)
- return val;
- lval |= (val << 16);
- val = io_read(sd, reg + 1);
- if (val < 0)
- return val;
- lval |= (val << 8);
- val = io_read(sd, reg + 2);
- if (val < 0)
- return val;
- lval |= val;
- return lval;
- }
- static unsigned int io_readn(struct v4l2_subdev *sd, u16 reg, u8 len, u8 *data)
- {
- int i;
- int sz = 0;
- int val;
- for (i = 0; i < len; i++) {
- val = io_read(sd, reg + i);
- if (val < 0)
- break;
- data[i] = val;
- sz++;
- }
- return sz;
- }
- static int io_write(struct v4l2_subdev *sd, u16 reg, u8 val)
- {
- struct tda1997x_state *state = to_state(sd);
- s32 ret = 0;
- mutex_lock(&state->page_lock);
- if (tda1997x_setpage(sd, reg >> 8)) {
- ret = -1;
- goto out;
- }
- ret = i2c_smbus_write_byte_data(state->client, reg & 0xff, val);
- if (ret < 0) {
- v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
- reg&0xff, val);
- ret = -1;
- goto out;
- }
- out:
- mutex_unlock(&state->page_lock);
- return ret;
- }
- static int io_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
- {
- int ret;
- ret = io_write(sd, reg, (val >> 8) & 0xff);
- if (ret < 0)
- return ret;
- ret = io_write(sd, reg + 1, val & 0xff);
- if (ret < 0)
- return ret;
- return 0;
- }
- static int io_write24(struct v4l2_subdev *sd, u16 reg, u32 val)
- {
- int ret;
- ret = io_write(sd, reg, (val >> 16) & 0xff);
- if (ret < 0)
- return ret;
- ret = io_write(sd, reg + 1, (val >> 8) & 0xff);
- if (ret < 0)
- return ret;
- ret = io_write(sd, reg + 2, val & 0xff);
- if (ret < 0)
- return ret;
- return 0;
- }
- /* -----------------------------------------------------------------------------
- * Hotplug
- */
- enum hpd_mode {
- HPD_LOW_BP, /* HPD low and pulse of at least 100ms */
- HPD_LOW_OTHER, /* HPD low and pulse of at least 100ms */
- HPD_HIGH_BP, /* HIGH */
- HPD_HIGH_OTHER,
- HPD_PULSE, /* HPD low pulse */
- };
- /* manual HPD (Hot Plug Detect) control */
- static int tda1997x_manual_hpd(struct v4l2_subdev *sd, enum hpd_mode mode)
- {
- u8 hpd_auto, hpd_pwr, hpd_man;
- hpd_auto = io_read(sd, REG_HPD_AUTO_CTRL);
- hpd_pwr = io_read(sd, REG_HPD_POWER);
- hpd_man = io_read(sd, REG_HPD_MAN_CTRL);
- /* mask out unused bits */
- hpd_man &= (HPD_MAN_CTRL_HPD_PULSE |
- HPD_MAN_CTRL_5VEN |
- HPD_MAN_CTRL_HPD_B |
- HPD_MAN_CTRL_HPD_A);
- switch (mode) {
- /* HPD low and pulse of at least 100ms */
- case HPD_LOW_BP:
- /* hpd_bp=0 */
- hpd_pwr &= ~HPD_POWER_BP_MASK;
- /* disable HPD_A and HPD_B */
- hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
- io_write(sd, REG_HPD_POWER, hpd_pwr);
- io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
- break;
- /* HPD high */
- case HPD_HIGH_BP:
- /* hpd_bp=1 */
- hpd_pwr &= ~HPD_POWER_BP_MASK;
- hpd_pwr |= 1 << HPD_POWER_BP_SHIFT;
- io_write(sd, REG_HPD_POWER, hpd_pwr);
- break;
- /* HPD low and pulse of at least 100ms */
- case HPD_LOW_OTHER:
- /* disable HPD_A and HPD_B */
- hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
- /* hp_other=0 */
- hpd_auto &= ~HPD_AUTO_HP_OTHER;
- io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
- io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
- break;
- /* HPD high */
- case HPD_HIGH_OTHER:
- hpd_auto |= HPD_AUTO_HP_OTHER;
- io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
- break;
- /* HPD low pulse */
- case HPD_PULSE:
- /* disable HPD_A and HPD_B */
- hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
- io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
- break;
- }
- return 0;
- }
- static void tda1997x_delayed_work_enable_hpd(struct work_struct *work)
- {
- struct delayed_work *dwork = to_delayed_work(work);
- struct tda1997x_state *state = container_of(dwork,
- struct tda1997x_state,
- delayed_work_enable_hpd);
- struct v4l2_subdev *sd = &state->sd;
- v4l2_dbg(2, debug, sd, "%s:\n", __func__);
- /* Set HPD high */
- tda1997x_manual_hpd(sd, HPD_HIGH_OTHER);
- tda1997x_manual_hpd(sd, HPD_HIGH_BP);
- state->edid.present = 1;
- }
- static void tda1997x_disable_edid(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l2_dbg(1, debug, sd, "%s\n", __func__);
- cancel_delayed_work_sync(&state->delayed_work_enable_hpd);
- /* Set HPD low */
- tda1997x_manual_hpd(sd, HPD_LOW_BP);
- }
- static void tda1997x_enable_edid(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l2_dbg(1, debug, sd, "%s\n", __func__);
- /* Enable hotplug after 100ms */
- schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10);
- }
- /* -----------------------------------------------------------------------------
- * Signal Control
- */
- /*
- * configure vid_fmt based on mbus_code
- */
- static int
- tda1997x_setup_format(struct tda1997x_state *state, u32 code)
- {
- v4l_dbg(1, debug, state->client, "%s code=0x%x\n", __func__, code);
- switch (code) {
- case MEDIA_BUS_FMT_RGB121212_1X36:
- case MEDIA_BUS_FMT_RGB888_1X24:
- case MEDIA_BUS_FMT_YUV12_1X36:
- case MEDIA_BUS_FMT_YUV8_1X24:
- state->vid_fmt = OF_FMT_444;
- break;
- case MEDIA_BUS_FMT_UYVY12_1X24:
- case MEDIA_BUS_FMT_UYVY10_1X20:
- case MEDIA_BUS_FMT_UYVY8_1X16:
- state->vid_fmt = OF_FMT_422_SMPT;
- break;
- case MEDIA_BUS_FMT_UYVY12_2X12:
- case MEDIA_BUS_FMT_UYVY10_2X10:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- state->vid_fmt = OF_FMT_422_CCIR;
- break;
- default:
- v4l_err(state->client, "incompatible format (0x%x)\n", code);
- return -EINVAL;
- }
- v4l_dbg(1, debug, state->client, "%s code=0x%x fmt=%s\n", __func__,
- code, vidfmt_names[state->vid_fmt]);
- state->mbus_code = code;
- return 0;
- }
- /*
- * The color conversion matrix will convert between the colorimetry of the
- * HDMI input to the desired output format RGB|YUV. RGB output is to be
- * full-range and YUV is to be limited range.
- *
- * RGB full-range uses values from 0 to 255 which is recommended on a monitor
- * and RGB Limited uses values from 16 to 236 (16=black, 235=white) which is
- * typically recommended on a TV.
- */
- static void
- tda1997x_configure_csc(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
- struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
- /* Blanking code values depend on output colorspace (RGB or YUV) */
- struct blanking_codes {
- s16 code_gy;
- s16 code_bu;
- s16 code_rv;
- };
- static const struct blanking_codes rgb_blanking = { 64, 64, 64 };
- static const struct blanking_codes yuv_blanking = { 64, 512, 512 };
- const struct blanking_codes *blanking_codes = NULL;
- u8 reg;
- v4l_dbg(1, debug, state->client, "input:%s quant:%s output:%s\n",
- hdmi_colorspace_names[avi->colorspace],
- v4l2_quantization_names[c->quantization],
- vidfmt_names[state->vid_fmt]);
- state->conv = NULL;
- switch (state->vid_fmt) {
- /* RGB output */
- case OF_FMT_444:
- blanking_codes = &rgb_blanking;
- if (c->colorspace == V4L2_COLORSPACE_SRGB) {
- if (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)
- state->conv = &conv_matrix[RGBLIMITED_RGBFULL];
- } else {
- if (c->colorspace == V4L2_COLORSPACE_REC709)
- state->conv = &conv_matrix[ITU709_RGBFULL];
- else if (c->colorspace == V4L2_COLORSPACE_SMPTE170M)
- state->conv = &conv_matrix[ITU601_RGBFULL];
- }
- break;
- /* YUV output */
- case OF_FMT_422_SMPT: /* semi-planar */
- case OF_FMT_422_CCIR: /* CCIR656 */
- blanking_codes = &yuv_blanking;
- if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
- (c->quantization == V4L2_QUANTIZATION_FULL_RANGE)) {
- if (state->timings.bt.height <= 576)
- state->conv = &conv_matrix[RGBFULL_ITU601];
- else
- state->conv = &conv_matrix[RGBFULL_ITU709];
- } else if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
- (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)) {
- if (state->timings.bt.height <= 576)
- state->conv = &conv_matrix[RGBLIMITED_ITU601];
- else
- state->conv = &conv_matrix[RGBLIMITED_ITU709];
- }
- break;
- }
- if (state->conv) {
- v4l_dbg(1, debug, state->client, "%s\n",
- state->conv->name);
- /* enable matrix conversion */
- reg = io_read(sd, REG_VDP_CTRL);
- reg &= ~VDP_CTRL_MATRIX_BP;
- io_write(sd, REG_VDP_CTRL, reg);
- /* offset inputs */
- io_write16(sd, REG_VDP_MATRIX + 0, state->conv->offint1);
- io_write16(sd, REG_VDP_MATRIX + 2, state->conv->offint2);
- io_write16(sd, REG_VDP_MATRIX + 4, state->conv->offint3);
- /* coefficients */
- io_write16(sd, REG_VDP_MATRIX + 6, state->conv->p11coef);
- io_write16(sd, REG_VDP_MATRIX + 8, state->conv->p12coef);
- io_write16(sd, REG_VDP_MATRIX + 10, state->conv->p13coef);
- io_write16(sd, REG_VDP_MATRIX + 12, state->conv->p21coef);
- io_write16(sd, REG_VDP_MATRIX + 14, state->conv->p22coef);
- io_write16(sd, REG_VDP_MATRIX + 16, state->conv->p23coef);
- io_write16(sd, REG_VDP_MATRIX + 18, state->conv->p31coef);
- io_write16(sd, REG_VDP_MATRIX + 20, state->conv->p32coef);
- io_write16(sd, REG_VDP_MATRIX + 22, state->conv->p33coef);
- /* offset outputs */
- io_write16(sd, REG_VDP_MATRIX + 24, state->conv->offout1);
- io_write16(sd, REG_VDP_MATRIX + 26, state->conv->offout2);
- io_write16(sd, REG_VDP_MATRIX + 28, state->conv->offout3);
- } else {
- /* disable matrix conversion */
- reg = io_read(sd, REG_VDP_CTRL);
- reg |= VDP_CTRL_MATRIX_BP;
- io_write(sd, REG_VDP_CTRL, reg);
- }
- /* SetBlankingCodes */
- if (blanking_codes) {
- io_write16(sd, REG_BLK_GY, blanking_codes->code_gy);
- io_write16(sd, REG_BLK_BU, blanking_codes->code_bu);
- io_write16(sd, REG_BLK_RV, blanking_codes->code_rv);
- }
- }
- /* Configure frame detection window and VHREF timing generator */
- static void
- tda1997x_configure_vhref(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- const struct v4l2_bt_timings *bt = &state->timings.bt;
- int width, lines;
- u16 href_start, href_end;
- u16 vref_f1_start, vref_f2_start;
- u8 vref_f1_width, vref_f2_width;
- u8 field_polarity;
- u16 fieldref_f1_start, fieldref_f2_start;
- u8 reg;
- href_start = bt->hbackporch + bt->hsync + 1;
- href_end = href_start + bt->width;
- vref_f1_start = bt->height + bt->vbackporch + bt->vsync +
- bt->il_vbackporch + bt->il_vsync +
- bt->il_vfrontporch;
- vref_f1_width = bt->vbackporch + bt->vsync + bt->vfrontporch;
- vref_f2_start = 0;
- vref_f2_width = 0;
- fieldref_f1_start = 0;
- fieldref_f2_start = 0;
- if (bt->interlaced) {
- vref_f2_start = (bt->height / 2) +
- (bt->il_vbackporch + bt->il_vsync - 1);
- vref_f2_width = bt->il_vbackporch + bt->il_vsync +
- bt->il_vfrontporch;
- fieldref_f2_start = vref_f2_start + bt->il_vfrontporch +
- fieldref_f1_start;
- }
- field_polarity = 0;
- width = V4L2_DV_BT_FRAME_WIDTH(bt);
- lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
- /*
- * Configure Frame Detection Window:
- * horiz area where the VHREF module consider a VSYNC a new frame
- */
- io_write16(sd, REG_FDW_S, 0x2ef); /* start position */
- io_write16(sd, REG_FDW_E, 0x141); /* end position */
- /* Set Pixel And Line Counters */
- if (state->chip_revision == 0)
- io_write16(sd, REG_PXCNT_PR, 4);
- else
- io_write16(sd, REG_PXCNT_PR, 1);
- io_write16(sd, REG_PXCNT_NPIX, width & MASK_VHREF);
- io_write16(sd, REG_LCNT_PR, 1);
- io_write16(sd, REG_LCNT_NLIN, lines & MASK_VHREF);
- /*
- * Configure the VHRef timing generator responsible for rebuilding all
- * horiz and vert synch and ref signals from its input allowing auto
- * detection algorithms and forcing predefined modes (480i & 576i)
- */
- reg = VHREF_STD_DET_OFF << VHREF_STD_DET_SHIFT;
- io_write(sd, REG_VHREF_CTRL, reg);
- /*
- * Configure the VHRef timing values. In case the VHREF generator has
- * been configured in manual mode, this will allow to manually set all
- * horiz and vert ref values (non-active pixel areas) of the generator
- * and allows setting the frame reference params.
- */
- /* horizontal reference start/end */
- io_write16(sd, REG_HREF_S, href_start & MASK_VHREF);
- io_write16(sd, REG_HREF_E, href_end & MASK_VHREF);
- /* vertical reference f1 start/end */
- io_write16(sd, REG_VREF_F1_S, vref_f1_start & MASK_VHREF);
- io_write(sd, REG_VREF_F1_WIDTH, vref_f1_width);
- /* vertical reference f2 start/end */
- io_write16(sd, REG_VREF_F2_S, vref_f2_start & MASK_VHREF);
- io_write(sd, REG_VREF_F2_WIDTH, vref_f2_width);
- /* F1/F2 FREF, field polarity */
- reg = fieldref_f1_start & MASK_VHREF;
- reg |= field_polarity << 8;
- io_write16(sd, REG_FREF_F1_S, reg);
- reg = fieldref_f2_start & MASK_VHREF;
- io_write16(sd, REG_FREF_F2_S, reg);
- }
- /* Configure Video Output port signals */
- static int
- tda1997x_configure_vidout(struct tda1997x_state *state)
- {
- struct v4l2_subdev *sd = &state->sd;
- struct tda1997x_platform_data *pdata = &state->pdata;
- u8 prefilter;
- u8 reg;
- /* Configure pixel clock generator: delay, polarity, rate */
- reg = (state->vid_fmt == OF_FMT_422_CCIR) ?
- PCLK_SEL_X2 : PCLK_SEL_X1;
- reg |= pdata->vidout_delay_pclk << PCLK_DELAY_SHIFT;
- reg |= pdata->vidout_inv_pclk << PCLK_INV_SHIFT;
- io_write(sd, REG_PCLK, reg);
- /* Configure pre-filter */
- prefilter = 0; /* filters off */
- /* YUV422 mode requires conversion */
- if ((state->vid_fmt == OF_FMT_422_SMPT) ||
- (state->vid_fmt == OF_FMT_422_CCIR)) {
- /* 2/7 taps for Rv and Bu */
- prefilter = FILTERS_CTRL_2_7TAP << FILTERS_CTRL_BU_SHIFT |
- FILTERS_CTRL_2_7TAP << FILTERS_CTRL_RV_SHIFT;
- }
- io_write(sd, REG_FILTERS_CTRL, prefilter);
- /* Configure video port */
- reg = state->vid_fmt & OF_FMT_MASK;
- if (state->vid_fmt == OF_FMT_422_CCIR)
- reg |= (OF_BLK | OF_TRC);
- reg |= OF_VP_ENABLE;
- io_write(sd, REG_OF, reg);
- /* Configure formatter and conversions */
- reg = io_read(sd, REG_VDP_CTRL);
- /* pre-filter is needed unless (REG_FILTERS_CTRL == 0) */
- if (!prefilter)
- reg |= VDP_CTRL_PREFILTER_BP;
- else
- reg &= ~VDP_CTRL_PREFILTER_BP;
- /* formatter is needed for YUV422 and for trc/blc codes */
- if (state->vid_fmt == OF_FMT_444)
- reg |= VDP_CTRL_FORMATTER_BP;
- /* formatter and compdel needed for timing/blanking codes */
- else
- reg &= ~(VDP_CTRL_FORMATTER_BP | VDP_CTRL_COMPDEL_BP);
- /* activate compdel for small sync delays */
- if ((pdata->vidout_delay_vs < 4) || (pdata->vidout_delay_hs < 4))
- reg &= ~VDP_CTRL_COMPDEL_BP;
- io_write(sd, REG_VDP_CTRL, reg);
- /* Configure DE output signal: delay, polarity, and source */
- reg = pdata->vidout_delay_de << DE_FREF_DELAY_SHIFT |
- pdata->vidout_inv_de << DE_FREF_INV_SHIFT |
- pdata->vidout_sel_de << DE_FREF_SEL_SHIFT;
- io_write(sd, REG_DE_FREF, reg);
- /* Configure HS/HREF output signal: delay, polarity, and source */
- if (state->vid_fmt != OF_FMT_422_CCIR) {
- reg = pdata->vidout_delay_hs << HS_HREF_DELAY_SHIFT |
- pdata->vidout_inv_hs << HS_HREF_INV_SHIFT |
- pdata->vidout_sel_hs << HS_HREF_SEL_SHIFT;
- } else
- reg = HS_HREF_SEL_NONE << HS_HREF_SEL_SHIFT;
- io_write(sd, REG_HS_HREF, reg);
- /* Configure VS/VREF output signal: delay, polarity, and source */
- if (state->vid_fmt != OF_FMT_422_CCIR) {
- reg = pdata->vidout_delay_vs << VS_VREF_DELAY_SHIFT |
- pdata->vidout_inv_vs << VS_VREF_INV_SHIFT |
- pdata->vidout_sel_vs << VS_VREF_SEL_SHIFT;
- } else
- reg = VS_VREF_SEL_NONE << VS_VREF_SEL_SHIFT;
- io_write(sd, REG_VS_VREF, reg);
- return 0;
- }
- /* Configure Audio output port signals */
- static int
- tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
- {
- struct tda1997x_state *state = to_state(sd);
- struct tda1997x_platform_data *pdata = &state->pdata;
- bool sp_used_by_fifo = 1;
- u8 reg;
- if (!pdata->audout_format)
- return 0;
- /* channel assignment (CEA-861-D Table 20) */
- io_write(sd, REG_AUDIO_PATH, channel_assignment);
- /* Audio output configuration */
- reg = 0;
- switch (pdata->audout_format) {
- case AUDFMT_TYPE_I2S:
- reg |= AUDCFG_BUS_I2S << AUDCFG_BUS_SHIFT;
- break;
- case AUDFMT_TYPE_SPDIF:
- reg |= AUDCFG_BUS_SPDIF << AUDCFG_BUS_SHIFT;
- break;
- }
- switch (state->audio_type) {
- case AUDCFG_TYPE_PCM:
- reg |= AUDCFG_TYPE_PCM << AUDCFG_TYPE_SHIFT;
- break;
- case AUDCFG_TYPE_OBA:
- reg |= AUDCFG_TYPE_OBA << AUDCFG_TYPE_SHIFT;
- break;
- case AUDCFG_TYPE_DST:
- reg |= AUDCFG_TYPE_DST << AUDCFG_TYPE_SHIFT;
- sp_used_by_fifo = 0;
- break;
- case AUDCFG_TYPE_HBR:
- reg |= AUDCFG_TYPE_HBR << AUDCFG_TYPE_SHIFT;
- if (pdata->audout_layout == 1) {
- /* demuxed via AP0:AP3 */
- reg |= AUDCFG_HBR_DEMUX << AUDCFG_HBR_SHIFT;
- if (pdata->audout_format == AUDFMT_TYPE_SPDIF)
- sp_used_by_fifo = 0;
- } else {
- /* straight via AP0 */
- reg |= AUDCFG_HBR_STRAIGHT << AUDCFG_HBR_SHIFT;
- }
- break;
- }
- if (pdata->audout_width == 32)
- reg |= AUDCFG_I2SW_32 << AUDCFG_I2SW_SHIFT;
- else
- reg |= AUDCFG_I2SW_16 << AUDCFG_I2SW_SHIFT;
- /* automatic hardware mute */
- if (pdata->audio_auto_mute)
- reg |= AUDCFG_AUTO_MUTE_EN;
- /* clock polarity */
- if (pdata->audout_invert_clk)
- reg |= AUDCFG_CLK_INVERT;
- io_write(sd, REG_AUDCFG, reg);
- /* audio layout */
- reg = (pdata->audout_layout) ? AUDIO_LAYOUT_LAYOUT1 : 0;
- if (!pdata->audout_layoutauto)
- reg |= AUDIO_LAYOUT_MANUAL;
- if (sp_used_by_fifo)
- reg |= AUDIO_LAYOUT_SP_FLAG;
- io_write(sd, REG_AUDIO_LAYOUT, reg);
- /* FIFO Latency value */
- io_write(sd, REG_FIFO_LATENCY_VAL, 0x80);
- /* Audio output port config */
- if (sp_used_by_fifo) {
- reg = AUDIO_OUT_ENABLE_AP0;
- if (channel_assignment >= 0x01)
- reg |= AUDIO_OUT_ENABLE_AP1;
- if (channel_assignment >= 0x04)
- reg |= AUDIO_OUT_ENABLE_AP2;
- if (channel_assignment >= 0x0c)
- reg |= AUDIO_OUT_ENABLE_AP3;
- /* specific cases where AP1 is not used */
- if ((channel_assignment == 0x04)
- || (channel_assignment == 0x08)
- || (channel_assignment == 0x0c)
- || (channel_assignment == 0x10)
- || (channel_assignment == 0x14)
- || (channel_assignment == 0x18)
- || (channel_assignment == 0x1c))
- reg &= ~AUDIO_OUT_ENABLE_AP1;
- /* specific cases where AP2 is not used */
- if ((channel_assignment >= 0x14)
- && (channel_assignment <= 0x17))
- reg &= ~AUDIO_OUT_ENABLE_AP2;
- } else {
- reg = AUDIO_OUT_ENABLE_AP3 |
- AUDIO_OUT_ENABLE_AP2 |
- AUDIO_OUT_ENABLE_AP1 |
- AUDIO_OUT_ENABLE_AP0;
- }
- if (pdata->audout_format == AUDFMT_TYPE_I2S)
- reg |= (AUDIO_OUT_ENABLE_ACLK | AUDIO_OUT_ENABLE_WS);
- io_write(sd, REG_AUDIO_OUT_ENABLE, reg);
- /* reset test mode to normal audio freq auto selection */
- io_write(sd, REG_TEST_MODE, 0x00);
- return 0;
- }
- /* Soft Reset of specific hdmi info */
- static int
- tda1997x_hdmi_info_reset(struct v4l2_subdev *sd, u8 info_rst, bool reset_sus)
- {
- u8 reg;
- /* reset infoframe engine packets */
- reg = io_read(sd, REG_HDMI_INFO_RST);
- io_write(sd, REG_HDMI_INFO_RST, info_rst);
- /* if infoframe engine has been reset clear INT_FLG_MODE */
- if (reg & RESET_IF) {
- reg = io_read(sd, REG_INT_FLG_CLR_MODE);
- io_write(sd, REG_INT_FLG_CLR_MODE, reg);
- }
- /* Disable REFTIM to restart start-up-sequencer (SUS) */
- reg = io_read(sd, REG_RATE_CTRL);
- reg &= ~RATE_REFTIM_ENABLE;
- if (!reset_sus)
- reg |= RATE_REFTIM_ENABLE;
- reg = io_write(sd, REG_RATE_CTRL, reg);
- return 0;
- }
- static void
- tda1997x_power_mode(struct tda1997x_state *state, bool enable)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg;
- if (enable) {
- /* Automatic control of TMDS */
- io_write(sd, REG_PON_OVR_EN, PON_DIS);
- /* Enable current bias unit */
- io_write(sd, REG_CFG1, PON_EN);
- /* Enable deep color PLL */
- io_write(sd, REG_DEEP_PLL7_BYP, PON_DIS);
- /* Output buffers active */
- reg = io_read(sd, REG_OF);
- reg &= ~OF_VP_ENABLE;
- io_write(sd, REG_OF, reg);
- } else {
- /* Power down EDID mode sequence */
- /* Output buffers in HiZ */
- reg = io_read(sd, REG_OF);
- reg |= OF_VP_ENABLE;
- io_write(sd, REG_OF, reg);
- /* Disable deep color PLL */
- io_write(sd, REG_DEEP_PLL7_BYP, PON_EN);
- /* Disable current bias unit */
- io_write(sd, REG_CFG1, PON_DIS);
- /* Manual control of TMDS */
- io_write(sd, REG_PON_OVR_EN, PON_EN);
- }
- }
- static bool
- tda1997x_detect_tx_5v(struct v4l2_subdev *sd)
- {
- u8 reg = io_read(sd, REG_DETECT_5V);
- return ((reg & DETECT_5V_SEL) ? 1 : 0);
- }
- static bool
- tda1997x_detect_tx_hpd(struct v4l2_subdev *sd)
- {
- u8 reg = io_read(sd, REG_DETECT_5V);
- return ((reg & DETECT_HPD) ? 1 : 0);
- }
- static int
- tda1997x_detect_std(struct tda1997x_state *state,
- struct v4l2_dv_timings *timings)
- {
- struct v4l2_subdev *sd = &state->sd;
- u32 vper;
- u16 hper;
- u16 hsper;
- int i;
- /*
- * Read the FMT registers
- * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) cycles
- * REG_H_PER: Period of a line in MCLK(27MHz) cycles
- * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles
- */
- vper = io_read24(sd, REG_V_PER) & MASK_VPER;
- hper = io_read16(sd, REG_H_PER) & MASK_HPER;
- hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
- v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper);
- if (!vper || !hper || !hsper)
- return -ENOLINK;
- for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
- const struct v4l2_bt_timings *bt;
- u32 lines, width, _hper, _hsper;
- u32 vmin, vmax, hmin, hmax, hsmin, hsmax;
- bool vmatch, hmatch, hsmatch;
- bt = &v4l2_dv_timings_presets[i].bt;
- width = V4L2_DV_BT_FRAME_WIDTH(bt);
- lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
- _hper = (u32)bt->pixelclock / width;
- if (bt->interlaced)
- lines /= 2;
- /* vper +/- 0.7% */
- vmin = ((27000000 / 1000) * 993) / _hper * lines;
- vmax = ((27000000 / 1000) * 1007) / _hper * lines;
- /* hper +/- 1.0% */
- hmin = ((27000000 / 100) * 99) / _hper;
- hmax = ((27000000 / 100) * 101) / _hper;
- /* hsper +/- 2 (take care to avoid 32bit overflow) */
- _hsper = 27000 * bt->hsync / ((u32)bt->pixelclock/1000);
- hsmin = _hsper - 2;
- hsmax = _hsper + 2;
- /* vmatch matches the framerate */
- vmatch = ((vper <= vmax) && (vper >= vmin)) ? 1 : 0;
- /* hmatch matches the width */
- hmatch = ((hper <= hmax) && (hper >= hmin)) ? 1 : 0;
- /* hsmatch matches the hswidth */
- hsmatch = ((hsper <= hsmax) && (hsper >= hsmin)) ? 1 : 0;
- if (hmatch && vmatch && hsmatch) {
- v4l2_print_dv_timings(sd->name, "Detected format: ",
- &v4l2_dv_timings_presets[i],
- false);
- if (timings)
- *timings = v4l2_dv_timings_presets[i];
- return 0;
- }
- }
- v4l_err(state->client, "no resolution match for timings: %d/%d/%d\n",
- vper, hper, hsper);
- return -ERANGE;
- }
- /* some sort of errata workaround for chip revision 0 (N1) */
- static void tda1997x_reset_n1(struct tda1997x_state *state)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg;
- /* clear HDMI mode flag in BCAPS */
- io_write(sd, REG_CLK_CFG, CLK_CFG_SEL_ACLK_EN | CLK_CFG_SEL_ACLK);
- io_write(sd, REG_PON_OVR_EN, PON_EN);
- io_write(sd, REG_PON_CBIAS, PON_EN);
- io_write(sd, REG_PON_PLL, PON_EN);
- reg = io_read(sd, REG_MODE_REC_CFG1);
- reg &= ~0x06;
- reg |= 0x02;
- io_write(sd, REG_MODE_REC_CFG1, reg);
- io_write(sd, REG_CLK_CFG, CLK_CFG_DIS);
- io_write(sd, REG_PON_OVR_EN, PON_DIS);
- reg = io_read(sd, REG_MODE_REC_CFG1);
- reg &= ~0x06;
- io_write(sd, REG_MODE_REC_CFG1, reg);
- }
- /*
- * Activity detection must only be notified when stable_clk_x AND active_x
- * bits are set to 1. If only stable_clk_x bit is set to 1 but not
- * active_x, it means that the TMDS clock is not in the defined range
- * and activity detection must not be notified.
- */
- static u8
- tda1997x_read_activity_status_regs(struct v4l2_subdev *sd)
- {
- u8 reg, status = 0;
- /* Read CLK_A_STATUS register */
- reg = io_read(sd, REG_CLK_A_STATUS);
- /* ignore if not active */
- if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
- reg &= ~MASK_CLK_STABLE;
- status |= ((reg & MASK_CLK_STABLE) >> 2);
- /* Read CLK_B_STATUS register */
- reg = io_read(sd, REG_CLK_B_STATUS);
- /* ignore if not active */
- if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
- reg &= ~MASK_CLK_STABLE;
- status |= ((reg & MASK_CLK_STABLE) >> 1);
- /* Read the SUS_STATUS register */
- reg = io_read(sd, REG_SUS_STATUS);
- /* If state = 5 => TMDS is locked */
- if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED)
- status |= MASK_SUS_STATE;
- else
- status &= ~MASK_SUS_STATE;
- return status;
- }
- static void
- set_rgb_quantization_range(struct tda1997x_state *state)
- {
- struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
- state->colorimetry = v4l2_hdmi_rx_colorimetry(&state->avi_infoframe,
- NULL,
- state->timings.bt.height);
- /* If ycbcr_enc is V4L2_YCBCR_ENC_DEFAULT, we receive RGB */
- if (c->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
- switch (state->rgb_quantization_range) {
- case V4L2_DV_RGB_RANGE_LIMITED:
- c->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- break;
- case V4L2_DV_RGB_RANGE_FULL:
- c->quantization = V4L2_QUANTIZATION_LIM_RANGE;
- break;
- }
- }
- v4l_dbg(1, debug, state->client,
- "colorspace=%d/%d colorimetry=%d range=%s content=%d\n",
- state->avi_infoframe.colorspace, c->colorspace,
- state->avi_infoframe.colorimetry,
- v4l2_quantization_names[c->quantization],
- state->avi_infoframe.content_type);
- }
- /* parse an infoframe and do some sanity checks on it */
- static unsigned int
- tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
- {
- struct v4l2_subdev *sd = &state->sd;
- union hdmi_infoframe frame;
- u8 buffer[40];
- u8 reg;
- int len, err;
- /* read data */
- len = io_readn(sd, addr, sizeof(buffer), buffer);
- err = hdmi_infoframe_unpack(&frame, buffer);
- if (err) {
- v4l_err(state->client,
- "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
- len, addr, buffer[0]);
- return err;
- }
- hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
- switch (frame.any.type) {
- /* Audio InfoFrame: see HDMI spec 8.2.2 */
- case HDMI_INFOFRAME_TYPE_AUDIO:
- /* sample rate */
- switch (frame.audio.sample_frequency) {
- case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
- state->audio_samplerate = 32000;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
- state->audio_samplerate = 44100;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
- state->audio_samplerate = 48000;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
- state->audio_samplerate = 88200;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
- state->audio_samplerate = 96000;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
- state->audio_samplerate = 176400;
- break;
- case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
- state->audio_samplerate = 192000;
- break;
- default:
- case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
- break;
- }
- /* sample size */
- switch (frame.audio.sample_size) {
- case HDMI_AUDIO_SAMPLE_SIZE_16:
- state->audio_samplesize = 16;
- break;
- case HDMI_AUDIO_SAMPLE_SIZE_20:
- state->audio_samplesize = 20;
- break;
- case HDMI_AUDIO_SAMPLE_SIZE_24:
- state->audio_samplesize = 24;
- break;
- case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
- default:
- break;
- }
- /* Channel Count */
- state->audio_channels = frame.audio.channels;
- if (frame.audio.channel_allocation &&
- frame.audio.channel_allocation != state->audio_ch_alloc) {
- /* use the channel assignment from the infoframe */
- state->audio_ch_alloc = frame.audio.channel_allocation;
- tda1997x_configure_audout(sd, state->audio_ch_alloc);
- /* reset the audio FIFO */
- tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
- }
- break;
- /* Auxiliary Video information (AVI) InfoFrame: see HDMI spec 8.2.1 */
- case HDMI_INFOFRAME_TYPE_AVI:
- state->avi_infoframe = frame.avi;
- set_rgb_quantization_range(state);
- /* configure upsampler: 0=bypass 1=repeatchroma 2=interpolate */
- reg = io_read(sd, REG_PIX_REPEAT);
- reg &= ~PIX_REPEAT_MASK_UP_SEL;
- if (frame.avi.colorspace == HDMI_COLORSPACE_YUV422)
- reg |= (PIX_REPEAT_CHROMA << PIX_REPEAT_SHIFT);
- io_write(sd, REG_PIX_REPEAT, reg);
- /* ConfigurePixelRepeater: repeat n-times each pixel */
- reg = io_read(sd, REG_PIX_REPEAT);
- reg &= ~PIX_REPEAT_MASK_REP;
- reg |= frame.avi.pixel_repeat;
- io_write(sd, REG_PIX_REPEAT, reg);
- /* configure the receiver with the new colorspace */
- tda1997x_configure_csc(sd);
- break;
- default:
- break;
- }
- return 0;
- }
- static void tda1997x_irq_sus(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg, source;
- source = io_read(sd, REG_INT_FLG_CLR_SUS);
- io_write(sd, REG_INT_FLG_CLR_SUS, source);
- if (source & MASK_MPT) {
- /* reset MTP in use flag if set */
- if (state->mptrw_in_progress)
- state->mptrw_in_progress = 0;
- }
- if (source & MASK_SUS_END) {
- /* reset audio FIFO */
- reg = io_read(sd, REG_HDMI_INFO_RST);
- reg |= MASK_SR_FIFO_FIFO_CTRL;
- io_write(sd, REG_HDMI_INFO_RST, reg);
- reg &= ~MASK_SR_FIFO_FIFO_CTRL;
- io_write(sd, REG_HDMI_INFO_RST, reg);
- /* reset HDMI flags */
- state->hdmi_status = 0;
- }
- /* filter FMT interrupt based on SUS state */
- reg = io_read(sd, REG_SUS_STATUS);
- if (((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED)
- || (source & MASK_MPT)) {
- source &= ~MASK_FMT;
- }
- if (source & (MASK_FMT | MASK_SUS_END)) {
- reg = io_read(sd, REG_SUS_STATUS);
- if ((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED) {
- v4l_err(state->client, "BAD SUS STATUS\n");
- return;
- }
- if (debug)
- tda1997x_detect_std(state, NULL);
- /* notify user of change in resolution */
- v4l2_subdev_notify_event(&state->sd, &tda1997x_ev_fmt);
- }
- }
- static void tda1997x_irq_ddc(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 source;
- source = io_read(sd, REG_INT_FLG_CLR_DDC);
- io_write(sd, REG_INT_FLG_CLR_DDC, source);
- if (source & MASK_EDID_MTP) {
- /* reset MTP in use flag if set */
- if (state->mptrw_in_progress)
- state->mptrw_in_progress = 0;
- }
- /* Detection of +5V */
- if (source & MASK_DET_5V) {
- v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
- tda1997x_detect_tx_5v(sd));
- }
- }
- static void tda1997x_irq_rate(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg, source;
- u8 irq_status;
- source = io_read(sd, REG_INT_FLG_CLR_RATE);
- io_write(sd, REG_INT_FLG_CLR_RATE, source);
- /* read status regs */
- irq_status = tda1997x_read_activity_status_regs(sd);
- /*
- * read clock status reg until INT_FLG_CLR_RATE is still 0
- * after the read to make sure its the last one
- */
- reg = source;
- while (reg != 0) {
- irq_status = tda1997x_read_activity_status_regs(sd);
- reg = io_read(sd, REG_INT_FLG_CLR_RATE);
- io_write(sd, REG_INT_FLG_CLR_RATE, reg);
- source |= reg;
- }
- /* we only pay attention to stability change events */
- if (source & (MASK_RATE_A_ST | MASK_RATE_B_ST)) {
- int input = (source & MASK_RATE_A_ST)?0:1;
- u8 mask = 1<<input;
- /* state change */
- if ((irq_status & mask) != (state->activity_status & mask)) {
- /* activity lost */
- if ((irq_status & mask) == 0) {
- v4l_info(state->client,
- "HDMI-%c: Digital Activity Lost\n",
- input+'A');
- /* bypass up/down sampler and pixel repeater */
- reg = io_read(sd, REG_PIX_REPEAT);
- reg &= ~PIX_REPEAT_MASK_UP_SEL;
- reg &= ~PIX_REPEAT_MASK_REP;
- io_write(sd, REG_PIX_REPEAT, reg);
- if (state->chip_revision == 0)
- tda1997x_reset_n1(state);
- state->input_detect[input] = 0;
- v4l2_subdev_notify_event(sd, &tda1997x_ev_fmt);
- }
- /* activity detected */
- else {
- v4l_info(state->client,
- "HDMI-%c: Digital Activity Detected\n",
- input+'A');
- state->input_detect[input] = 1;
- }
- /* hold onto current state */
- state->activity_status = (irq_status & mask);
- }
- }
- }
- static void tda1997x_irq_info(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 source;
- source = io_read(sd, REG_INT_FLG_CLR_INFO);
- io_write(sd, REG_INT_FLG_CLR_INFO, source);
- /* Audio infoframe */
- if (source & MASK_AUD_IF) {
- tda1997x_parse_infoframe(state, AUD_IF);
- source &= ~MASK_AUD_IF;
- }
- /* Source Product Descriptor infoframe change */
- if (source & MASK_SPD_IF) {
- tda1997x_parse_infoframe(state, SPD_IF);
- source &= ~MASK_SPD_IF;
- }
- /* Auxiliary Video Information infoframe */
- if (source & MASK_AVI_IF) {
- tda1997x_parse_infoframe(state, AVI_IF);
- source &= ~MASK_AVI_IF;
- }
- }
- static void tda1997x_irq_audio(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg, source;
- source = io_read(sd, REG_INT_FLG_CLR_AUDIO);
- io_write(sd, REG_INT_FLG_CLR_AUDIO, source);
- /* reset audio FIFO on FIFO pointer error or audio mute */
- if (source & MASK_ERROR_FIFO_PT ||
- source & MASK_MUTE_FLG) {
- /* audio reset audio FIFO */
- reg = io_read(sd, REG_SUS_STATUS);
- if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED) {
- reg = io_read(sd, REG_HDMI_INFO_RST);
- reg |= MASK_SR_FIFO_FIFO_CTRL;
- io_write(sd, REG_HDMI_INFO_RST, reg);
- reg &= ~MASK_SR_FIFO_FIFO_CTRL;
- io_write(sd, REG_HDMI_INFO_RST, reg);
- /* reset channel status IT if present */
- source &= ~(MASK_CH_STATE);
- }
- }
- if (source & MASK_AUDIO_FREQ_FLG) {
- static const int freq[] = {
- 0, 32000, 44100, 48000, 88200, 96000, 176400, 192000
- };
- reg = io_read(sd, REG_AUDIO_FREQ);
- state->audio_samplerate = freq[reg & 7];
- v4l_info(state->client, "Audio Frequency Change: %dHz\n",
- state->audio_samplerate);
- }
- if (source & MASK_AUDIO_FLG) {
- reg = io_read(sd, REG_AUDIO_FLAGS);
- if (reg & BIT(AUDCFG_TYPE_DST))
- state->audio_type = AUDCFG_TYPE_DST;
- if (reg & BIT(AUDCFG_TYPE_OBA))
- state->audio_type = AUDCFG_TYPE_OBA;
- if (reg & BIT(AUDCFG_TYPE_HBR))
- state->audio_type = AUDCFG_TYPE_HBR;
- if (reg & BIT(AUDCFG_TYPE_PCM))
- state->audio_type = AUDCFG_TYPE_PCM;
- v4l_info(state->client, "Audio Type: %s\n",
- audtype_names[state->audio_type]);
- }
- }
- static void tda1997x_irq_hdcp(struct tda1997x_state *state, u8 *flags)
- {
- struct v4l2_subdev *sd = &state->sd;
- u8 reg, source;
- source = io_read(sd, REG_INT_FLG_CLR_HDCP);
- io_write(sd, REG_INT_FLG_CLR_HDCP, source);
- /* reset MTP in use flag if set */
- if (source & MASK_HDCP_MTP)
- state->mptrw_in_progress = 0;
- if (source & MASK_STATE_C5) {
- /* REPEATER: mask AUDIO and IF irqs to avoid IF during auth */
- reg = io_read(sd, REG_INT_MASK_TOP);
- reg &= ~(INTERRUPT_AUDIO | INTERRUPT_INFO);
- io_write(sd, REG_INT_MASK_TOP, reg);
- *flags &= (INTERRUPT_AUDIO | INTERRUPT_INFO);
- }
- }
- static irqreturn_t tda1997x_isr_thread(int irq, void *d)
- {
- struct tda1997x_state *state = d;
- struct v4l2_subdev *sd = &state->sd;
- u8 flags;
- mutex_lock(&state->lock);
- do {
- /* read interrupt flags */
- flags = io_read(sd, REG_INT_FLG_CLR_TOP);
- if (flags == 0)
- break;
- /* SUS interrupt source (Input activity events) */
- if (flags & INTERRUPT_SUS)
- tda1997x_irq_sus(state, &flags);
- /* DDC interrupt source (Display Data Channel) */
- else if (flags & INTERRUPT_DDC)
- tda1997x_irq_ddc(state, &flags);
- /* RATE interrupt source (Digital Input activity) */
- else if (flags & INTERRUPT_RATE)
- tda1997x_irq_rate(state, &flags);
- /* Infoframe change interrupt */
- else if (flags & INTERRUPT_INFO)
- tda1997x_irq_info(state, &flags);
- /* Audio interrupt source:
- * freq change, DST,OBA,HBR,ASP flags, mute, FIFO err
- */
- else if (flags & INTERRUPT_AUDIO)
- tda1997x_irq_audio(state, &flags);
- /* HDCP interrupt source (content protection) */
- if (flags & INTERRUPT_HDCP)
- tda1997x_irq_hdcp(state, &flags);
- } while (flags != 0);
- mutex_unlock(&state->lock);
- return IRQ_HANDLED;
- }
- /* -----------------------------------------------------------------------------
- * v4l2_subdev_video_ops
- */
- static int
- tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status)
- {
- struct tda1997x_state *state = to_state(sd);
- u32 vper;
- u16 hper;
- u16 hsper;
- mutex_lock(&state->lock);
- vper = io_read24(sd, REG_V_PER) & MASK_VPER;
- hper = io_read16(sd, REG_H_PER) & MASK_HPER;
- hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
- /*
- * The tda1997x supports A/B inputs but only a single output.
- * The irq handler monitors for timing changes on both inputs and
- * sets the input_detect array to 0|1 depending on signal presence.
- * I believe selection of A vs B is automatic.
- *
- * The vper/hper/hsper registers provide the frame period, line period
- * and horiz sync period (units of MCLK clock cycles (27MHz)) and
- * testing shows these values to be random if no signal is present
- * or locked.
- */
- v4l2_dbg(1, debug, sd, "inputs:%d/%d timings:%d/%d/%d\n",
- state->input_detect[0], state->input_detect[1],
- vper, hper, hsper);
- if (!state->input_detect[0] && !state->input_detect[1])
- *status = V4L2_IN_ST_NO_SIGNAL;
- else if (!vper || !hper || !hsper)
- *status = V4L2_IN_ST_NO_SYNC;
- else
- *status = 0;
- mutex_unlock(&state->lock);
- return 0;
- };
- static int tda1997x_s_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *timings)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s\n", __func__);
- if (v4l2_match_dv_timings(&state->timings, timings, 0, false))
- return 0; /* no changes */
- if (!v4l2_valid_dv_timings(timings, &tda1997x_dv_timings_cap,
- NULL, NULL))
- return -ERANGE;
- mutex_lock(&state->lock);
- state->timings = *timings;
- /* setup frame detection window and VHREF timing generator */
- tda1997x_configure_vhref(sd);
- /* configure colorspace conversion */
- tda1997x_configure_csc(sd);
- mutex_unlock(&state->lock);
- return 0;
- }
- static int tda1997x_g_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *timings)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s\n", __func__);
- mutex_lock(&state->lock);
- *timings = state->timings;
- mutex_unlock(&state->lock);
- return 0;
- }
- static int tda1997x_query_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *timings)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s\n", __func__);
- memset(timings, 0, sizeof(struct v4l2_dv_timings));
- mutex_lock(&state->lock);
- tda1997x_detect_std(state, timings);
- mutex_unlock(&state->lock);
- return 0;
- }
- static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
- .g_input_status = tda1997x_g_input_status,
- .s_dv_timings = tda1997x_s_dv_timings,
- .g_dv_timings = tda1997x_g_dv_timings,
- .query_dv_timings = tda1997x_query_dv_timings,
- };
- /* -----------------------------------------------------------------------------
- * v4l2_subdev_pad_ops
- */
- static int tda1997x_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
- {
- struct tda1997x_state *state = to_state(sd);
- struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
- mf->code = state->mbus_codes[0];
- return 0;
- }
- static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s %d\n", __func__, code->index);
- if (code->index >= ARRAY_SIZE(state->mbus_codes))
- return -EINVAL;
- if (!state->mbus_codes[code->index])
- return -EINVAL;
- code->code = state->mbus_codes[code->index];
- return 0;
- }
- static void tda1997x_fill_format(struct tda1997x_state *state,
- struct v4l2_mbus_framefmt *format)
- {
- const struct v4l2_bt_timings *bt;
- memset(format, 0, sizeof(*format));
- bt = &state->timings.bt;
- format->width = bt->width;
- format->height = bt->height;
- format->colorspace = state->colorimetry.colorspace;
- format->field = (bt->interlaced) ?
- V4L2_FIELD_SEQ_TB : V4L2_FIELD_NONE;
- }
- static int tda1997x_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s pad=%d which=%d\n",
- __func__, format->pad, format->which);
- tda1997x_fill_format(state, &format->format);
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
- format->format.code = fmt->code;
- } else
- format->format.code = state->mbus_code;
- return 0;
- }
- static int tda1997x_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
- {
- struct tda1997x_state *state = to_state(sd);
- u32 code = 0;
- int i;
- v4l_dbg(1, debug, state->client, "%s pad=%d which=%d fmt=0x%x\n",
- __func__, format->pad, format->which, format->format.code);
- for (i = 0; i < ARRAY_SIZE(state->mbus_codes); i++) {
- if (format->format.code == state->mbus_codes[i]) {
- code = state->mbus_codes[i];
- break;
- }
- }
- if (!code)
- code = state->mbus_codes[0];
- tda1997x_fill_format(state, &format->format);
- format->format.code = code;
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
- *fmt = format->format;
- } else {
- int ret = tda1997x_setup_format(state, format->format.code);
- if (ret)
- return ret;
- /* mbus_code has changed - re-configure csc/vidout */
- tda1997x_configure_csc(sd);
- tda1997x_configure_vidout(state);
- }
- return 0;
- }
- static int tda1997x_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
- {
- struct tda1997x_state *state = to_state(sd);
- v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
- memset(edid->reserved, 0, sizeof(edid->reserved));
- if (edid->start_block == 0 && edid->blocks == 0) {
- edid->blocks = state->edid.blocks;
- return 0;
- }
- if (!state->edid.present)
- return -ENODATA;
- if (edid->start_block >= state->edid.blocks)
- return -EINVAL;
- if (edid->start_block + edid->blocks > state->edid.blocks)
- edid->blocks = state->edid.blocks - edid->start_block;
- memcpy(edid->edid, state->edid.edid + edid->start_block * 128,
- edid->blocks * 128);
- return 0;
- }
- static int tda1997x_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
- {
- struct tda1997x_state *state = to_state(sd);
- int i;
- v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
- memset(edid->reserved, 0, sizeof(edid->reserved));
- if (edid->start_block != 0)
- return -EINVAL;
- if (edid->blocks == 0) {
- state->edid.blocks = 0;
- state->edid.present = 0;
- tda1997x_disable_edid(sd);
- return 0;
- }
- if (edid->blocks > 2) {
- edid->blocks = 2;
- return -E2BIG;
- }
- tda1997x_disable_edid(sd);
- /* write base EDID */
- for (i = 0; i < 128; i++)
- io_write(sd, REG_EDID_IN_BYTE0 + i, edid->edid[i]);
- /* write CEA Extension */
- for (i = 0; i < 128; i++)
- io_write(sd, REG_EDID_IN_BYTE128 + i, edid->edid[i+128]);
- tda1997x_enable_edid(sd);
- return 0;
- }
- static int tda1997x_get_dv_timings_cap(struct v4l2_subdev *sd,
- struct v4l2_dv_timings_cap *cap)
- {
- *cap = tda1997x_dv_timings_cap;
- return 0;
- }
- static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_enum_dv_timings *timings)
- {
- return v4l2_enum_dv_timings_cap(timings, &tda1997x_dv_timings_cap,
- NULL, NULL);
- }
- static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = {
- .init_cfg = tda1997x_init_cfg,
- .enum_mbus_code = tda1997x_enum_mbus_code,
- .get_fmt = tda1997x_get_format,
- .set_fmt = tda1997x_set_format,
- .get_edid = tda1997x_get_edid,
- .set_edid = tda1997x_set_edid,
- .dv_timings_cap = tda1997x_get_dv_timings_cap,
- .enum_dv_timings = tda1997x_enum_dv_timings,
- };
- /* -----------------------------------------------------------------------------
- * v4l2_subdev_core_ops
- */
- static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
- {
- struct tda1997x_state *state = to_state(sd);
- union hdmi_infoframe frame;
- u8 buffer[40];
- int len, err;
- /* read data */
- len = io_readn(sd, addr, sizeof(buffer), buffer);
- v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
- err = hdmi_infoframe_unpack(&frame, buffer);
- if (err) {
- v4l_err(state->client,
- "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
- len, addr, buffer[0]);
- return err;
- }
- hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
- return 0;
- }
- static int tda1997x_log_status(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- struct v4l2_dv_timings timings;
- struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
- v4l2_info(sd, "-----Chip status-----\n");
- v4l2_info(sd, "Chip: %s N%d\n", state->info->name,
- state->chip_revision + 1);
- v4l2_info(sd, "EDID Enabled: %s\n", state->edid.present ? "yes" : "no");
- v4l2_info(sd, "-----Signal status-----\n");
- v4l2_info(sd, "Cable detected (+5V power): %s\n",
- tda1997x_detect_tx_5v(sd) ? "yes" : "no");
- v4l2_info(sd, "HPD detected: %s\n",
- tda1997x_detect_tx_hpd(sd) ? "yes" : "no");
- v4l2_info(sd, "-----Video Timings-----\n");
- switch (tda1997x_detect_std(state, &timings)) {
- case -ENOLINK:
- v4l2_info(sd, "No video detected\n");
- break;
- case -ERANGE:
- v4l2_info(sd, "Invalid signal detected\n");
- break;
- }
- v4l2_print_dv_timings(sd->name, "Configured format: ",
- &state->timings, true);
- v4l2_info(sd, "-----Color space-----\n");
- v4l2_info(sd, "Input color space: %s %s %s",
- hdmi_colorspace_names[avi->colorspace],
- (avi->colorspace == HDMI_COLORSPACE_RGB) ? "" :
- hdmi_colorimetry_names[avi->colorimetry],
- v4l2_quantization_names[state->colorimetry.quantization]);
- v4l2_info(sd, "Output color space: %s",
- vidfmt_names[state->vid_fmt]);
- v4l2_info(sd, "Color space conversion: %s", state->conv ?
- state->conv->name : "None");
- v4l2_info(sd, "-----Audio-----\n");
- if (state->audio_channels) {
- v4l2_info(sd, "audio: %dch %dHz\n", state->audio_channels,
- state->audio_samplerate);
- } else {
- v4l2_info(sd, "audio: none\n");
- }
- v4l2_info(sd, "-----Infoframes-----\n");
- tda1997x_log_infoframe(sd, AUD_IF);
- tda1997x_log_infoframe(sd, SPD_IF);
- tda1997x_log_infoframe(sd, AVI_IF);
- return 0;
- }
- static int tda1997x_subscribe_event(struct v4l2_subdev *sd,
- struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
- {
- switch (sub->type) {
- case V4L2_EVENT_SOURCE_CHANGE:
- return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
- case V4L2_EVENT_CTRL:
- return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
- default:
- return -EINVAL;
- }
- }
- static const struct v4l2_subdev_core_ops tda1997x_core_ops = {
- .log_status = tda1997x_log_status,
- .subscribe_event = tda1997x_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
- };
- /* -----------------------------------------------------------------------------
- * v4l2_subdev_ops
- */
- static const struct v4l2_subdev_ops tda1997x_subdev_ops = {
- .core = &tda1997x_core_ops,
- .video = &tda1997x_video_ops,
- .pad = &tda1997x_pad_ops,
- };
- /* -----------------------------------------------------------------------------
- * v4l2_controls
- */
- static int tda1997x_s_ctrl(struct v4l2_ctrl *ctrl)
- {
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct tda1997x_state *state = to_state(sd);
- switch (ctrl->id) {
- /* allow overriding the default RGB quantization range */
- case V4L2_CID_DV_RX_RGB_RANGE:
- state->rgb_quantization_range = ctrl->val;
- set_rgb_quantization_range(state);
- tda1997x_configure_csc(sd);
- return 0;
- }
- return -EINVAL;
- };
- static int tda1997x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
- {
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct tda1997x_state *state = to_state(sd);
- if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) {
- ctrl->val = state->avi_infoframe.content_type;
- return 0;
- }
- return -EINVAL;
- };
- static const struct v4l2_ctrl_ops tda1997x_ctrl_ops = {
- .s_ctrl = tda1997x_s_ctrl,
- .g_volatile_ctrl = tda1997x_g_volatile_ctrl,
- };
- static int tda1997x_core_init(struct v4l2_subdev *sd)
- {
- struct tda1997x_state *state = to_state(sd);
- struct tda1997x_platform_data *pdata = &state->pdata;
- u8 reg;
- int i;
- /* disable HPD */
- io_write(sd, REG_HPD_AUTO_CTRL, HPD_AUTO_HPD_UNSEL);
- if (state->chip_revision == 0) {
- io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_DIS_HDCP | MAN_RST_HDCP);
- io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
- }
- /* reset infoframe at end of start-up-sequencer */
- io_write(sd, REG_SUS_SET_RGB2, 0x06);
- io_write(sd, REG_SUS_SET_RGB3, 0x06);
- /* Enable TMDS pull-ups */
- io_write(sd, REG_RT_MAN_CTRL, RT_MAN_CTRL_RT |
- RT_MAN_CTRL_RT_B | RT_MAN_CTRL_RT_A);
- /* enable sync measurement timing */
- tda1997x_cec_write(sd, REG_PWR_CONTROL & 0xff, 0x04);
- /* adjust CEC clock divider */
- tda1997x_cec_write(sd, REG_OSC_DIVIDER & 0xff, 0x03);
- tda1997x_cec_write(sd, REG_EN_OSC_PERIOD_LSB & 0xff, 0xa0);
- io_write(sd, REG_TIMER_D, 0x54);
- /* enable power switch */
- reg = tda1997x_cec_read(sd, REG_CONTROL & 0xff);
- reg |= 0x20;
- tda1997x_cec_write(sd, REG_CONTROL & 0xff, reg);
- mdelay(50);
- /* read the chip version */
- reg = io_read(sd, REG_VERSION);
- /* get the chip configuration */
- reg = io_read(sd, REG_CMTP_REG10);
- /* enable interrupts we care about */
- io_write(sd, REG_INT_MASK_TOP,
- INTERRUPT_HDCP | INTERRUPT_AUDIO | INTERRUPT_INFO |
- INTERRUPT_RATE | INTERRUPT_SUS);
- /* config_mtp,fmt,sus_end,sus_st */
- io_write(sd, REG_INT_MASK_SUS, MASK_MPT | MASK_FMT | MASK_SUS_END);
- /* rate stability change for inputs A/B */
- io_write(sd, REG_INT_MASK_RATE, MASK_RATE_B_ST | MASK_RATE_A_ST);
- /* aud,spd,avi*/
- io_write(sd, REG_INT_MASK_INFO,
- MASK_AUD_IF | MASK_SPD_IF | MASK_AVI_IF);
- /* audio_freq,audio_flg,mute_flg,fifo_err */
- io_write(sd, REG_INT_MASK_AUDIO,
- MASK_AUDIO_FREQ_FLG | MASK_AUDIO_FLG | MASK_MUTE_FLG |
- MASK_ERROR_FIFO_PT);
- /* HDCP C5 state reached */
- io_write(sd, REG_INT_MASK_HDCP, MASK_STATE_C5);
- /* 5V detect and HDP pulse end */
- io_write(sd, REG_INT_MASK_DDC, MASK_DET_5V);
- /* don't care about AFE/MODE */
- io_write(sd, REG_INT_MASK_AFE, 0);
- io_write(sd, REG_INT_MASK_MODE, 0);
- /* clear all interrupts */
- io_write(sd, REG_INT_FLG_CLR_TOP, 0xff);
- io_write(sd, REG_INT_FLG_CLR_SUS, 0xff);
- io_write(sd, REG_INT_FLG_CLR_DDC, 0xff);
- io_write(sd, REG_INT_FLG_CLR_RATE, 0xff);
- io_write(sd, REG_INT_FLG_CLR_MODE, 0xff);
- io_write(sd, REG_INT_FLG_CLR_INFO, 0xff);
- io_write(sd, REG_INT_FLG_CLR_AUDIO, 0xff);
- io_write(sd, REG_INT_FLG_CLR_HDCP, 0xff);
- io_write(sd, REG_INT_FLG_CLR_AFE, 0xff);
- /* init TMDS equalizer */
- if (state->chip_revision == 0)
- io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
- io_write24(sd, REG_CLK_MIN_RATE, CLK_MIN_RATE);
- io_write24(sd, REG_CLK_MAX_RATE, CLK_MAX_RATE);
- if (state->chip_revision == 0)
- io_write(sd, REG_WDL_CFG, WDL_CFG_VAL);
- /* DC filter */
- io_write(sd, REG_DEEP_COLOR_CTRL, DC_FILTER_VAL);
- /* disable test pattern */
- io_write(sd, REG_SVC_MODE, 0x00);
- /* update HDMI INFO CTRL */
- io_write(sd, REG_INFO_CTRL, 0xff);
- /* write HDMI INFO EXCEED value */
- io_write(sd, REG_INFO_EXCEED, 3);
- if (state->chip_revision == 0)
- tda1997x_reset_n1(state);
- /*
- * No HDCP acknowledge when HDCP is disabled
- * and reset SUS to force format detection
- */
- tda1997x_hdmi_info_reset(sd, NACK_HDCP, true);
- /* Set HPD low */
- tda1997x_manual_hpd(sd, HPD_LOW_BP);
- /* Configure receiver capabilities */
- io_write(sd, REG_HDCP_BCAPS, HDCP_HDMI | HDCP_FAST_REAUTH);
- /* Configure HDMI: Auto HDCP mode, packet controlled mute */
- reg = HDMI_CTRL_MUTE_AUTO << HDMI_CTRL_MUTE_SHIFT;
- reg |= HDMI_CTRL_HDCP_AUTO << HDMI_CTRL_HDCP_SHIFT;
- io_write(sd, REG_HDMI_CTRL, reg);
- /* reset start-up-sequencer to force format detection */
- tda1997x_hdmi_info_reset(sd, 0, true);
- /* disable matrix conversion */
- reg = io_read(sd, REG_VDP_CTRL);
- reg |= VDP_CTRL_MATRIX_BP;
- io_write(sd, REG_VDP_CTRL, reg);
- /* set video output mode */
- tda1997x_configure_vidout(state);
- /* configure video output port */
- for (i = 0; i < 9; i++) {
- v4l_dbg(1, debug, state->client, "vidout_cfg[%d]=0x%02x\n", i,
- pdata->vidout_port_cfg[i]);
- io_write(sd, REG_VP35_32_CTRL + i, pdata->vidout_port_cfg[i]);
- }
- /* configure audio output port */
- tda1997x_configure_audout(sd, 0);
- /* configure audio clock freq */
- switch (pdata->audout_mclk_fs) {
- case 512:
- reg = AUDIO_CLOCK_SEL_512FS;
- break;
- case 256:
- reg = AUDIO_CLOCK_SEL_256FS;
- break;
- case 128:
- reg = AUDIO_CLOCK_SEL_128FS;
- break;
- case 64:
- reg = AUDIO_CLOCK_SEL_64FS;
- break;
- case 32:
- reg = AUDIO_CLOCK_SEL_32FS;
- break;
- default:
- reg = AUDIO_CLOCK_SEL_16FS;
- break;
- }
- io_write(sd, REG_AUDIO_CLOCK, reg);
- /* reset advanced infoframes (ISRC1/ISRC2/ACP) */
- tda1997x_hdmi_info_reset(sd, RESET_AI, false);
- /* reset infoframe */
- tda1997x_hdmi_info_reset(sd, RESET_IF, false);
- /* reset audio infoframes */
- tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
- /* reset gamut */
- tda1997x_hdmi_info_reset(sd, RESET_GAMUT, false);
- /* get initial HDMI status */
- state->hdmi_status = io_read(sd, REG_HDMI_FLAGS);
- return 0;
- }
- static int tda1997x_set_power(struct tda1997x_state *state, bool on)
- {
- int ret = 0;
- if (on) {
- ret = regulator_bulk_enable(TDA1997X_NUM_SUPPLIES,
- state->supplies);
- msleep(300);
- } else {
- ret = regulator_bulk_disable(TDA1997X_NUM_SUPPLIES,
- state->supplies);
- }
- return ret;
- }
- static const struct i2c_device_id tda1997x_i2c_id[] = {
- {"tda19971", (kernel_ulong_t)&tda1997x_chip_info[TDA19971]},
- {"tda19973", (kernel_ulong_t)&tda1997x_chip_info[TDA19973]},
- { },
- };
- MODULE_DEVICE_TABLE(i2c, tda1997x_i2c_id);
- static const struct of_device_id tda1997x_of_id[] __maybe_unused = {
- { .compatible = "nxp,tda19971", .data = &tda1997x_chip_info[TDA19971] },
- { .compatible = "nxp,tda19973", .data = &tda1997x_chip_info[TDA19973] },
- { },
- };
- MODULE_DEVICE_TABLE(of, tda1997x_of_id);
- static int tda1997x_parse_dt(struct tda1997x_state *state)
- {
- struct tda1997x_platform_data *pdata = &state->pdata;
- struct v4l2_fwnode_endpoint bus_cfg;
- struct device_node *ep;
- struct device_node *np;
- unsigned int flags;
- const char *str;
- int ret;
- u32 v;
- /*
- * setup default values:
- * - HREF: active high from start to end of row
- * - VS: Vertical Sync active high at beginning of frame
- * - DE: Active high when data valid
- * - A_CLK: 128*Fs
- */
- pdata->vidout_sel_hs = HS_HREF_SEL_HREF_VHREF;
- pdata->vidout_sel_vs = VS_VREF_SEL_VREF_HDMI;
- pdata->vidout_sel_de = DE_FREF_SEL_DE_VHREF;
- np = state->client->dev.of_node;
- ep = of_graph_get_next_endpoint(np, NULL);
- if (!ep)
- return -EINVAL;
- ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
- if (ret) {
- of_node_put(ep);
- return ret;
- }
- of_node_put(ep);
- pdata->vidout_bus_type = bus_cfg.bus_type;
- /* polarity of HS/VS/DE */
- flags = bus_cfg.bus.parallel.flags;
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- pdata->vidout_inv_hs = 1;
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- pdata->vidout_inv_vs = 1;
- if (flags & V4L2_MBUS_DATA_ACTIVE_LOW)
- pdata->vidout_inv_de = 1;
- pdata->vidout_bus_width = bus_cfg.bus.parallel.bus_width;
- /* video output port config */
- ret = of_property_count_u32_elems(np, "nxp,vidout-portcfg");
- if (ret > 0) {
- u32 reg, val, i;
- for (i = 0; i < ret / 2 && i < 9; i++) {
- of_property_read_u32_index(np, "nxp,vidout-portcfg",
- i * 2, ®);
- of_property_read_u32_index(np, "nxp,vidout-portcfg",
- i * 2 + 1, &val);
- if (reg < 9)
- pdata->vidout_port_cfg[reg] = val;
- }
- } else {
- v4l_err(state->client, "nxp,vidout-portcfg missing\n");
- return -EINVAL;
- }
- /* default to channel layout dictated by packet header */
- pdata->audout_layoutauto = true;
- pdata->audout_format = AUDFMT_TYPE_DISABLED;
- if (!of_property_read_string(np, "nxp,audout-format", &str)) {
- if (strcmp(str, "i2s") == 0)
- pdata->audout_format = AUDFMT_TYPE_I2S;
- else if (strcmp(str, "spdif") == 0)
- pdata->audout_format = AUDFMT_TYPE_SPDIF;
- else {
- v4l_err(state->client, "nxp,audout-format invalid\n");
- return -EINVAL;
- }
- if (!of_property_read_u32(np, "nxp,audout-layout", &v)) {
- switch (v) {
- case 0:
- case 1:
- break;
- default:
- v4l_err(state->client,
- "nxp,audout-layout invalid\n");
- return -EINVAL;
- }
- pdata->audout_layout = v;
- }
- if (!of_property_read_u32(np, "nxp,audout-width", &v)) {
- switch (v) {
- case 16:
- case 32:
- break;
- default:
- v4l_err(state->client,
- "nxp,audout-width invalid\n");
- return -EINVAL;
- }
- pdata->audout_width = v;
- }
- if (!of_property_read_u32(np, "nxp,audout-mclk-fs", &v)) {
- switch (v) {
- case 512:
- case 256:
- case 128:
- case 64:
- case 32:
- case 16:
- break;
- default:
- v4l_err(state->client,
- "nxp,audout-mclk-fs invalid\n");
- return -EINVAL;
- }
- pdata->audout_mclk_fs = v;
- }
- }
- return 0;
- }
- static int tda1997x_get_regulators(struct tda1997x_state *state)
- {
- int i;
- for (i = 0; i < TDA1997X_NUM_SUPPLIES; i++)
- state->supplies[i].supply = tda1997x_supply_name[i];
- return devm_regulator_bulk_get(&state->client->dev,
- TDA1997X_NUM_SUPPLIES,
- state->supplies);
- }
- static int tda1997x_identify_module(struct tda1997x_state *state)
- {
- struct v4l2_subdev *sd = &state->sd;
- enum tda1997x_type type;
- u8 reg;
- /* Read chip configuration*/
- reg = io_read(sd, REG_CMTP_REG10);
- state->tmdsb_clk = (reg >> 6) & 0x01; /* use tmds clock B_inv for B */
- state->tmdsb_soc = (reg >> 5) & 0x01; /* tmds of input B */
- state->port_30bit = (reg >> 2) & 0x03; /* 30bit vs 24bit */
- state->output_2p5 = (reg >> 1) & 0x01; /* output supply 2.5v */
- switch ((reg >> 4) & 0x03) {
- case 0x00:
- type = TDA19971;
- break;
- case 0x02:
- case 0x03:
- type = TDA19973;
- break;
- default:
- dev_err(&state->client->dev, "unsupported chip ID\n");
- return -EIO;
- }
- if (state->info->type != type) {
- dev_err(&state->client->dev, "chip id mismatch\n");
- return -EIO;
- }
- /* read chip revision */
- state->chip_revision = io_read(sd, REG_CMTP_REG11);
- return 0;
- }
- static const struct media_entity_operations tda1997x_media_ops = {
- .link_validate = v4l2_subdev_link_validate,
- };
- /* -----------------------------------------------------------------------------
- * HDMI Audio Codec
- */
- /* refine sample-rate based on HDMI source */
- static int tda1997x_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
- {
- struct tda1997x_state *state = snd_soc_dai_get_drvdata(dai);
- struct snd_soc_component *component = dai->component;
- struct snd_pcm_runtime *rtd = substream->runtime;
- int rate, err;
- rate = state->audio_samplerate;
- err = snd_pcm_hw_constraint_minmax(rtd, SNDRV_PCM_HW_PARAM_RATE,
- rate, rate);
- if (err < 0) {
- dev_err(component->dev, "failed to constrain samplerate to %dHz\n",
- rate);
- return err;
- }
- dev_info(component->dev, "set samplerate constraint to %dHz\n", rate);
- return 0;
- }
- static const struct snd_soc_dai_ops tda1997x_dai_ops = {
- .startup = tda1997x_pcm_startup,
- };
- static struct snd_soc_dai_driver tda1997x_audio_dai = {
- .name = "tda1997x",
- .capture = {
- .stream_name = "Capture",
- .channels_min = 2,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
- SNDRV_PCM_RATE_192000,
- },
- .ops = &tda1997x_dai_ops,
- };
- static int tda1997x_codec_probe(struct snd_soc_component *component)
- {
- return 0;
- }
- static void tda1997x_codec_remove(struct snd_soc_component *component)
- {
- }
- static struct snd_soc_component_driver tda1997x_codec_driver = {
- .probe = tda1997x_codec_probe,
- .remove = tda1997x_codec_remove,
- .idle_bias_on = 1,
- .use_pmdown_time = 1,
- .endianness = 1,
- .non_legacy_dai_naming = 1,
- };
- static int tda1997x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct tda1997x_state *state;
- struct tda1997x_platform_data *pdata;
- struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
- struct v4l2_ctrl *ctrl;
- static const struct v4l2_dv_timings cea1920x1080 =
- V4L2_DV_BT_CEA_1920X1080P60;
- u32 *mbus_codes;
- int i, ret;
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
- state = kzalloc(sizeof(struct tda1997x_state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
- state->client = client;
- pdata = &state->pdata;
- if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) {
- const struct of_device_id *oid;
- oid = of_match_node(tda1997x_of_id, client->dev.of_node);
- state->info = oid->data;
- ret = tda1997x_parse_dt(state);
- if (ret < 0) {
- v4l_err(client, "DT parsing error\n");
- goto err_free_state;
- }
- } else if (client->dev.platform_data) {
- struct tda1997x_platform_data *pdata =
- client->dev.platform_data;
- state->info =
- (const struct tda1997x_chip_info *)id->driver_data;
- state->pdata = *pdata;
- } else {
- v4l_err(client, "No platform data\n");
- ret = -ENODEV;
- goto err_free_state;
- }
- ret = tda1997x_get_regulators(state);
- if (ret)
- goto err_free_state;
- ret = tda1997x_set_power(state, 1);
- if (ret)
- goto err_free_state;
- mutex_init(&state->page_lock);
- mutex_init(&state->lock);
- state->page = 0xff;
- INIT_DELAYED_WORK(&state->delayed_work_enable_hpd,
- tda1997x_delayed_work_enable_hpd);
- /* set video format based on chip and bus width */
- ret = tda1997x_identify_module(state);
- if (ret)
- goto err_free_mutex;
- /* initialize subdev */
- sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_ops);
- snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
- id->name, i2c_adapter_id(client->adapter),
- client->addr);
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
- sd->entity.function = MEDIA_ENT_F_DV_DECODER;
- sd->entity.ops = &tda1997x_media_ops;
- /* set allowed mbus modes based on chip, bus-type, and bus-width */
- i = 0;
- mbus_codes = state->mbus_codes;
- switch (state->info->type) {
- case TDA19973:
- switch (pdata->vidout_bus_type) {
- case V4L2_MBUS_PARALLEL:
- switch (pdata->vidout_bus_width) {
- case 36:
- mbus_codes[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
- mbus_codes[i++] = MEDIA_BUS_FMT_YUV12_1X36;
- /* fall-through */
- case 24:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
- break;
- }
- break;
- case V4L2_MBUS_BT656:
- switch (pdata->vidout_bus_width) {
- case 36:
- case 24:
- case 12:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
- break;
- }
- break;
- default:
- break;
- }
- break;
- case TDA19971:
- switch (pdata->vidout_bus_type) {
- case V4L2_MBUS_PARALLEL:
- switch (pdata->vidout_bus_width) {
- case 24:
- mbus_codes[i++] = MEDIA_BUS_FMT_RGB888_1X24;
- mbus_codes[i++] = MEDIA_BUS_FMT_YUV8_1X24;
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
- /* fall through */
- case 20:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
- /* fall through */
- case 16:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
- break;
- }
- break;
- case V4L2_MBUS_BT656:
- switch (pdata->vidout_bus_width) {
- case 24:
- case 20:
- case 16:
- case 12:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
- /* fall through */
- case 10:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
- /* fall through */
- case 8:
- mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
- break;
- }
- break;
- default:
- break;
- }
- break;
- }
- if (WARN_ON(i > ARRAY_SIZE(state->mbus_codes))) {
- ret = -EINVAL;
- goto err_free_mutex;
- }
- /* default format */
- tda1997x_setup_format(state, state->mbus_codes[0]);
- state->timings = cea1920x1080;
- /*
- * default to SRGB full range quantization
- * (in case we don't get an infoframe such as DVI signal
- */
- state->colorimetry.colorspace = V4L2_COLORSPACE_SRGB;
- state->colorimetry.quantization = V4L2_QUANTIZATION_FULL_RANGE;
- /* disable/reset HDCP to get correct I2C access to Rx HDMI */
- io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_RST_HDCP | MAN_DIS_HDCP);
- /*
- * if N2 version, reset compdel_bp as it may generate some small pixel
- * shifts in case of embedded sync/or delay lower than 4
- */
- if (state->chip_revision != 0) {
- io_write(sd, REG_MAN_SUS_HDMI_SEL, 0x00);
- io_write(sd, REG_VDP_CTRL, 0x1f);
- }
- v4l_info(client, "NXP %s N%d detected\n", state->info->name,
- state->chip_revision + 1);
- v4l_info(client, "video: %dbit %s %d formats available\n",
- pdata->vidout_bus_width,
- (pdata->vidout_bus_type == V4L2_MBUS_PARALLEL) ?
- "parallel" : "BT656",
- i);
- if (pdata->audout_format) {
- v4l_info(client, "audio: %dch %s layout%d sysclk=%d*fs\n",
- pdata->audout_layout ? 2 : 8,
- audfmt_names[pdata->audout_format],
- pdata->audout_layout,
- pdata->audout_mclk_fs);
- }
- ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03);
- state->client_cec = i2c_new_dummy(client->adapter, ret);
- v4l_info(client, "CEC slave address 0x%02x\n", ret);
- ret = tda1997x_core_init(sd);
- if (ret)
- goto err_free_mutex;
- /* control handlers */
- hdl = &state->hdl;
- v4l2_ctrl_handler_init(hdl, 3);
- ctrl = v4l2_ctrl_new_std_menu(hdl, &tda1997x_ctrl_ops,
- V4L2_CID_DV_RX_IT_CONTENT_TYPE,
- V4L2_DV_IT_CONTENT_TYPE_NO_ITC, 0,
- V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
- if (ctrl)
- ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
- /* custom controls */
- state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
- state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl,
- &tda1997x_ctrl_ops,
- V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0,
- V4L2_DV_RGB_RANGE_AUTO);
- state->sd.ctrl_handler = hdl;
- if (hdl->error) {
- ret = hdl->error;
- goto err_free_handler;
- }
- v4l2_ctrl_handler_setup(hdl);
- /* initialize source pads */
- state->pads[TDA1997X_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&sd->entity, TDA1997X_NUM_PADS,
- state->pads);
- if (ret) {
- v4l_err(client, "failed entity_init: %d", ret);
- goto err_free_handler;
- }
- ret = v4l2_async_register_subdev(sd);
- if (ret)
- goto err_free_media;
- /* register audio DAI */
- if (pdata->audout_format) {
- u64 formats;
- if (pdata->audout_width == 32)
- formats = SNDRV_PCM_FMTBIT_S32_LE;
- else
- formats = SNDRV_PCM_FMTBIT_S16_LE;
- tda1997x_audio_dai.capture.formats = formats;
- ret = devm_snd_soc_register_component(&state->client->dev,
- &tda1997x_codec_driver,
- &tda1997x_audio_dai, 1);
- if (ret) {
- dev_err(&client->dev, "register audio codec failed\n");
- goto err_free_media;
- }
- dev_set_drvdata(&state->client->dev, state);
- v4l_info(state->client, "registered audio codec\n");
- }
- /* request irq */
- ret = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, tda1997x_isr_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- KBUILD_MODNAME, state);
- if (ret) {
- v4l_err(client, "irq%d reg failed: %d\n", client->irq, ret);
- goto err_free_media;
- }
- return 0;
- err_free_media:
- media_entity_cleanup(&sd->entity);
- err_free_handler:
- v4l2_ctrl_handler_free(&state->hdl);
- err_free_mutex:
- cancel_delayed_work(&state->delayed_work_enable_hpd);
- mutex_destroy(&state->page_lock);
- mutex_destroy(&state->lock);
- err_free_state:
- kfree(state);
- dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
- return ret;
- }
- static int tda1997x_remove(struct i2c_client *client)
- {
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct tda1997x_state *state = to_state(sd);
- struct tda1997x_platform_data *pdata = &state->pdata;
- if (pdata->audout_format) {
- mutex_destroy(&state->audio_lock);
- }
- disable_irq(state->client->irq);
- tda1997x_power_mode(state, 0);
- v4l2_async_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_ctrl_handler_free(&state->hdl);
- regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies);
- i2c_unregister_device(state->client_cec);
- cancel_delayed_work(&state->delayed_work_enable_hpd);
- mutex_destroy(&state->page_lock);
- mutex_destroy(&state->lock);
- kfree(state);
- return 0;
- }
- static struct i2c_driver tda1997x_i2c_driver = {
- .driver = {
- .name = "tda1997x",
- .of_match_table = of_match_ptr(tda1997x_of_id),
- },
- .probe = tda1997x_probe,
- .remove = tda1997x_remove,
- .id_table = tda1997x_i2c_id,
- };
- module_i2c_driver(tda1997x_i2c_driver);
- MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
- MODULE_DESCRIPTION("TDA1997X HDMI Receiver driver");
- MODULE_LICENSE("GPL v2");
|