From 67a5135a64acbd32f6c918849d268725f372b0e7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 09:12:45 -0500 Subject: media: vivid: add SPDX license info Replace the old license information with the corresponding SPDX license. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-cec.c | 14 +------------- drivers/media/platform/vivid/vivid-cec.h | 14 +------------- drivers/media/platform/vivid/vivid-core.c | 14 +------------- drivers/media/platform/vivid/vivid-core.h | 14 +------------- drivers/media/platform/vivid/vivid-ctrls.c | 14 +------------- drivers/media/platform/vivid/vivid-ctrls.h | 14 +------------- drivers/media/platform/vivid/vivid-kthread-cap.c | 14 +------------- drivers/media/platform/vivid/vivid-kthread-cap.h | 14 +------------- drivers/media/platform/vivid/vivid-kthread-out.c | 14 +------------- drivers/media/platform/vivid/vivid-kthread-out.h | 14 +------------- drivers/media/platform/vivid/vivid-osd.c | 14 +------------- drivers/media/platform/vivid/vivid-osd.h | 14 +------------- drivers/media/platform/vivid/vivid-radio-common.c | 14 +------------- drivers/media/platform/vivid/vivid-radio-common.h | 14 +------------- drivers/media/platform/vivid/vivid-radio-rx.c | 14 +------------- drivers/media/platform/vivid/vivid-radio-rx.h | 14 +------------- drivers/media/platform/vivid/vivid-radio-tx.c | 14 +------------- drivers/media/platform/vivid/vivid-radio-tx.h | 14 +------------- drivers/media/platform/vivid/vivid-rds-gen.c | 14 +------------- drivers/media/platform/vivid/vivid-rds-gen.h | 14 +------------- drivers/media/platform/vivid/vivid-sdr-cap.c | 14 +------------- drivers/media/platform/vivid/vivid-sdr-cap.h | 14 +------------- drivers/media/platform/vivid/vivid-vbi-cap.c | 14 +------------- drivers/media/platform/vivid/vivid-vbi-cap.h | 14 +------------- drivers/media/platform/vivid/vivid-vbi-gen.c | 14 +------------- drivers/media/platform/vivid/vivid-vbi-gen.h | 14 +------------- drivers/media/platform/vivid/vivid-vbi-out.c | 14 +------------- drivers/media/platform/vivid/vivid-vbi-out.h | 14 +------------- drivers/media/platform/vivid/vivid-vid-cap.c | 14 +------------- drivers/media/platform/vivid/vivid-vid-cap.h | 14 +------------- drivers/media/platform/vivid/vivid-vid-common.c | 14 +------------- drivers/media/platform/vivid/vivid-vid-common.h | 14 +------------- drivers/media/platform/vivid/vivid-vid-out.c | 14 +------------- drivers/media/platform/vivid/vivid-vid-out.h | 14 +------------- 34 files changed, 34 insertions(+), 442 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index b55d278d38a7..619bd8435b7f 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-cec.c - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h index 3926b1422777..7524ed48a914 100644 --- a/drivers/media/platform/vivid/vivid-cec.h +++ b/drivers/media/platform/vivid/vivid-cec.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-cec.h - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifdef CONFIG_VIDEO_VIVID_CEC diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 9f036c5f51b0..82ec216f2ad8 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-core.c - A Virtual Video Test Driver, core initialization * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index c90e4a0ab94e..477c80a4d44c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-core.h - core datastructures * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CORE_H_ diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 3f9d354827af..4b6b5d715031 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-ctrls.c - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h index 9bcca9d56359..6fad5f5d0054 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.h +++ b/drivers/media/platform/vivid/vivid-ctrls.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-ctrls.h - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CTRLS_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 6ca71aabb576..3fdb280c36ca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h index 5b92fc9a0d04..0f43015306d6 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.h +++ b/drivers/media/platform/vivid/vivid-kthread-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index 98eed5889bc1..9981e7548019 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h index 2bf04a17b05d..d5bcf44bbaca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.h +++ b/drivers/media/platform/vivid/vivid-kthread-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index bdc380b14e0c..bbbc1b6938a5 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-osd.c - osd support for testing overlays. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h index 57c9daa5940a..f9ac1af25dd3 100644 --- a/drivers/media/platform/vivid/vivid-osd.h +++ b/drivers/media/platform/vivid/vivid-osd.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-osd.h - output overlay support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_OSD_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c index 78c1e920670a..7c8efe38ff5b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.c +++ b/drivers/media/platform/vivid/vivid-radio-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-common.c - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h index 92fe589141b7..30a9900e5b2b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.h +++ b/drivers/media/platform/vivid/vivid-radio-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-common.h - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c index f834f7df8cf9..acbfea2cce76 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-rx.c - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h index 2b33edb60942..c9c7849f6f99 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.h +++ b/drivers/media/platform/vivid/vivid-radio-rx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-rx.h - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_RX_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c index 308b13f85dc0..1a3749ba5e7e 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.c +++ b/drivers/media/platform/vivid/vivid-radio-tx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-tx.c - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h index 3c3343d70cbc..c2bf1e7e634a 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.h +++ b/drivers/media/platform/vivid/vivid-radio-tx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-tx.h - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_TX_H_ diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c index 996e35e28d37..39ca9a56448c 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ b/drivers/media/platform/vivid/vivid-rds-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-rds-gen.c - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h index e55e3b22b7ca..35ac5742302b 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.h +++ b/drivers/media/platform/vivid/vivid-rds-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-rds-gen.h - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RDS_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index ebd7b9c4dd83..cfb7cb4d37a8 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-sdr-cap.c - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h index 43014b2733db..813c9248e5a7 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.h +++ b/drivers/media/platform/vivid/vivid-sdr-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-sdr-cap.h - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_SDR_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index d66ef95dd2b5..92a852955173 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-cap.c - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h index 2d8ea0bac743..91d2de01381c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.h +++ b/drivers/media/platform/vivid/vivid-vbi-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-cap.h - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c index 02c79d7cedab..acc98445a1fa 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-gen.c - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h index 8444abe905ea..2657a7f5571c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.h +++ b/drivers/media/platform/vivid/vivid-vbi-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-gen.h - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index d2989195cf03..69486c130a7e 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-out.c - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h index 6555ba9d2860..76584940cdaf 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.h +++ b/drivers/media/platform/vivid/vivid-vbi-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-out.h - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 0fbbcde19f0d..808967c7b0ab 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-cap.c - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h index 94079815dbc2..47d8b48820df 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.h +++ b/drivers/media/platform/vivid/vivid-vid-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-cap.h - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index a651527d80db..cc67f403a808 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-common.c - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 4b6175eab8a2..29b6c0b40a1b 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-common.h - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 0b1b6218ede8..51fec66d8d45 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-out.c - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h index dfa84db184ed..e87aacf843c5 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-out.h - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_OUT_H_ -- cgit From 6884db3c5f99793fef57f53a2897c0b744651d71 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 09:27:12 -0500 Subject: media: cobalt: add SPDX license info Replace the old license information with the corresponding SPDX license. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/Makefile | 1 + drivers/media/pci/cobalt/cobalt-alsa-main.c | 14 +------------- drivers/media/pci/cobalt/cobalt-alsa-pcm.c | 14 +------------- drivers/media/pci/cobalt/cobalt-alsa-pcm.h | 14 +------------- drivers/media/pci/cobalt/cobalt-alsa.h | 14 +------------- drivers/media/pci/cobalt/cobalt-cpld.c | 14 +------------- drivers/media/pci/cobalt/cobalt-cpld.h | 14 +------------- drivers/media/pci/cobalt/cobalt-driver.c | 14 +------------- drivers/media/pci/cobalt/cobalt-driver.h | 14 +------------- drivers/media/pci/cobalt/cobalt-flash.c | 14 +------------- drivers/media/pci/cobalt/cobalt-flash.h | 14 +------------- drivers/media/pci/cobalt/cobalt-i2c.c | 14 +------------- drivers/media/pci/cobalt/cobalt-i2c.h | 14 +------------- drivers/media/pci/cobalt/cobalt-irq.c | 14 +------------- drivers/media/pci/cobalt/cobalt-irq.h | 14 +------------- drivers/media/pci/cobalt/cobalt-omnitek.c | 14 +------------- drivers/media/pci/cobalt/cobalt-omnitek.h | 14 +------------- drivers/media/pci/cobalt/cobalt-v4l2.c | 14 +------------- drivers/media/pci/cobalt/cobalt-v4l2.h | 14 +------------- .../media/pci/cobalt/m00233_video_measure_memmap_package.h | 14 +------------- .../media/pci/cobalt/m00235_fdma_packer_memmap_package.h | 14 +------------- drivers/media/pci/cobalt/m00389_cvi_memmap_package.h | 14 +------------- drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h | 14 +------------- drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h | 14 +------------- .../pci/cobalt/m00479_clk_loss_detector_memmap_package.h | 14 +------------- .../pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h | 14 +------------- 26 files changed, 26 insertions(+), 325 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile index b328955abbd2..29eddff2f35f 100644 --- a/drivers/media/pci/cobalt/Makefile +++ b/drivers/media/pci/cobalt/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 cobalt-objs := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \ cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \ cobalt-alsa-main.o cobalt-alsa-pcm.o diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c index 720e3ad93a9e..e5022b620856 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-main.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c index b69b258d39b9..f6a7df13cd04 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ALSA PCM device for the * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h index 513fb1f71794..0e2e9c63a23e 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ALSA PCM device for the * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc); diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h index 08db699ced37..bb7f156ad3e7 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa.h +++ b/drivers/media/pci/cobalt/cobalt-alsa.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ALSA interface to cobalt PCM capture streams * * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ struct snd_card; diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c index bfcecef659e3..3d8026483ac3 100644 --- a/drivers/media/pci/cobalt/cobalt-cpld.c +++ b/drivers/media/pci/cobalt/cobalt-cpld.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cobalt CPLD functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h index 0fc88fd5fa7b..8c880ed14cda 100644 --- a/drivers/media/pci/cobalt/cobalt-cpld.h +++ b/drivers/media/pci/cobalt/cobalt-cpld.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Cobalt CPLD functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_CPLD_H diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 3f16cf3f6d74..c8b1a6206c65 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt driver initialization and card probing * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h index 00f773ec359a..429bee4ef79c 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.h +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt driver internal defines and structures * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_DRIVER_H diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c index 04dcaf9198d2..ef96e0f956d2 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.c +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Cobalt NOR flash functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h index 8077daea51cd..605ce3d37ca3 100644 --- a/drivers/media/pci/cobalt/cobalt-flash.h +++ b/drivers/media/pci/cobalt/cobalt-flash.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Cobalt NOR flash functions * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_FLASH_H diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c index 1a5c55673ea8..c374dae78bf7 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.c +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt I2C functions * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include "cobalt-driver.h" diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h index a4c1cfaacf95..7a9057c8bff6 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.h +++ b/drivers/media/pci/cobalt/cobalt-i2c.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt I2C functions * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* init + register i2c algo-bit adapter */ diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index b190d4f81c6e..04783e78cc12 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt interrupt handling * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h index 5119484a24d9..0b4078ce6555 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.h +++ b/drivers/media/pci/cobalt/cobalt-irq.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt interrupt handling * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c index a28a8482c1d4..4c137453e679 100644 --- a/drivers/media/pci/cobalt/cobalt-omnitek.c +++ b/drivers/media/pci/cobalt/cobalt-omnitek.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Omnitek Scatter-Gather DMA Controller * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h index e5c6d032c6f2..129c5fccbe39 100644 --- a/drivers/media/pci/cobalt/cobalt-omnitek.h +++ b/drivers/media/pci/cobalt/cobalt-omnitek.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Omnitek Scatter-Gather DMA Controller * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef COBALT_OMNITEK_H diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index def4a3b37084..e2a4c705d353 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cobalt V4L2 API * @@ -5,19 +6,6 @@ * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h index 62be553cd8e2..dc43974b2d86 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.h +++ b/drivers/media/pci/cobalt/cobalt-v4l2.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cobalt V4L2 API * * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ int cobalt_nodes_register(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h index 9bc9ef1fd3a8..4c6ad1cee87e 100644 --- a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h +++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h index a480529f561e..6cc1ad7d98c9 100644 --- a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h +++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h index 602419e589d3..f0c6fe304247 100644 --- a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h +++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00389_CVI_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h index 95471c995067..27f05aca632f 100644 --- a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h +++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00460_EVCNT_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h index 384a3e156301..8a5bf008750a 100644 --- a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h +++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h index 2a029026bf82..18bd4fcd2db8 100644 --- a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h +++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h index bdef2df5d689..86da49033cd8 100644 --- a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h +++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H -- cgit From b4e30a9e059c5e246550b0b201fc0a64445bb016 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 09:34:03 -0500 Subject: media: cec: add SPDX license info Replace the old license information with the corresponding SPDX license. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 14 +------------- drivers/media/cec/cec-api.c | 14 +------------- drivers/media/cec/cec-core.c | 14 +------------- drivers/media/cec/cec-edid.c | 14 +------------- drivers/media/cec/cec-notifier.c | 14 +------------- drivers/media/cec/cec-pin-priv.h | 14 +------------- drivers/media/cec/cec-pin.c | 14 +------------- drivers/media/cec/cec-priv.h | 14 +------------- 8 files changed, 8 insertions(+), 104 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 2b1e540587d6..768f7d70b55c 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 492db12b8c4d..10b67fc40318 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-api.c - HDMI Consumer Electronics Control framework - API * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index a9f9525db9ae..e47ea22b3c23 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-core.c - HDMI Consumer Electronics Control framework - Core * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c index 38e3fec6152b..ec72ac1c0b91 100644 --- a/drivers/media/cec/cec-edid.c +++ b/drivers/media/cec/cec-edid.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 08b619d0ea1e..16dffa06c913 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * cec-notifier.c - notify CEC drivers of physical address changes * * Copyright 2016 Russell King * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index 7d0def199762..cf41c4236efd 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-pin-priv.h - internal cec-pin header * * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef LINUX_CEC_PIN_PRIV_H diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index b48dfe844118..8e834b9f72c6 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index daf597643af8..804e38f849c7 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * cec-priv.h - HDMI Consumer Electronics Control internal header * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _CEC_PRIV_H -- cgit From 55e5927eb13e4f73989cb18cd67687af41aceb78 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 09:34:26 -0500 Subject: media: i2c: add SPDX license info Replace the old license information with the corresponding SPDX license for those drivers Cisco authored. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ad9389b.c | 14 +------------- drivers/media/i2c/adv7511.c | 14 +------------- drivers/media/i2c/adv7604.c | 14 +------------- drivers/media/i2c/adv7842.c | 15 +-------------- drivers/media/i2c/tc358743.c | 15 +-------------- drivers/media/i2c/tc358743_regs.h | 15 +-------------- 6 files changed, 6 insertions(+), 81 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index a056d6cdaaaa..91ff06088572 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices AD9389B/AD9889B video encoder driver * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 2817bafc67bf..d23505a411ee 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices ADV7511 HDMI Transmitter Device Driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 1544920ec52d..b2caaff945ab 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adv7604 - Analog Devices ADV7604 video decoder driver * * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 136aa80a834b..fddac32e5051 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * adv7842 - Analog Devices ADV7842 video decoder driver * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 2b8181469b93..393bbbbbaad7 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tc358743 - Toshiba HDMI to CSI-2 bridge * * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights * reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h index 227b46471793..2495878dc358 100644 --- a/drivers/media/i2c/tc358743_regs.h +++ b/drivers/media/i2c/tc358743_regs.h @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks * * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights * reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ /* -- cgit From ddddfa78acab32adb1071454a6d29d35d7710b36 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 09:34:55 -0500 Subject: media: add SPDX license info Replace the old license information with the corresponding SPDX license for the remaining media drivers that Cisco authored. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c | 14 +------------- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 14 +------------- drivers/media/platform/cec-gpio/cec-gpio.c | 14 +------------- drivers/media/radio/radio-raremono.c | 14 +------------- drivers/media/radio/si4713/radio-usb-si4713.c | 14 +------------- drivers/media/v4l2-core/v4l2-dv-timings.c | 15 +-------------- 6 files changed, 6 insertions(+), 79 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c index 43180204fab2..3a3dc23c560c 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-tpg-colors.c - A table that converts colors to various colorspaces * @@ -20,19 +21,6 @@ * in order to preserve precision. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 2b3d4ac4dfd4..d248d1fb9d1d 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-tpg-core.c - Test Pattern Generator * @@ -5,19 +6,6 @@ * vivi.c source for the copyright information of those functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index 5debdf08fbe7..f1f28cf5c751 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 70a2c86774ce..9a5079d64c4a 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index a115db24667b..05c66701a899 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. * All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ /* kernel includes */ diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index e2ee5f00c445..d98c4ad7a9c3 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * v4l2-dv-timings - dv-timings helper functions * * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * */ #include -- cgit From 22756ae7319b0afc2a80fbdec365a6976a1ad350 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 25 Jan 2018 17:19:08 -0500 Subject: media: rc: don't mark IR decoders default y I usually update my config with make oldconfig and pressing return, trusting that whoever updates Kconfig sets sensible defaults. But my recent kernels ended up with all kinds of IR decoders built in that are not used by anything because they are all marked with default y. default y should only be set for something that prevents booting on common systems, never for some random weirdo driver feature like this. Remove all the "default y" in drivers/media/rc/Kconfig Signed-off-by: Andi Kleen Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index f14ead5954e0..447f82c1f65a 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -28,14 +28,12 @@ config LIRC menuconfig RC_DECODERS bool "Remote controller decoders" depends on RC_CORE - default y if RC_DECODERS config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with NEC protocol, and @@ -45,7 +43,6 @@ config IR_RC5_DECODER tristate "Enable IR raw decoder for the RC-5 protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with RC-5 protocol, and @@ -55,7 +52,6 @@ config IR_RC6_DECODER tristate "Enable IR raw decoder for the RC6 protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -65,7 +61,6 @@ config IR_JVC_DECODER tristate "Enable IR raw decoder for the JVC protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -75,7 +70,6 @@ config IR_SONY_DECODER tristate "Enable IR raw decoder for the Sony protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have an infrared remote control which @@ -84,7 +78,6 @@ config IR_SONY_DECODER config IR_SANYO_DECODER tristate "Enable IR raw decoder for the Sanyo protocol" depends on RC_CORE - default y ---help--- Enable this option if you have an infrared remote control which @@ -94,7 +87,6 @@ config IR_SANYO_DECODER config IR_SHARP_DECODER tristate "Enable IR raw decoder for the Sharp protocol" depends on RC_CORE - default y ---help--- Enable this option if you have an infrared remote control which @@ -105,7 +97,6 @@ config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have a Microsoft Remote Keyboard for @@ -116,7 +107,6 @@ config IR_XMP_DECODER tristate "Enable IR raw decoder for the XMP protocol" depends on RC_CORE select BITREVERSE - default y ---help--- Enable this option if you have IR with XMP protocol, and @@ -446,7 +436,6 @@ config IR_SERIAL config IR_SERIAL_TRANSMITTER bool "Serial Port Transmitter" - default y depends on IR_SERIAL ---help--- Serial Port Transmitter support -- cgit From de5b22d98705a4c103492e36a5220faca5a2d0a0 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 26 Jan 2018 17:10:17 -0500 Subject: media: rc: ir-hix5hd2: fix error handling of clk_prepare_enable() Return code of clk_prepare_enable() is ignored in many places. The patch adds error handling for all of them. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-hix5hd2.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 0ce11c41dfae..700ab4c563d0 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -71,9 +71,10 @@ struct hix5hd2_ir_priv { unsigned long rate; }; -static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) +static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) { u32 val; + int ret = 0; if (dev->regmap) { regmap_read(dev->regmap, IR_CLK, &val); @@ -87,10 +88,11 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) regmap_write(dev->regmap, IR_CLK, val); } else { if (on) - clk_prepare_enable(dev->clock); + ret = clk_prepare_enable(dev->clock); else clk_disable_unprepare(dev->clock); } + return ret; } static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) @@ -127,9 +129,18 @@ static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) static int hix5hd2_ir_open(struct rc_dev *rdev) { struct hix5hd2_ir_priv *priv = rdev->priv; + int ret; + + ret = hix5hd2_ir_enable(priv, true); + if (ret) + return ret; - hix5hd2_ir_enable(priv, true); - return hix5hd2_ir_config(priv); + ret = hix5hd2_ir_config(priv); + if (ret) { + hix5hd2_ir_enable(priv, false); + return ret; + } + return 0; } static void hix5hd2_ir_close(struct rc_dev *rdev) @@ -239,7 +250,9 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) ret = PTR_ERR(priv->clock); goto err; } - clk_prepare_enable(priv->clock); + ret = clk_prepare_enable(priv->clock); + if (ret) + goto err; priv->rate = clk_get_rate(priv->clock); rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; @@ -309,9 +322,17 @@ static int hix5hd2_ir_suspend(struct device *dev) static int hix5hd2_ir_resume(struct device *dev) { struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); + int ret; - hix5hd2_ir_enable(priv, true); - clk_prepare_enable(priv->clock); + ret = hix5hd2_ir_enable(priv, true); + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clock); + if (ret) { + hix5hd2_ir_enable(priv, false); + return ret; + } writel_relaxed(0x01, priv->base + IR_ENABLE); writel_relaxed(0x00, priv->base + IR_INTM); -- cgit From 069edf8a6a42be39b4ec04e56ab7bd18634dc12e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 27 Jan 2018 09:05:37 -0500 Subject: media: rc: ir-spi: fix duty cycle Calculate the pulse rather than having a few preset values. Signed-off-by: Sean Young Acked-by: Andi Shyti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-spi.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index a32a84ae2d0b..7163d5ce2e64 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -15,21 +15,11 @@ #define IR_SPI_DRIVER_NAME "ir-spi" -/* pulse value for different duty cycles */ -#define IR_SPI_PULSE_DC_50 0xff00 -#define IR_SPI_PULSE_DC_60 0xfc00 -#define IR_SPI_PULSE_DC_70 0xf800 -#define IR_SPI_PULSE_DC_75 0xf000 -#define IR_SPI_PULSE_DC_80 0xc000 -#define IR_SPI_PULSE_DC_90 0x8000 - #define IR_SPI_DEFAULT_FREQUENCY 38000 -#define IR_SPI_BIT_PER_WORD 8 #define IR_SPI_MAX_BUFSIZE 4096 struct ir_spi_data { u32 freq; - u8 duty_cycle; bool negated; u16 tx_buf[IR_SPI_MAX_BUFSIZE]; @@ -105,19 +95,9 @@ static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) { struct ir_spi_data *idata = dev->priv; + int bits = (duty_cycle * 15) / 100; - if (duty_cycle >= 90) - idata->pulse = IR_SPI_PULSE_DC_90; - else if (duty_cycle >= 80) - idata->pulse = IR_SPI_PULSE_DC_80; - else if (duty_cycle >= 75) - idata->pulse = IR_SPI_PULSE_DC_75; - else if (duty_cycle >= 70) - idata->pulse = IR_SPI_PULSE_DC_70; - else if (duty_cycle >= 60) - idata->pulse = IR_SPI_PULSE_DC_60; - else - idata->pulse = IR_SPI_PULSE_DC_50; + idata->pulse = GENMASK(bits, 0); if (idata->negated) { idata->pulse = ~idata->pulse; -- cgit From 50078a903830796a8a47f26edc4cc10b9061711f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Feb 2018 07:20:52 -0500 Subject: media: rc: replace IR_dprintk() with dev_dbg in IR decoders Use dev_dbg() rather than custom debug function. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-jvc-decoder.c | 14 ++++---- drivers/media/rc/ir-mce_kbd-decoder.c | 60 ++++++++++++++++++----------------- drivers/media/rc/ir-nec-decoder.c | 20 ++++++------ drivers/media/rc/ir-rc5-decoder.c | 12 +++---- drivers/media/rc/ir-rc6-decoder.c | 26 +++++++-------- drivers/media/rc/ir-sanyo-decoder.c | 18 +++++------ drivers/media/rc/ir-sharp-decoder.c | 17 +++++----- drivers/media/rc/ir-sony-decoder.c | 14 ++++---- drivers/media/rc/ir-xmp-decoder.c | 29 +++++++++-------- 9 files changed, 106 insertions(+), 104 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index c03c776cfa54..8cb68ae43282 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -56,8 +56,8 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) goto out; - IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); again: switch (data->state) { @@ -136,15 +136,15 @@ again: u32 scancode; scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | (bitrev8((data->bits >> 0) & 0xff) << 0); - IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); + dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode); rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle); data->first = false; data->old_bits = data->bits; } else if (data->bits == data->old_bits) { - IR_dprintk(1, "JVC repeat\n"); + dev_dbg(&dev->dev, "JVC repeat\n"); rc_repeat(dev); } else { - IR_dprintk(1, "JVC invalid repeat msg\n"); + dev_dbg(&dev->dev, "JVC invalid repeat msg\n"); break; } @@ -164,8 +164,8 @@ again: } out: - IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 2c3df02e05ff..c110984ca671 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -117,19 +117,19 @@ static unsigned char kbd_keycodes[256] = { static void mce_kbd_rx_timeout(struct timer_list *t) { - struct mce_kbd_dec *mce_kbd = from_timer(mce_kbd, t, rx_timeout); - int i; + struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout); unsigned char maskcode; + int i; - IR_dprintk(2, "timer callback clearing all keys\n"); + dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n"); for (i = 0; i < 7; i++) { maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; - input_report_key(mce_kbd->idev, maskcode, 0); + input_report_key(raw->mce_kbd.idev, maskcode, 0); } for (i = 0; i < MCIR2_MASK_KEYS_START; i++) - input_report_key(mce_kbd->idev, kbd_keycodes[i], 0); + input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0); } static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) @@ -144,16 +144,16 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) } } -static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, - u32 scancode) +static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode) { + struct mce_kbd_dec *data = &dev->raw->mce_kbd; u8 keydata = (scancode >> 8) & 0xff; u8 shiftmask = scancode & 0xff; unsigned char keycode, maskcode; int i, keystate; - IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", - keydata, shiftmask); + dev_dbg(&dev->dev, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", + keydata, shiftmask); for (i = 0; i < 7; i++) { maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; @@ -161,20 +161,21 @@ static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, keystate = 1; else keystate = 0; - input_report_key(idev, maskcode, keystate); + input_report_key(data->idev, maskcode, keystate); } if (keydata) { keycode = kbd_keycodes[keydata]; - input_report_key(idev, keycode, 1); + input_report_key(data->idev, keycode, 1); } else { for (i = 0; i < MCIR2_MASK_KEYS_START; i++) - input_report_key(idev, kbd_keycodes[i], 0); + input_report_key(data->idev, kbd_keycodes[i], 0); } } -static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) +static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode) { + struct mce_kbd_dec *data = &dev->raw->mce_kbd; /* raw mouse coordinates */ u8 xdata = (scancode >> 7) & 0x7f; u8 ydata = (scancode >> 14) & 0x7f; @@ -193,14 +194,14 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) else y = ydata; - IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n", - x, y, left ? "L" : "", right ? "R" : ""); + dev_dbg(&dev->dev, "mouse: x = %d, y = %d, btns = %s%s\n", + x, y, left ? "L" : "", right ? "R" : ""); - input_report_rel(idev, REL_X, x); - input_report_rel(idev, REL_Y, y); + input_report_rel(data->idev, REL_X, x); + input_report_rel(data->idev, REL_Y, y); - input_report_key(idev, BTN_LEFT, left); - input_report_key(idev, BTN_RIGHT, right); + input_report_key(data->idev, BTN_LEFT, left); + input_report_key(data->idev, BTN_RIGHT, right); } /** @@ -227,8 +228,8 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) return 0; @@ -280,7 +281,7 @@ again: data->wanted_bits = MCIR2_MOUSE_NBITS; break; default: - IR_dprintk(1, "not keyboard or mouse data\n"); + dev_dbg(&dev->dev, "not keyboard or mouse data\n"); goto out; } @@ -319,25 +320,26 @@ again: switch (data->wanted_bits) { case MCIR2_KEYBOARD_NBITS: scancode = data->body & 0xffff; - IR_dprintk(1, "keyboard data 0x%08x\n", data->body); + dev_dbg(&dev->dev, "keyboard data 0x%08x\n", + data->body); if (dev->timeout) delay = usecs_to_jiffies(dev->timeout / 1000); else delay = msecs_to_jiffies(100); mod_timer(&data->rx_timeout, jiffies + delay); /* Pass data to keyboard buffer parser */ - ir_mce_kbd_process_keyboard_data(data->idev, scancode); + ir_mce_kbd_process_keyboard_data(dev, scancode); lsc.rc_proto = RC_PROTO_MCIR2_KBD; break; case MCIR2_MOUSE_NBITS: scancode = data->body & 0x1fffff; - IR_dprintk(1, "mouse data 0x%06x\n", scancode); + dev_dbg(&dev->dev, "mouse data 0x%06x\n", scancode); /* Pass data to mouse buffer parser */ - ir_mce_kbd_process_mouse_data(data->idev, scancode); + ir_mce_kbd_process_mouse_data(dev, scancode); lsc.rc_proto = RC_PROTO_MCIR2_MSE; break; default: - IR_dprintk(1, "not keyboard or mouse data\n"); + dev_dbg(&dev->dev, "not keyboard or mouse data\n"); goto out; } @@ -350,8 +352,8 @@ again: } out: - IR_dprintk(1, "failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; input_sync(data->idev); return -EINVAL; diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 31d7bafe7bda..21647b809e6f 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -49,8 +49,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "NEC decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -99,13 +99,11 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) break; if (data->necx_repeat && data->count == NECX_REPEAT_BITS && - geq_margin(ev.duration, - NEC_TRAILER_SPACE, NEC_UNIT / 2)) { - IR_dprintk(1, "Repeat last key\n"); - rc_repeat(dev); - data->state = STATE_INACTIVE; - return 0; - + geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) { + dev_dbg(&dev->dev, "Repeat last key\n"); + rc_repeat(dev); + data->state = STATE_INACTIVE; + return 0; } else if (data->count > NECX_REPEAT_BITS) data->necx_repeat = false; @@ -164,8 +162,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "NEC decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 11a28f8772da..74d3b859c3a2 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -54,8 +54,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) return 0; @@ -157,8 +157,8 @@ again: } else break; - IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n", - scancode, protocol, toggle); + dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n", + scancode, protocol, toggle); rc_keydown(dev, protocol, scancode, toggle); data->state = STATE_INACTIVE; @@ -166,8 +166,8 @@ again: } out: - IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n", - data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 55bb19bbd4e9..8314da32453f 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -100,8 +100,8 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC6 decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) return 0; @@ -170,7 +170,7 @@ again: break; if (!(data->header & RC6_STARTBIT_MASK)) { - IR_dprintk(1, "RC6 invalid start bit\n"); + dev_dbg(&dev->dev, "RC6 invalid start bit\n"); break; } @@ -187,7 +187,7 @@ again: data->wanted_bits = RC6_6A_NBITS; break; default: - IR_dprintk(1, "RC6 unknown mode\n"); + dev_dbg(&dev->dev, "RC6 unknown mode\n"); goto out; } goto again; @@ -230,13 +230,13 @@ again: scancode = data->body; toggle = data->toggle; protocol = RC_PROTO_RC6_0; - IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", - scancode, toggle); + dev_dbg(&dev->dev, "RC6(0) scancode 0x%04x (toggle: %u)\n", + scancode, toggle); break; case RC6_MODE_6A: if (data->count > CHAR_BIT * sizeof data->body) { - IR_dprintk(1, "RC6 too many (%u) data bits\n", + dev_dbg(&dev->dev, "RC6 too many (%u) data bits\n", data->count); goto out; } @@ -262,15 +262,15 @@ again: } break; default: - IR_dprintk(1, "RC6(6A) unsupported length\n"); + dev_dbg(&dev->dev, "RC6(6A) unsupported length\n"); goto out; } - IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n", - protocol, scancode, toggle); + dev_dbg(&dev->dev, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n", + protocol, scancode, toggle); break; default: - IR_dprintk(1, "RC6 unknown mode\n"); + dev_dbg(&dev->dev, "RC6 unknown mode\n"); goto out; } @@ -280,8 +280,8 @@ again: } out: - IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "RC6 decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index ded39cdfc6ef..4efe6db5376a 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -52,14 +52,14 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!is_timing_event(ev)) { if (ev.reset) { - IR_dprintk(1, "SANYO event reset received. reset to state 0\n"); + dev_dbg(&dev->dev, "SANYO event reset received. reset to state 0\n"); data->state = STATE_INACTIVE; } return 0; } - IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -102,7 +102,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) { rc_repeat(dev); - IR_dprintk(1, "SANYO repeat last key\n"); + dev_dbg(&dev->dev, "SANYO repeat last key\n"); data->state = STATE_INACTIVE; return 0; } @@ -144,21 +144,21 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) not_command = bitrev8((data->bits >> 0) & 0xff); if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n", - data->bits); + dev_dbg(&dev->dev, "SANYO checksum error: received 0x%08llx\n", + data->bits); data->state = STATE_INACTIVE; return 0; } scancode = address << 8 | command; - IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); + dev_dbg(&dev->dev, "SANYO scancode: 0x%06x\n", scancode); rc_keydown(dev, RC_PROTO_SANYO, scancode, 0); data->state = STATE_INACTIVE; return 0; } - IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index df296991906c..6a38c50566a4 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -54,8 +54,8 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -149,9 +149,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) msg = (data->bits >> 15) & 0x7fff; echo = data->bits & 0x7fff; if ((msg ^ echo) != 0x3ff) { - IR_dprintk(1, - "Sharp checksum error: received 0x%04x, 0x%04x\n", - msg, echo); + dev_dbg(&dev->dev, + "Sharp checksum error: received 0x%04x, 0x%04x\n", + msg, echo); break; } @@ -159,16 +159,15 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) command = bitrev8((msg >> 2) & 0xff); scancode = address << 8 | command; - IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); + dev_dbg(&dev->dev, "Sharp scancode 0x%04x\n", scancode); rc_keydown(dev, RC_PROTO_SHARP, scancode, 0); data->state = STATE_INACTIVE; return 0; } - IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), - TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index e4bcff21c025..6764ec9de646 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -55,8 +55,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) goto out; - IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -148,19 +148,21 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) protocol = RC_PROTO_SONY20; break; default: - IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); + dev_dbg(&dev->dev, "Sony invalid bitcount %u\n", + data->count); goto out; } scancode = device << 16 | subdevice << 8 | function; - IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); + dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n", data->count, + scancode); rc_keydown(dev, protocol, scancode, 0); goto finish_state_machine; } out: - IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index 712bc6d76e92..58b47af1a763 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -49,8 +49,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n", - data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "XMP decode started at state %d %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); switch (data->state) { @@ -85,7 +85,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; if (data->count != 16) { - IR_dprintk(2, "received TRAILER period at index %d: %u\n", + dev_dbg(&dev->dev, "received TRAILER period at index %d: %u\n", data->count, ev.duration); data->state = STATE_INACTIVE; return -EINVAL; @@ -99,7 +99,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) */ divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000; if (divider < 50) { - IR_dprintk(2, "divider to small %d.\n", divider); + dev_dbg(&dev->dev, "divider to small %d.\n", + divider); data->state = STATE_INACTIVE; return -EINVAL; } @@ -113,7 +114,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) n[12] + n[13] + n[14] + n[15]) % 16; if (sum1 != 15 || sum2 != 15) { - IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n", + dev_dbg(&dev->dev, "checksum errors sum1=0x%X sum2=0x%X\n", sum1, sum2); data->state = STATE_INACTIVE; return -EINVAL; @@ -127,24 +128,24 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) obc1 = n[12] << 4 | n[13]; obc2 = n[14] << 4 | n[15]; if (subaddr != subaddr2) { - IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", + dev_dbg(&dev->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", subaddr, subaddr2); data->state = STATE_INACTIVE; return -EINVAL; } if (oem != 0x44) - IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", + dev_dbg(&dev->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", oem); scancode = addr << 24 | subaddr << 16 | obc1 << 8 | obc2; - IR_dprintk(1, "XMP scancode 0x%06x\n", scancode); + dev_dbg(&dev->dev, "XMP scancode 0x%06x\n", scancode); if (toggle == 0) { rc_keydown(dev, RC_PROTO_XMP, scancode, 0); } else { rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); + dev_dbg(&dev->dev, "Repeat last key\n"); } data->state = STATE_INACTIVE; @@ -153,7 +154,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) { /* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */ if (data->count == 16) { - IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n", + dev_dbg(&dev->dev, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n", data->count, ev.duration); /* * TODO: for now go back to half frame position @@ -164,7 +165,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (data->count != 8) - IR_dprintk(2, "received half frame pulse at index %d: %u\n", + dev_dbg(&dev->dev, "received half frame pulse at index %d: %u\n", data->count, ev.duration); data->state = STATE_LEADER_PULSE; @@ -173,7 +174,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) { /* store nibble raw data, decode after trailer */ if (data->count == 16) { - IR_dprintk(2, "to many pulses (%d) ignoring: %u\n", + dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n", data->count, ev.duration); data->state = STATE_INACTIVE; return -EINVAL; @@ -189,8 +190,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) break; } - IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n", - data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "XMP decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } -- cgit From 1f17f684d9ea3aafccbb5d727b19c5ffafb07e75 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Feb 2018 07:27:50 -0500 Subject: media: rc: remove IR_dprintk() from rc-core Use dev_dbg() rather than custom debug function. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 10 ++--- drivers/media/rc/rc-ir-raw.c | 6 +-- drivers/media/rc/rc-main.c | 91 ++++++++++++++++++++++---------------------- 3 files changed, 53 insertions(+), 54 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index cc863044c880..b01725296b46 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -60,12 +60,12 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) * space with the maximum time value. */ sample = LIRC_SPACE(LIRC_VALUE_MASK); - IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); + dev_dbg(&dev->dev, "delivering reset sync space to lirc_dev\n"); /* Carrier reports */ } else if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); - IR_dprintk(2, "carrier report (freq: %d)\n", sample); + dev_dbg(&dev->dev, "carrier report (freq: %d)\n", sample); /* Packet end */ } else if (ev.timeout) { @@ -77,7 +77,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) dev->gap_duration = ev.duration; sample = LIRC_TIMEOUT(ev.duration / 1000); - IR_dprintk(2, "timeout report (duration: %d)\n", sample); + dev_dbg(&dev->dev, "timeout report (duration: %d)\n", sample); /* Normal sample */ } else { @@ -100,8 +100,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : LIRC_SPACE(ev.duration / 1000); - IR_dprintk(2, "delivering %uus %s to lirc_dev\n", - TO_US(ev.duration), TO_STR(ev.pulse)); + dev_dbg(&dev->dev, "delivering %uus %s to lirc_dev\n", + TO_US(ev.duration), TO_STR(ev.pulse)); } spin_lock_irqsave(&dev->lirc_fh_lock, flags); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 18504870b9f0..2790a0d268fd 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -65,8 +65,8 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev) if (!dev->raw) return -EINVAL; - IR_dprintk(2, "sample: (%05dus %s)\n", - TO_US(ev->duration), TO_STR(ev->pulse)); + dev_dbg(&dev->dev, "sample: (%05dus %s)\n", + TO_US(ev->duration), TO_STR(ev->pulse)); if (!kfifo_put(&dev->raw->kfifo, *ev)) { dev_err(&dev->dev, "IR event FIFO is full!\n"); @@ -168,7 +168,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle) if (!dev->raw) return; - IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); + dev_dbg(&dev->dev, "%s idle mode\n", idle ? "enter" : "leave"); if (idle) { dev->raw->this_ev.timeout = true; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 1db8d38fed7c..4a952108ba1e 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -156,6 +156,7 @@ static struct rc_map_list empty_map = { /** * ir_create_table() - initializes a scancode table + * @dev: the rc_dev device * @rc_map: the rc_map to initialize * @name: name to assign to the table * @rc_proto: ir type to assign to the new table @@ -166,7 +167,7 @@ static struct rc_map_list empty_map = { * * return: zero on success or a negative error code */ -static int ir_create_table(struct rc_map *rc_map, +static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map, const char *name, u64 rc_proto, size_t size) { rc_map->name = kstrdup(name, GFP_KERNEL); @@ -182,8 +183,8 @@ static int ir_create_table(struct rc_map *rc_map, return -ENOMEM; } - IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", - rc_map->size, rc_map->alloc); + dev_dbg(&dev->dev, "Allocated space for %u keycode entries (%u bytes)\n", + rc_map->size, rc_map->alloc); return 0; } @@ -205,6 +206,7 @@ static void ir_free_table(struct rc_map *rc_map) /** * ir_resize_table() - resizes a scancode table if necessary + * @dev: the rc_dev device * @rc_map: the rc_map to resize * @gfp_flags: gfp flags to use when allocating memory * @@ -213,7 +215,8 @@ static void ir_free_table(struct rc_map *rc_map) * * return: zero on success or a negative error code */ -static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) +static int ir_resize_table(struct rc_dev *dev, struct rc_map *rc_map, + gfp_t gfp_flags) { unsigned int oldalloc = rc_map->alloc; unsigned int newalloc = oldalloc; @@ -226,23 +229,21 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags) return -ENOMEM; newalloc *= 2; - IR_dprintk(1, "Growing table to %u bytes\n", newalloc); + dev_dbg(&dev->dev, "Growing table to %u bytes\n", newalloc); } if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) { /* Less than 1/3 of entries in use -> shrink keytable */ newalloc /= 2; - IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc); + dev_dbg(&dev->dev, "Shrinking table to %u bytes\n", newalloc); } if (newalloc == oldalloc) return 0; newscan = kmalloc(newalloc, gfp_flags); - if (!newscan) { - IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc); + if (!newscan) return -ENOMEM; - } memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table)); rc_map->scan = newscan; @@ -275,16 +276,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { - IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", - index, rc_map->scan[index].scancode); + dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n", + index, rc_map->scan[index].scancode); rc_map->len--; memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], (rc_map->len - index) * sizeof(struct rc_map_table)); } else { - IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n", - index, - old_keycode == KEY_RESERVED ? "New" : "Replacing", - rc_map->scan[index].scancode, new_keycode); + dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n", + index, + old_keycode == KEY_RESERVED ? "New" : "Replacing", + rc_map->scan[index].scancode, new_keycode); rc_map->scan[index].keycode = new_keycode; __set_bit(new_keycode, dev->input_dev->keybit); } @@ -301,7 +302,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, } /* Possibly shrink the keytable, failure is not a problem */ - ir_resize_table(rc_map, GFP_ATOMIC); + ir_resize_table(dev, rc_map, GFP_ATOMIC); } return old_keycode; @@ -352,7 +353,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev, /* No previous mapping found, we might need to grow the table */ if (rc_map->size == rc_map->len) { - if (!resize || ir_resize_table(rc_map, GFP_ATOMIC)) + if (!resize || ir_resize_table(dev, rc_map, GFP_ATOMIC)) return -1U; } @@ -431,8 +432,8 @@ static int ir_setkeytable(struct rc_dev *dev, unsigned int i, index; int rc; - rc = ir_create_table(rc_map, from->name, - from->rc_proto, from->size); + rc = ir_create_table(dev, rc_map, from->name, from->rc_proto, + from->size); if (rc) return rc; @@ -576,8 +577,8 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) spin_unlock_irqrestore(&rc_map->lock, flags); if (keycode != KEY_RESERVED) - IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", - dev->device_name, scancode, keycode); + dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n", + dev->device_name, scancode, keycode); return keycode; } @@ -596,7 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync) if (!dev->keypressed) return; - IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); + dev_dbg(&dev->dev, "keyup key 0x%04x\n", dev->last_keycode); del_timer(&dev->timer_repeat); input_report_key(dev->input_dev, dev->last_keycode, 0); led_trigger_event(led_feedback, LED_OFF); @@ -751,8 +752,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, /* Register a keypress */ dev->keypressed = true; - IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", - dev->device_name, keycode, protocol, scancode); + dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + dev->device_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); led_trigger_event(led_feedback, LED_FULL); @@ -1056,8 +1057,8 @@ static ssize_t show_protocols(struct device *device, mutex_unlock(&dev->lock); - IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n", - __func__, (long long)allowed, (long long)enabled); + dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - 0x%llx\n", + __func__, (long long)allowed, (long long)enabled); for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (allowed & enabled & proto_names[i].type) @@ -1083,6 +1084,7 @@ static ssize_t show_protocols(struct device *device, /** * parse_protocol_change() - parses a protocol change request + * @dev: rc_dev device * @protocols: pointer to the bitmask of current protocols * @buf: pointer to the buffer with a list of changes * @@ -1092,7 +1094,8 @@ static ssize_t show_protocols(struct device *device, * Writing "none" will disable all protocols. * Returns the number of changes performed or a negative error code. */ -static int parse_protocol_change(u64 *protocols, const char *buf) +static int parse_protocol_change(struct rc_dev *dev, u64 *protocols, + const char *buf) { const char *tmp; unsigned count = 0; @@ -1128,7 +1131,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf) if (!strcasecmp(tmp, "lirc")) mask = 0; else { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + dev_dbg(&dev->dev, "Unknown protocol: '%s'\n", + tmp); return -EINVAL; } } @@ -1144,7 +1148,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } if (!count) { - IR_dprintk(1, "Protocol not specified\n"); + dev_dbg(&dev->dev, "Protocol not specified\n"); return -EINVAL; } @@ -1217,12 +1221,12 @@ static ssize_t store_protocols(struct device *device, u64 old_protocols, new_protocols; ssize_t rc; - IR_dprintk(1, "Normal protocol change requested\n"); + dev_dbg(&dev->dev, "Normal protocol change requested\n"); current_protocols = &dev->enabled_protocols; filter = &dev->scancode_filter; if (!dev->change_protocol) { - IR_dprintk(1, "Protocol switching not supported\n"); + dev_dbg(&dev->dev, "Protocol switching not supported\n"); return -EINVAL; } @@ -1230,14 +1234,14 @@ static ssize_t store_protocols(struct device *device, old_protocols = *current_protocols; new_protocols = old_protocols; - rc = parse_protocol_change(&new_protocols, buf); + rc = parse_protocol_change(dev, &new_protocols, buf); if (rc < 0) goto out; rc = dev->change_protocol(dev, &new_protocols); if (rc < 0) { - IR_dprintk(1, "Error setting protocols to 0x%llx\n", - (long long)new_protocols); + dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n", + (long long)new_protocols); goto out; } @@ -1246,8 +1250,8 @@ static ssize_t store_protocols(struct device *device, if (new_protocols != old_protocols) { *current_protocols = new_protocols; - IR_dprintk(1, "Protocols changed to 0x%llx\n", - (long long)new_protocols); + dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n", + (long long)new_protocols); } /* @@ -1435,8 +1439,8 @@ static ssize_t show_wakeup_protocols(struct device *device, mutex_unlock(&dev->lock); - IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n", - __func__, (long long)allowed, enabled); + dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - %d\n", + __func__, (long long)allowed, enabled); for (i = 0; i < ARRAY_SIZE(protocols); i++) { if (allowed & (1ULL << i)) { @@ -1511,7 +1515,7 @@ static ssize_t store_wakeup_protocols(struct device *device, if (dev->wakeup_protocol != protocol) { dev->wakeup_protocol = protocol; - IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol); + dev_dbg(&dev->dev, "Wakeup protocol changed to %d\n", protocol); if (protocol == RC_PROTO_RC6_MCE) dev->scancode_wakeup_filter.data = 0x800f0000; @@ -1874,9 +1878,8 @@ int rc_register_device(struct rc_dev *dev) dev->registered = true; - IR_dprintk(1, "Registered rc%u (driver: %s)\n", - dev->minor, - dev->driver_name ? dev->driver_name : "unknown"); + dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor, + dev->driver_name ? dev->driver_name : "unknown"); return 0; @@ -1994,9 +1997,5 @@ static void __exit rc_core_exit(void) subsys_initcall(rc_core_init); module_exit(rc_core_exit); -int rc_core_debug; /* ir_debug level (0,1,2) */ -EXPORT_SYMBOL_GPL(rc_core_debug); -module_param_named(debug, rc_core_debug, int, 0644); - MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL v2"); -- cgit From ba02086dee2d181f0b438606c38cb0c8f82d71a3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Feb 2018 08:58:01 -0500 Subject: media: rc: remove obsolete comment This comment is no longer relevant. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-core-priv.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 458e9eb2d6a9..d09a06e1c17f 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -292,11 +292,4 @@ static inline int ir_lirc_register(struct rc_dev *dev) { return 0; } static inline void ir_lirc_unregister(struct rc_dev *dev) { } #endif -/* - * Decoder initialization code - * - * Those load logic are called during ir-core init, and automatically - * loads the compiled decoders for their usage with IR raw events - */ - #endif /* _RC_CORE_PRIV */ -- cgit From c2837ad09018807437f1249d30915e70dd6b6bbe Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Feb 2018 08:59:00 -0500 Subject: media: rc: remove useless if statement ret is always 0, so remove if statement. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index b01725296b46..fd3860d50034 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -570,7 +570,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd, ret = -EINVAL; else if (dev->s_timeout) ret = dev->s_timeout(dev, tmp); - else if (!ret) + else dev->timeout = tmp; } break; -- cgit From 29422737017b866d4a51014cc7522fa3a99e8852 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Feb 2018 09:00:28 -0500 Subject: media: rc: get start time just before calling driver tx The current code gets the start time before copying the IR from userspace (could cause page faults) and encoding IR. This means that the gap calculation could be off. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index fd3860d50034..da3b5c095a59 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -249,8 +249,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, goto out_unlock; } - start = ktime_get(); - if (!dev->tx_ir) { ret = -EINVAL; goto out_unlock; @@ -343,6 +341,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, duration += txbuf[i]; } + start = ktime_get(); + ret = dev->tx_ir(dev, txbuf, count); if (ret < 0) goto out_kfree; -- cgit From 7c8a940a5ea0b0861a566f02b67be75d8d86df36 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 3 Feb 2018 08:20:21 -0500 Subject: media: v4l2-subdev: clear reserved fields Clear the reserved fields for these ioctls according to the specification: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL VIDIOC_SUBDEV_ENUM_FRAME_SIZE VIDIOC_SUBDEV_ENUM_MBUS_CODE VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION Found with v4l2-compliance. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index c5639817db34..74fe8083cf26 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -260,6 +260,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(format->reserved, 0, sizeof(format->reserved)); + memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); } @@ -270,6 +272,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(format->reserved, 0, sizeof(format->reserved)); + memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); } @@ -281,6 +285,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -298,6 +303,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; + memset(crop->reserved, 0, sizeof(crop->reserved)); rval = check_crop(sd, crop); if (rval) return rval; @@ -326,6 +332,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (code->pad >= sd->entity.num_pads) return -EINVAL; + memset(code->reserved, 0, sizeof(code->reserved)); return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); } @@ -340,6 +347,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fse->pad >= sd->entity.num_pads) return -EINVAL; + memset(fse->reserved, 0, sizeof(fse->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); } @@ -350,6 +358,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fi->pad >= sd->entity.num_pads) return -EINVAL; + memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, g_frame_interval, arg); } @@ -359,6 +368,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fi->pad >= sd->entity.num_pads) return -EINVAL; + memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -372,6 +382,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fie->pad >= sd->entity.num_pads) return -EINVAL; + memset(fie->reserved, 0, sizeof(fie->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); } @@ -383,6 +394,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); } @@ -394,6 +406,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; + memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); } -- cgit From 672de9a79cd34c864f5eca7de5264b2645212605 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 22 Jan 2018 03:58:36 -0500 Subject: media: v4l2-common: create v4l2_g/s_parm_cap helpers Create helpers to handle VIDIOC_G/S_PARM by querying the g/s_frame_interval v4l2_subdev ops. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 8650ad92b64d..96c1b31de9e3 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -392,3 +392,51 @@ void v4l2_get_timestamp(struct timeval *tv) tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; } EXPORT_SYMBOL_GPL(v4l2_get_timestamp); + +int v4l2_g_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct v4l2_subdev_frame_interval ival = { 0 }; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + if (vdev->device_caps & V4L2_CAP_READWRITE) + a->parm.capture.readbuffers = 2; + if (v4l2_subdev_has_op(sd, video, g_frame_interval)) + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival); + if (!ret) + a->parm.capture.timeperframe = ival.interval; + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_g_parm_cap); + +int v4l2_s_parm_cap(struct video_device *vdev, + struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct v4l2_subdev_frame_interval ival = { + .interval = a->parm.capture.timeperframe + }; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + memset(&a->parm, 0, sizeof(a->parm)); + if (vdev->device_caps & V4L2_CAP_READWRITE) + a->parm.capture.readbuffers = 2; + else + a->parm.capture.readbuffers = 0; + + if (v4l2_subdev_has_op(sd, video, g_frame_interval)) + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival); + if (!ret) + a->parm.capture.timeperframe = ival.interval; + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_s_parm_cap); -- cgit From 4471109e3894f500079d21fea4bc4d58bbdc4045 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 22 Jan 2018 04:00:45 -0500 Subject: media: convert g/s_parm to g/s_frame_interval in subdevs Convert all g/s_parm calls to g/s_frame_interval. This allows us to remove the g/s_parm ops since those are a duplicate of g/s_frame_interval. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9v011.c | 29 ++++++------------- drivers/media/i2c/ov6650.c | 33 ++++++++-------------- drivers/media/i2c/ov7670.c | 22 ++++++--------- drivers/media/i2c/ov7740.c | 29 ++++++------------- drivers/media/i2c/tvp514x.c | 37 ++++++++----------------- drivers/media/i2c/vs6624.c | 27 ++++++------------ drivers/media/platform/atmel/atmel-isc.c | 10 ++----- drivers/media/platform/atmel/atmel-isi.c | 12 ++------ drivers/media/platform/blackfin/bfin_capture.c | 14 +++------- drivers/media/platform/marvell-ccic/mcam-core.c | 12 ++++---- drivers/media/platform/soc_camera/soc_camera.c | 10 ++++--- drivers/media/platform/via-camera.c | 4 +-- drivers/media/usb/em28xx/em28xx-video.c | 36 ++++++++++++++++++++---- 13 files changed, 110 insertions(+), 165 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 5e29064fae91..46ef74a2ca36 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -364,33 +364,22 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int mt9v011_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; calc_fps(sd, - &cp->timeperframe.numerator, - &cp->timeperframe.denominator); + &ival->interval.numerator, + &ival->interval.denominator); return 0; } -static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int mt9v011_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; u16 speed; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; - speed = calc_speed(sd, tpf->numerator, tpf->denominator); mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); @@ -469,8 +458,8 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .g_parm = mt9v011_g_parm, - .s_parm = mt9v011_s_parm, + .g_frame_interval = mt9v011_g_frame_interval, + .s_frame_interval = mt9v011_s_frame_interval, }; static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = { diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 8975d16b2b24..17a34b4a819d 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -201,7 +201,7 @@ struct ov6650 { struct v4l2_rect rect; /* sensor cropping window */ unsigned long pclk_limit; /* from host */ unsigned long pclk_max; /* from resolution and format */ - struct v4l2_fract tpf; /* as requested with s_parm */ + struct v4l2_fract tpf; /* as requested with s_frame_interval */ u32 code; enum v4l2_colorspace colorspace; }; @@ -723,42 +723,31 @@ static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov6650_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(*cp)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, + ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max)); - cp->timeperframe.denominator = FRAME_RATE_MAX; + ival->interval.denominator = FRAME_RATE_MAX; dev_dbg(&client->dev, "Frame interval: %u/%u s\n", - cp->timeperframe.numerator, cp->timeperframe.denominator); + ival->interval.numerator, ival->interval.denominator); return 0; } -static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov6650_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; int div, ret; u8 clkrc; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cp->extendedmode != 0) - return -EINVAL; - if (tpf->numerator == 0 || tpf->denominator == 0) div = 1; /* Reset to full rate */ else @@ -921,8 +910,8 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, - .g_parm = ov6650_g_parm, - .s_parm = ov6650_s_parm, + .g_frame_interval = ov6650_g_frame_interval, + .s_frame_interval = ov6650_s_frame_interval, .g_mbus_config = ov6650_g_mbus_config, .s_mbus_config = ov6650_s_mbus_config, }; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 28571de1c2f6..31b0c33cfc5b 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1100,30 +1100,24 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, * Implement G/S_PARM. There is a "high quality" mode we could try * to do someday; for now, we just do the frame rate tweak. */ -static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov7670_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; struct ov7670_info *info = to_state(sd); - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cp->capability = V4L2_CAP_TIMEPERFRAME; - info->devtype->get_framerate(sd, &cp->timeperframe); + info->devtype->get_framerate(sd, &ival->interval); return 0; } -static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int ov7670_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; struct ov7670_info *info = to_state(sd); - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cp->capability = V4L2_CAP_TIMEPERFRAME; return info->devtype->set_framerate(sd, tpf); } @@ -1636,8 +1630,8 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { }; static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .s_parm = ov7670_s_parm, - .g_parm = ov7670_g_parm, + .s_frame_interval = ov7670_s_frame_interval, + .g_frame_interval = ov7670_g_frame_interval, }; static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index fc9dbbcae56e..e1a44a18d9a8 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -624,17 +624,11 @@ err_unlock: return ret; } -static int ov7740_get_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *parms) +static int ov7740_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(struct v4l2_captureparm)); - cp->capability = V4L2_CAP_TIMEPERFRAME; tpf->numerator = 1; tpf->denominator = 60; @@ -642,18 +636,11 @@ static int ov7740_get_parm(struct v4l2_subdev *sd, return 0; } -static int ov7740_set_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *parms) +static int ov7740_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; - - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; + struct v4l2_fract *tpf = &ival->interval; - cp->capability = V4L2_CAP_TIMEPERFRAME; tpf->numerator = 1; tpf->denominator = 60; @@ -663,8 +650,8 @@ static int ov7740_set_parm(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { .s_stream = ov7740_set_stream, - .s_parm = ov7740_set_parm, - .g_parm = ov7740_get_parm, + .s_frame_interval = ov7740_s_frame_interval, + .g_frame_interval = ov7740_g_frame_interval, }; static const struct reg_sequence ov7740_format_yuyv[] = { diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 8b0aa9297bde..310f9fce520d 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -747,60 +747,47 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) } /** - * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm + * tvp514x_g_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * @a: pointer to a v4l2_subdev_frame_interval structure * * Returns the decoder's video CAPTURE parameters. */ static int -tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +tvp514x_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_captureparm *cparm; enum tvp514x_std current_std; - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; /* get the current standard */ current_std = decoder->current_std; - cparm = &a->parm.capture; - cparm->capability = V4L2_CAP_TIMEPERFRAME; - cparm->timeperframe = + ival->interval = decoder->std_list[current_std].standard.frameperiod; return 0; } /** - * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm + * tvp514x_s_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * @a: pointer to a v4l2_subdev_frame_interval structure * * Configures the decoder to use the input parameters, if possible. If * not possible, returns the appropriate error code. */ static int -tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +tvp514x_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct tvp514x_decoder *decoder = to_decoder(sd); struct v4l2_fract *timeperframe; enum tvp514x_std current_std; - if (a == NULL) - return -EINVAL; - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - timeperframe = &a->parm.capture.timeperframe; + timeperframe = &ival->interval; /* get the current standard */ current_std = decoder->current_std; @@ -961,8 +948,8 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, - .g_parm = tvp514x_g_parm, - .s_parm = tvp514x_s_parm, + .g_frame_interval = tvp514x_g_frame_interval, + .s_frame_interval = tvp514x_s_frame_interval, .s_stream = tvp514x_s_stream, }; diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 560738213c00..1658816a9844 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -657,31 +657,22 @@ static int vs6624_get_fmt(struct v4l2_subdev *sd, return 0; } -static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int vs6624_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct vs6624 *sensor = to_vs6624(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memset(cp, 0, sizeof(*cp)); - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = sensor->frame_rate.denominator; - cp->timeperframe.denominator = sensor->frame_rate.numerator; + ival->interval.numerator = sensor->frame_rate.denominator; + ival->interval.denominator = sensor->frame_rate.numerator; return 0; } -static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +static int vs6624_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) { struct vs6624 *sensor = to_vs6624(sd); - struct v4l2_captureparm *cp = &parms->parm.capture; - struct v4l2_fract *tpf = &cp->timeperframe; + struct v4l2_fract *tpf = &ival->interval; - if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cp->extendedmode != 0) - return -EINVAL; if (tpf->numerator == 0 || tpf->denominator == 0 || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) { @@ -738,8 +729,8 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { }; static const struct v4l2_subdev_video_ops vs6624_video_ops = { - .s_parm = vs6624_s_parm, - .g_parm = vs6624_g_parm, + .s_frame_interval = vs6624_s_frame_interval, + .g_frame_interval = vs6624_g_frame_interval, .s_stream = vs6624_s_stream, }; diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 34676409ca08..92d695b29fa9 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1417,20 +1417,14 @@ static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 9958918e2449..e5be21a31640 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -689,22 +689,14 @@ static int isi_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 41f179117fb0..b7660b1000fd 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -712,24 +712,18 @@ static int bcap_querycap(struct file *file, void *priv, return 0; } -static int bcap_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) +static int bcap_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct bcap_device *bcap_dev = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), bcap_dev->sd, a); } -static int bcap_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) +static int bcap_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct bcap_device *bcap_dev = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), bcap_dev->sd, a); } static int bcap_log_status(struct file *file, void *priv) diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 7b7250b1cff8..80670eeee142 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1443,24 +1443,24 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) * the level which controls the number of read buffers. */ static int mcam_vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, g_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } static int mcam_vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, s_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index c86dd2fdab84..1318512c8fe3 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1788,17 +1788,19 @@ static int default_s_selection(struct soc_camera_device *icd, } static int default_g_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, g_parm, parm); + + return v4l2_g_parm_cap(icd->vdev, sd, a); } static int default_s_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, s_parm, parm); + + return v4l2_s_parm_cap(icd->vdev, sd, a); } static int default_enum_framesizes(struct soc_camera_device *icd, diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index f77be9302120..e9a02639554b 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1112,7 +1112,7 @@ static int viacam_g_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, g_parm, parm); + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; @@ -1125,7 +1125,7 @@ static int viacam_s_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, s_parm, parm); + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index a2ba2d905952..2724e3b99af2 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1582,17 +1582,26 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { + struct v4l2_subdev_frame_interval ival = { 0 }; struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; int rc = 0; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + p->parm.capture.readbuffers = EM28XX_MIN_BUF; - if (dev->board.is_webcam) + p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + if (dev->board.is_webcam) { rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0, - video, g_parm, p); - else + video, g_frame_interval, &ival); + if (!rc) + p->parm.capture.timeperframe = ival.interval; + } else { v4l2_video_std_frame_period(v4l2->norm, &p->parm.capture.timeperframe); + } return rc; } @@ -1601,10 +1610,27 @@ static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { struct em28xx *dev = video_drvdata(file); + struct v4l2_subdev_frame_interval ival = { + 0, + p->parm.capture.timeperframe + }; + int rc = 0; + + if (!dev->board.is_webcam) + return -ENOTTY; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + memset(&p->parm, 0, sizeof(p->parm)); p->parm.capture.readbuffers = EM28XX_MIN_BUF; - return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, - 0, video, s_parm, p); + p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0, + video, s_frame_interval, &ival); + if (!rc) + p->parm.capture.timeperframe = ival.interval; + return rc; } static int vidioc_enum_input(struct file *file, void *priv, -- cgit From 357a856a6ceba0fac54623aef483ca99906c4747 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 15 Feb 2018 12:55:29 -0500 Subject: media: v4l2-dv-timings: add v4l2_hdmi_colorimetry() Add the v4l2_hdmi_colorimetry() function so we have a single function that determines the colorspace, YCbCr encoding, quantization range and transfer function from the InfoFrame data. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 141 ++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index d98c4ad7a9c3..c81faea96fba 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -14,6 +14,7 @@ #include #include #include +#include MODULE_AUTHOR("Hans Verkuil"); MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions"); @@ -801,3 +802,143 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) return aspect; } EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio); + +/** v4l2_hdmi_rx_colorimetry - determine HDMI colorimetry information + * based on various InfoFrames. + * @avi: the AVI InfoFrame + * @hdmi: the HDMI Vendor InfoFrame, may be NULL + * @height: the frame height + * + * Determines the HDMI colorimetry information, i.e. how the HDMI + * pixel color data should be interpreted. + * + * Note that some of the newer features (DCI-P3, HDR) are not yet + * implemented: the hdmi.h header needs to be updated to the HDMI 2.0 + * and CTA-861-G standards. + */ +struct v4l2_hdmi_colorimetry +v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi, + const struct hdmi_vendor_infoframe *hdmi, + unsigned int height) +{ + struct v4l2_hdmi_colorimetry c = { + V4L2_COLORSPACE_SRGB, + V4L2_YCBCR_ENC_DEFAULT, + V4L2_QUANTIZATION_FULL_RANGE, + V4L2_XFER_FUNC_SRGB + }; + bool is_ce = avi->video_code || (hdmi && hdmi->vic); + bool is_sdtv = height <= 576; + bool default_is_lim_range_rgb = avi->video_code > 1; + + switch (avi->colorspace) { + case HDMI_COLORSPACE_RGB: + /* RGB pixel encoding */ + switch (avi->colorimetry) { + case HDMI_COLORIMETRY_EXTENDED: + switch (avi->extended_colorimetry) { + case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB: + c.colorspace = V4L2_COLORSPACE_ADOBERGB; + c.xfer_func = V4L2_XFER_FUNC_ADOBERGB; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + default: + break; + } + break; + default: + break; + } + switch (avi->quantization_range) { + case HDMI_QUANTIZATION_RANGE_LIMITED: + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + break; + case HDMI_QUANTIZATION_RANGE_FULL: + break; + default: + if (default_is_lim_range_rgb) + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + break; + } + break; + + default: + /* YCbCr pixel encoding */ + c.quantization = V4L2_QUANTIZATION_LIM_RANGE; + switch (avi->colorimetry) { + case HDMI_COLORIMETRY_NONE: + if (!is_ce) + break; + if (is_sdtv) { + c.colorspace = V4L2_COLORSPACE_SMPTE170M; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + } else { + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + } + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_ITU_601: + c.colorspace = V4L2_COLORSPACE_SMPTE170M; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_ITU_709: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_COLORIMETRY_EXTENDED: + switch (avi->extended_colorimetry) { + case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_XV709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709: + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_XV601; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_S_YCC_601: + c.colorspace = V4L2_COLORSPACE_SRGB; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_SRGB; + break; + case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601: + c.colorspace = V4L2_COLORSPACE_ADOBERGB; + c.ycbcr_enc = V4L2_YCBCR_ENC_601; + c.xfer_func = V4L2_XFER_FUNC_ADOBERGB; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM: + c.colorspace = V4L2_COLORSPACE_BT2020; + c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020_CONST_LUM; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + default: /* fall back to ITU_709 */ + c.colorspace = V4L2_COLORSPACE_REC709; + c.ycbcr_enc = V4L2_YCBCR_ENC_709; + c.xfer_func = V4L2_XFER_FUNC_709; + break; + } + break; + default: + break; + } + /* + * YCC Quantization Range signaling is more-or-less broken, + * let's just ignore this. + */ + break; + } + return c; +} +EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry); -- cgit From c4455c265edbe8822e88ea8c8b0d78b5aee494e2 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 15 Feb 2018 12:55:30 -0500 Subject: media: v4l-ioctl: fix clearing pad for VIDIOC_DV_TIMINGS_CAP The pad field was inadvertently cleared. Fix this. It's needed for subdevs. Signed-off-by: Tim Harvey Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: make a proper commit message] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 260288ca4f55..f697c235f698 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2611,7 +2611,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE), IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, INFO_FL_CLEAR(v4l2_enum_dv_timings, pad)), IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, INFO_FL_ALWAYS_COPY), - IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), + IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, pad)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)), IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)), -- cgit From 9ac0038db9a7e10fc8f425010ec98b7afc2ff621 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 15 Feb 2018 12:55:34 -0500 Subject: media: i2c: Add TDA1997x HDMI receiver driver Add support for the TDA1997x HDMI receivers. Signed-off-by: Tim Harvey Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: fix type 'testin' -> 'testing'] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 9 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tda1997x.c | 2820 +++++++++++++++++++++++++++++++++++++ drivers/media/i2c/tda1997x_regs.h | 641 +++++++++ 4 files changed, 3471 insertions(+) create mode 100644 drivers/media/i2c/tda1997x.c create mode 100644 drivers/media/i2c/tda1997x_regs.h (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 9f18cd296841..8fdd673d449f 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -56,6 +56,15 @@ config VIDEO_TDA9840 To compile this driver as a module, choose M here: the module will be called tda9840. +config VIDEO_TDA1997X + tristate "NXP TDA1997x HDMI receiver" + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + ---help--- + V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. + + To compile this driver as a module, choose M here: the + module will be called tda1997x. + config VIDEO_TEA6415C tristate "Philips TEA6415C audio processor" depends on I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index c0f94cd8d56d..26b19a2e9d04 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o +obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c new file mode 100644 index 000000000000..a480aafecbf6 --- /dev/null +++ b/drivers/media/i2c/tda1997x.c @@ -0,0 +1,2820 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Gateworks Corporation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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, last_irq_status; + + source = io_read(sd, REG_INT_FLG_CLR_RATE); + io_write(sd, REG_INT_FLG_CLR_RATE, source); + + /* read status regs */ + last_irq_status = 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<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_codec *codec = dai->codec; + 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(codec->dev, "failed to constrain samplerate to %dHz\n", + rate); + return err; + } + dev_info(codec->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_codec *codec) +{ + return 0; +} + +static int tda1997x_codec_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static struct snd_soc_codec_driver tda1997x_codec_driver = { + .probe = tda1997x_codec_probe, + .remove = tda1997x_codec_remove, + .reg_word_size = sizeof(u16), +}; + +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_DTV_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_mutex; + } + + 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 = snd_soc_register_codec(&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) { + snd_soc_unregister_codec(&client->dev); + 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 "); +MODULE_DESCRIPTION("TDA1997X HDMI Receiver driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h new file mode 100644 index 000000000000..f55dfc423a86 --- /dev/null +++ b/drivers/media/i2c/tda1997x_regs.h @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Gateworks Corporation + */ + +/* Page 0x00 - General Control */ +#define REG_VERSION 0x0000 +#define REG_INPUT_SEL 0x0001 +#define REG_SVC_MODE 0x0002 +#define REG_HPD_MAN_CTRL 0x0003 +#define REG_RT_MAN_CTRL 0x0004 +#define REG_STANDBY_SOFT_RST 0x000A +#define REG_HDMI_SOFT_RST 0x000B +#define REG_HDMI_INFO_RST 0x000C +#define REG_INT_FLG_CLR_TOP 0x000E +#define REG_INT_FLG_CLR_SUS 0x000F +#define REG_INT_FLG_CLR_DDC 0x0010 +#define REG_INT_FLG_CLR_RATE 0x0011 +#define REG_INT_FLG_CLR_MODE 0x0012 +#define REG_INT_FLG_CLR_INFO 0x0013 +#define REG_INT_FLG_CLR_AUDIO 0x0014 +#define REG_INT_FLG_CLR_HDCP 0x0015 +#define REG_INT_FLG_CLR_AFE 0x0016 +#define REG_INT_MASK_TOP 0x0017 +#define REG_INT_MASK_SUS 0x0018 +#define REG_INT_MASK_DDC 0x0019 +#define REG_INT_MASK_RATE 0x001A +#define REG_INT_MASK_MODE 0x001B +#define REG_INT_MASK_INFO 0x001C +#define REG_INT_MASK_AUDIO 0x001D +#define REG_INT_MASK_HDCP 0x001E +#define REG_INT_MASK_AFE 0x001F +#define REG_DETECT_5V 0x0020 +#define REG_SUS_STATUS 0x0021 +#define REG_V_PER 0x0022 +#define REG_H_PER 0x0025 +#define REG_HS_WIDTH 0x0027 +#define REG_FMT_H_TOT 0x0029 +#define REG_FMT_H_ACT 0x002b +#define REG_FMT_H_FRONT 0x002d +#define REG_FMT_H_SYNC 0x002f +#define REG_FMT_H_BACK 0x0031 +#define REG_FMT_V_TOT 0x0033 +#define REG_FMT_V_ACT 0x0035 +#define REG_FMT_V_FRONT_F1 0x0037 +#define REG_FMT_V_FRONT_F2 0x0038 +#define REG_FMT_V_SYNC 0x0039 +#define REG_FMT_V_BACK_F1 0x003a +#define REG_FMT_V_BACK_F2 0x003b +#define REG_FMT_DE_ACT 0x003c +#define REG_RATE_CTRL 0x0040 +#define REG_CLK_MIN_RATE 0x0043 +#define REG_CLK_MAX_RATE 0x0046 +#define REG_CLK_A_STATUS 0x0049 +#define REG_CLK_A_RATE 0x004A +#define REG_DRIFT_CLK_A_REG 0x004D +#define REG_CLK_B_STATUS 0x004E +#define REG_CLK_B_RATE 0x004F +#define REG_DRIFT_CLK_B_REG 0x0052 +#define REG_HDCP_CTRL 0x0060 +#define REG_HDCP_KDS 0x0061 +#define REG_HDCP_BCAPS 0x0063 +#define REG_HDCP_KEY_CTRL 0x0064 +#define REG_INFO_CTRL 0x0076 +#define REG_INFO_EXCEED 0x0077 +#define REG_PIX_REPEAT 0x007B +#define REG_AUDIO_PATH 0x007C +#define REG_AUDCFG 0x007D +#define REG_AUDIO_OUT_ENABLE 0x007E +#define REG_AUDIO_OUT_HIZ 0x007F +#define REG_VDP_CTRL 0x0080 +#define REG_VDP_MATRIX 0x0081 +#define REG_VHREF_CTRL 0x00A0 +#define REG_PXCNT_PR 0x00A2 +#define REG_PXCNT_NPIX 0x00A4 +#define REG_LCNT_PR 0x00A6 +#define REG_LCNT_NLIN 0x00A8 +#define REG_HREF_S 0x00AA +#define REG_HREF_E 0x00AC +#define REG_HS_S 0x00AE +#define REG_HS_E 0x00B0 +#define REG_VREF_F1_S 0x00B2 +#define REG_VREF_F1_WIDTH 0x00B4 +#define REG_VREF_F2_S 0x00B5 +#define REG_VREF_F2_WIDTH 0x00B7 +#define REG_VS_F1_LINE_S 0x00B8 +#define REG_VS_F1_LINE_WIDTH 0x00BA +#define REG_VS_F2_LINE_S 0x00BB +#define REG_VS_F2_LINE_WIDTH 0x00BD +#define REG_VS_F1_PIX_S 0x00BE +#define REG_VS_F1_PIX_E 0x00C0 +#define REG_VS_F2_PIX_S 0x00C2 +#define REG_VS_F2_PIX_E 0x00C4 +#define REG_FREF_F1_S 0x00C6 +#define REG_FREF_F2_S 0x00C8 +#define REG_FDW_S 0x00ca +#define REG_FDW_E 0x00cc +#define REG_BLK_GY 0x00da +#define REG_BLK_BU 0x00dc +#define REG_BLK_RV 0x00de +#define REG_FILTERS_CTRL 0x00e0 +#define REG_DITHERING_CTRL 0x00E9 +#define REG_OF 0x00EA +#define REG_PCLK 0x00EB +#define REG_HS_HREF 0x00EC +#define REG_VS_VREF 0x00ED +#define REG_DE_FREF 0x00EE +#define REG_VP35_32_CTRL 0x00EF +#define REG_VP31_28_CTRL 0x00F0 +#define REG_VP27_24_CTRL 0x00F1 +#define REG_VP23_20_CTRL 0x00F2 +#define REG_VP19_16_CTRL 0x00F3 +#define REG_VP15_12_CTRL 0x00F4 +#define REG_VP11_08_CTRL 0x00F5 +#define REG_VP07_04_CTRL 0x00F6 +#define REG_VP03_00_CTRL 0x00F7 +#define REG_CURPAGE_00H 0xFF + +#define MASK_VPER 0x3fffff +#define MASK_VHREF 0x3fff +#define MASK_HPER 0x0fff +#define MASK_HSWIDTH 0x03ff + +/* HPD Detection */ +#define DETECT_UTIL BIT(7) /* utility of HDMI level */ +#define DETECT_HPD BIT(6) /* HPD of HDMI level */ +#define DETECT_5V_SEL BIT(2) /* 5V present on selected input */ +#define DETECT_5V_B BIT(1) /* 5V present on input B */ +#define DETECT_5V_A BIT(0) /* 5V present on input A */ + +/* Input Select */ +#define INPUT_SEL_RST_FMT BIT(7) /* 1=reset format measurement */ +#define INPUT_SEL_RST_VDP BIT(2) /* 1=reset video data path */ +#define INPUT_SEL_OUT_MODE BIT(1) /* 0=loop 1=bypass */ +#define INPUT_SEL_B BIT(0) /* 0=inputA 1=inputB */ + +/* Service Mode */ +#define SVC_MODE_CLK2_MASK 0xc0 +#define SVC_MODE_CLK2_SHIFT 6 +#define SVC_MODE_CLK2_XTL 0L +#define SVC_MODE_CLK2_XTLDIV2 1L +#define SVC_MODE_CLK2_HDMIX2 3L +#define SVC_MODE_CLK1_MASK 0x30 +#define SVC_MODE_CLK1_SHIFT 4 +#define SVC_MODE_CLK1_XTAL 0L +#define SVC_MODE_CLK1_XTLDIV2 1L +#define SVC_MODE_CLK1_HDMI 3L +#define SVC_MODE_RAMP BIT(3) /* 0=colorbar 1=ramp */ +#define SVC_MODE_PAL BIT(2) /* 0=NTSC(480i/p) 1=PAL(576i/p) */ +#define SVC_MODE_INT_PROG BIT(1) /* 0=interlaced 1=progressive */ +#define SVC_MODE_SM_ON BIT(0) /* Enable color bars and tone gen */ + +/* HDP Manual Control */ +#define HPD_MAN_CTRL_HPD_PULSE BIT(7) /* HPD Pulse low 110ms */ +#define HPD_MAN_CTRL_5VEN BIT(2) /* Output 5V */ +#define HPD_MAN_CTRL_HPD_B BIT(1) /* Assert HPD High for Input A */ +#define HPD_MAN_CTRL_HPD_A BIT(0) /* Assert HPD High for Input A */ + +/* RT_MAN_CTRL */ +#define RT_MAN_CTRL_RT_AUTO BIT(7) +#define RT_MAN_CTRL_RT BIT(6) +#define RT_MAN_CTRL_RT_B BIT(1) /* enable TMDS pull-up on Input B */ +#define RT_MAN_CTRL_RT_A BIT(0) /* enable TMDS pull-up on Input A */ + +/* VDP_CTRL */ +#define VDP_CTRL_COMPDEL_BP BIT(5) /* bypass compdel */ +#define VDP_CTRL_FORMATTER_BP BIT(4) /* bypass formatter */ +#define VDP_CTRL_PREFILTER_BP BIT(1) /* bypass prefilter */ +#define VDP_CTRL_MATRIX_BP BIT(0) /* bypass matrix conversion */ + +/* REG_VHREF_CTRL */ +#define VHREF_INT_DET BIT(7) /* interlace detect: 1=alt 0=frame */ +#define VHREF_VSYNC_MASK 0x60 +#define VHREF_VSYNC_SHIFT 6 +#define VHREF_VSYNC_AUTO 0L +#define VHREF_VSYNC_FDW 1L +#define VHREF_VSYNC_EVEN 2L +#define VHREF_VSYNC_ODD 3L +#define VHREF_STD_DET_MASK 0x18 +#define VHREF_STD_DET_SHIFT 3 +#define VHREF_STD_DET_PAL 0L +#define VHREF_STD_DET_NTSC 1L +#define VHREF_STD_DET_AUTO 2L +#define VHREF_STD_DET_OFF 3L +#define VHREF_VREF_SRC_STD BIT(2) /* 1=from standard 0=manual */ +#define VHREF_HREF_SRC_STD BIT(1) /* 1=from standard 0=manual */ +#define VHREF_HSYNC_SEL_HS BIT(0) /* 1=HS 0=VS */ + +/* AUDIO_OUT_ENABLE */ +#define AUDIO_OUT_ENABLE_ACLK BIT(5) +#define AUDIO_OUT_ENABLE_WS BIT(4) +#define AUDIO_OUT_ENABLE_AP3 BIT(3) +#define AUDIO_OUT_ENABLE_AP2 BIT(2) +#define AUDIO_OUT_ENABLE_AP1 BIT(1) +#define AUDIO_OUT_ENABLE_AP0 BIT(0) + +/* Prefilter Control */ +#define FILTERS_CTRL_BU_MASK 0x0c +#define FILTERS_CTRL_BU_SHIFT 2 +#define FILTERS_CTRL_RV_MASK 0x03 +#define FILTERS_CTRL_RV_SHIFT 0 +#define FILTERS_CTRL_OFF 0L /* off */ +#define FILTERS_CTRL_2TAP 1L /* 2 Taps */ +#define FILTERS_CTRL_7TAP 2L /* 7 Taps */ +#define FILTERS_CTRL_2_7TAP 3L /* 2/7 Taps */ + +/* PCLK Configuration */ +#define PCLK_DELAY_MASK 0x70 +#define PCLK_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define PCLK_INV_SHIFT 2 +#define PCLK_SEL_MASK 0x03 /* clock scaler */ +#define PCLK_SEL_SHIFT 0 +#define PCLK_SEL_X1 0L +#define PCLK_SEL_X2 1L +#define PCLK_SEL_DIV2 2L +#define PCLK_SEL_DIV4 3L + +/* Pixel Repeater */ +#define PIX_REPEAT_MASK_UP_SEL 0x30 +#define PIX_REPEAT_MASK_REP 0x0f +#define PIX_REPEAT_SHIFT 4 +#define PIX_REPEAT_CHROMA 1 + +/* Page 0x01 - HDMI info and packets */ +#define REG_HDMI_FLAGS 0x0100 +#define REG_DEEP_COLOR_MODE 0x0101 +#define REG_AUDIO_FLAGS 0x0108 +#define REG_AUDIO_FREQ 0x0109 +#define REG_ACP_PACKET_TYPE 0x0141 +#define REG_ISRC1_PACKET_TYPE 0x0161 +#define REG_ISRC2_PACKET_TYPE 0x0181 +#define REG_GBD_PACKET_TYPE 0x01a1 + +/* HDMI_FLAGS */ +#define HDMI_FLAGS_AUDIO BIT(7) /* Audio packet in last videoframe */ +#define HDMI_FLAGS_HDMI BIT(6) /* HDMI detected */ +#define HDMI_FLAGS_EESS BIT(5) /* EESS detected */ +#define HDMI_FLAGS_HDCP BIT(4) /* HDCP detected */ +#define HDMI_FLAGS_AVMUTE BIT(3) /* AVMUTE */ +#define HDMI_FLAGS_AUD_LAYOUT BIT(2) /* Layout status Audio sample packet */ +#define HDMI_FLAGS_AUD_FIFO_OF BIT(1) /* FIFO read/write pointers crossed */ +#define HDMI_FLAGS_AUD_FIFO_LOW BIT(0) /* FIFO read ptr within 2 of write */ + +/* Page 0x12 - HDMI Extra control and debug */ +#define REG_CLK_CFG 0x1200 +#define REG_CLK_OUT_CFG 0x1201 +#define REG_CFG1 0x1202 +#define REG_CFG2 0x1203 +#define REG_WDL_CFG 0x1210 +#define REG_DELOCK_DELAY 0x1212 +#define REG_PON_OVR_EN 0x12A0 +#define REG_PON_CBIAS 0x12A1 +#define REG_PON_RESCAL 0x12A2 +#define REG_PON_RES 0x12A3 +#define REG_PON_CLK 0x12A4 +#define REG_PON_PLL 0x12A5 +#define REG_PON_EQ 0x12A6 +#define REG_PON_DES 0x12A7 +#define REG_PON_OUT 0x12A8 +#define REG_PON_MUX 0x12A9 +#define REG_MODE_REC_CFG1 0x12F8 +#define REG_MODE_REC_CFG2 0x12F9 +#define REG_MODE_REC_STS 0x12FA +#define REG_AUDIO_LAYOUT 0x12D0 + +#define PON_EN 1 +#define PON_DIS 0 + +/* CLK CFG */ +#define CLK_CFG_INV_OUT_CLK BIT(7) +#define CLK_CFG_INV_BUS_CLK BIT(6) +#define CLK_CFG_SEL_ACLK_EN BIT(1) +#define CLK_CFG_SEL_ACLK BIT(0) +#define CLK_CFG_DIS 0 + +/* Page 0x13 - HDMI Extra control and debug */ +#define REG_DEEP_COLOR_CTRL 0x1300 +#define REG_CGU_DBG_SEL 0x1305 +#define REG_HDCP_DDC_ADDR 0x1310 +#define REG_HDCP_KIDX 0x1316 +#define REG_DEEP_PLL7_BYP 0x1347 +#define REG_HDCP_DE_CTRL 0x1370 +#define REG_HDCP_EP_FILT_CTRL 0x1371 +#define REG_HDMI_CTRL 0x1377 +#define REG_HMTP_CTRL 0x137a +#define REG_TIMER_D 0x13CF +#define REG_SUS_SET_RGB0 0x13E1 +#define REG_SUS_SET_RGB1 0x13E2 +#define REG_SUS_SET_RGB2 0x13E3 +#define REG_SUS_SET_RGB3 0x13E4 +#define REG_SUS_SET_RGB4 0x13E5 +#define REG_MAN_SUS_HDMI_SEL 0x13E8 +#define REG_MAN_HDMI_SET 0x13E9 +#define REG_SUS_CLOCK_GOOD 0x13EF + +/* HDCP DE Control */ +#define HDCP_DE_MODE_MASK 0xc0 /* DE Measurement mode */ +#define HDCP_DE_MODE_SHIFT 6 +#define HDCP_DE_REGEN_EN BIT(5) /* enable regen mode */ +#define HDCP_DE_FILTER_MASK 0x18 /* DE filter sensitivity */ +#define HDCP_DE_FILTER_SHIFT 3 +#define HDCP_DE_COMP_MASK 0x07 /* DE Composition mode */ +#define HDCP_DE_COMP_MIXED 6L +#define HDCP_DE_COMP_OR 5L +#define HDCP_DE_COMP_AND 4L +#define HDCP_DE_COMP_CH3 3L +#define HDCP_DE_COMP_CH2 2L +#define HDCP_DE_COMP_CH1 1L +#define HDCP_DE_COMP_CH0 0L + +/* HDCP EP Filter Control */ +#define HDCP_EP_FIL_CTL_MASK 0x30 +#define HDCP_EP_FIL_CTL_SHIFT 4 +#define HDCP_EP_FIL_VS_MASK 0x0c +#define HDCP_EP_FIL_VS_SHIFT 2 +#define HDCP_EP_FIL_HS_MASK 0x03 +#define HDCP_EP_FIL_HS_SHIFT 0 + +/* HDMI_CTRL */ +#define HDMI_CTRL_MUTE_MASK 0x0c +#define HDMI_CTRL_MUTE_SHIFT 2 +#define HDMI_CTRL_MUTE_AUTO 0L +#define HDMI_CTRL_MUTE_OFF 1L +#define HDMI_CTRL_MUTE_ON 2L +#define HDMI_CTRL_HDCP_MASK 0x03 +#define HDMI_CTRL_HDCP_SHIFT 0 +#define HDMI_CTRL_HDCP_EESS 2L +#define HDMI_CTRL_HDCP_OESS 1L +#define HDMI_CTRL_HDCP_AUTO 0L + +/* CGU_DBG_SEL bits */ +#define CGU_DBG_CLK_SEL_MASK 0x18 +#define CGU_DBG_CLK_SEL_SHIFT 3 +#define CGU_DBG_XO_FRO_SEL BIT(2) +#define CGU_DBG_VDP_CLK_SEL BIT(1) +#define CGU_DBG_PIX_CLK_SEL BIT(0) + +/* REG_MAN_SUS_HDMI_SEL / REG_MAN_HDMI_SET bits */ +#define MAN_DIS_OUT_BUF BIT(7) +#define MAN_DIS_ANA_PATH BIT(6) +#define MAN_DIS_HDCP BIT(5) +#define MAN_DIS_TMDS_ENC BIT(4) +#define MAN_DIS_TMDS_FLOW BIT(3) +#define MAN_RST_HDCP BIT(2) +#define MAN_RST_TMDS_ENC BIT(1) +#define MAN_RST_TMDS_FLOW BIT(0) + +/* Page 0x14 - Audio Extra control and debug */ +#define REG_FIFO_LATENCY_VAL 0x1403 +#define REG_AUDIO_CLOCK 0x1411 +#define REG_TEST_NCTS_CTRL 0x1415 +#define REG_TEST_AUDIO_FREQ 0x1426 +#define REG_TEST_MODE 0x1437 + +/* Audio Clock Configuration */ +#define AUDIO_CLOCK_PLL_PD BIT(7) /* powerdown PLL */ +#define AUDIO_CLOCK_SEL_MASK 0x7f +#define AUDIO_CLOCK_SEL_16FS 0L /* 16*fs */ +#define AUDIO_CLOCK_SEL_32FS 1L /* 32*fs */ +#define AUDIO_CLOCK_SEL_64FS 2L /* 64*fs */ +#define AUDIO_CLOCK_SEL_128FS 3L /* 128*fs */ +#define AUDIO_CLOCK_SEL_256FS 4L /* 256*fs */ +#define AUDIO_CLOCK_SEL_512FS 5L /* 512*fs */ + +/* Page 0x20: EDID and Hotplug Detect */ +#define REG_EDID_IN_BYTE0 0x2000 /* EDID base */ +#define REG_EDID_IN_VERSION 0x2080 +#define REG_EDID_ENABLE 0x2081 +#define REG_HPD_POWER 0x2084 +#define REG_HPD_AUTO_CTRL 0x2085 +#define REG_HPD_DURATION 0x2086 +#define REG_RX_HPD_HEAC 0x2087 + +/* EDID_ENABLE */ +#define EDID_ENABLE_NACK_OFF BIT(7) +#define EDID_ENABLE_EDID_ONLY BIT(6) +#define EDID_ENABLE_B_EN BIT(1) +#define EDID_ENABLE_A_EN BIT(0) + +/* HPD Power */ +#define HPD_POWER_BP_MASK 0x0c +#define HPD_POWER_BP_SHIFT 2 +#define HPD_POWER_BP_LOW 0L +#define HPD_POWER_BP_HIGH 1L +#define HPD_POWER_EDID_ONLY BIT(1) + +/* HPD Auto control */ +#define HPD_AUTO_READ_EDID BIT(7) +#define HPD_AUTO_HPD_F3TECH BIT(5) +#define HPD_AUTO_HP_OTHER BIT(4) +#define HPD_AUTO_HPD_UNSEL BIT(3) +#define HPD_AUTO_HPD_ALL_CH BIT(2) +#define HPD_AUTO_HPD_PRV_CH BIT(1) +#define HPD_AUTO_HPD_NEW_CH BIT(0) + +/* Page 0x21 - EDID content */ +#define REG_EDID_IN_BYTE128 0x2100 /* CEA Extension block */ +#define REG_EDID_IN_SPA_SUB 0x2180 +#define REG_EDID_IN_SPA_AB_A 0x2181 +#define REG_EDID_IN_SPA_CD_A 0x2182 +#define REG_EDID_IN_CKSUM_A 0x2183 +#define REG_EDID_IN_SPA_AB_B 0x2184 +#define REG_EDID_IN_SPA_CD_B 0x2185 +#define REG_EDID_IN_CKSUM_B 0x2186 + +/* Page 0x30 - NV Configuration */ +#define REG_RT_AUTO_CTRL 0x3000 +#define REG_EQ_MAN_CTRL0 0x3001 +#define REG_EQ_MAN_CTRL1 0x3002 +#define REG_OUTPUT_CFG 0x3003 +#define REG_MUTE_CTRL 0x3004 +#define REG_SLAVE_ADDR 0x3005 +#define REG_CMTP_REG6 0x3006 +#define REG_CMTP_REG7 0x3007 +#define REG_CMTP_REG8 0x3008 +#define REG_CMTP_REG9 0x3009 +#define REG_CMTP_REGA 0x300A +#define REG_CMTP_REGB 0x300B +#define REG_CMTP_REGC 0x300C +#define REG_CMTP_REGD 0x300D +#define REG_CMTP_REGE 0x300E +#define REG_CMTP_REGF 0x300F +#define REG_CMTP_REG10 0x3010 +#define REG_CMTP_REG11 0x3011 + +/* Page 0x80 - CEC */ +#define REG_PWR_CONTROL 0x80F4 +#define REG_OSC_DIVIDER 0x80F5 +#define REG_EN_OSC_PERIOD_LSB 0x80F8 +#define REG_CONTROL 0x80FF + +/* global interrupt flags (INT_FLG_CRL_TOP) */ +#define INTERRUPT_AFE BIT(7) /* AFE module */ +#define INTERRUPT_HDCP BIT(6) /* HDCP module */ +#define INTERRUPT_AUDIO BIT(5) /* Audio module */ +#define INTERRUPT_INFO BIT(4) /* Infoframe module */ +#define INTERRUPT_MODE BIT(3) /* HDMI mode module */ +#define INTERRUPT_RATE BIT(2) /* rate module */ +#define INTERRUPT_DDC BIT(1) /* DDC module */ +#define INTERRUPT_SUS BIT(0) /* SUS module */ + +/* INT_FLG_CLR_HDCP bits */ +#define MASK_HDCP_MTP BIT(7) /* HDCP MTP busy */ +#define MASK_HDCP_DLMTP BIT(4) /* HDCP end download MTP to SRAM */ +#define MASK_HDCP_DLRAM BIT(3) /* HDCP end download keys from SRAM */ +#define MASK_HDCP_ENC BIT(2) /* HDCP ENC */ +#define MASK_STATE_C5 BIT(1) /* HDCP State C5 reached */ +#define MASK_AKSV BIT(0) /* AKSV received (start of auth) */ + +/* INT_FLG_CLR_RATE bits */ +#define MASK_RATE_B_DRIFT BIT(7) /* Rate measurement drifted */ +#define MASK_RATE_B_ST BIT(6) /* Rate measurement stability change */ +#define MASK_RATE_B_ACT BIT(5) /* Rate measurement activity change */ +#define MASK_RATE_B_PST BIT(4) /* Rate measreument presence change */ +#define MASK_RATE_A_DRIFT BIT(3) /* Rate measurement drifted */ +#define MASK_RATE_A_ST BIT(2) /* Rate measurement stability change */ +#define MASK_RATE_A_ACT BIT(1) /* Rate measurement presence change */ +#define MASK_RATE_A_PST BIT(0) /* Rate measreument presence change */ + +/* INT_FLG_CLR_SUS (Start Up Sequencer) bits */ +#define MASK_MPT BIT(7) /* Config MTP end of process */ +#define MASK_FMT BIT(5) /* Video format changed */ +#define MASK_RT_PULSE BIT(4) /* End of termination resistance pulse */ +#define MASK_SUS_END BIT(3) /* SUS last state reached */ +#define MASK_SUS_ACT BIT(2) /* Activity of selected input changed */ +#define MASK_SUS_CH BIT(1) /* Selected input changed */ +#define MASK_SUS_ST BIT(0) /* SUS state changed */ + +/* INT_FLG_CLR_DDC bits */ +#define MASK_EDID_MTP BIT(7) /* EDID MTP end of process */ +#define MASK_DDC_ERR BIT(6) /* master DDC error */ +#define MASK_DDC_CMD_DONE BIT(5) /* master DDC cmd send correct */ +#define MASK_READ_DONE BIT(4) /* End of down EDID read */ +#define MASK_RX_DDC_SW BIT(3) /* Output DDC switching finished */ +#define MASK_HDCP_DDC_SW BIT(2) /* HDCP DDC switching finished */ +#define MASK_HDP_PULSE_END BIT(1) /* End of Hot Plug Detect pulse */ +#define MASK_DET_5V BIT(0) /* Detection of +5V */ + +/* INT_FLG_CLR_MODE bits */ +#define MASK_HDMI_FLG BIT(7) /* HDMI mode/avmute/encrypt/FIFO fail */ +#define MASK_GAMUT BIT(6) /* Gamut packet */ +#define MASK_ISRC2 BIT(5) /* ISRC2 packet */ +#define MASK_ISRC1 BIT(4) /* ISRC1 packet */ +#define MASK_ACP BIT(3) /* Audio Content Protection packet */ +#define MASK_DC_NO_GCP BIT(2) /* GCP not received in 5 frames */ +#define MASK_DC_PHASE BIT(1) /* deepcolor pixel phase needs update */ +#define MASK_DC_MODE BIT(0) /* deepcolor color depth changed */ + +/* INT_FLG_CLR_INFO bits (Infoframe Change Status) */ +#define MASK_MPS_IF BIT(6) /* MPEG Source Product */ +#define MASK_AUD_IF BIT(5) /* Audio */ +#define MASK_SPD_IF BIT(4) /* Source Product Descriptor */ +#define MASK_AVI_IF BIT(3) /* Auxiliary Video IF */ +#define MASK_VS_IF_OTHER_BK2 BIT(2) /* Vendor Specific (bank2) */ +#define MASK_VS_IF_OTHER_BK1 BIT(1) /* Vendor Specific (bank1) */ +#define MASK_VS_IF_HDMI BIT(0) /* Vendor Specific (w/ HDMI LLC code) */ + +/* INT_FLG_CLR_AUDIO bits */ +#define MASK_AUDIO_FREQ_FLG BIT(5) /* Audio freq change */ +#define MASK_AUDIO_FLG BIT(4) /* DST, OBA, HBR, ASP change */ +#define MASK_MUTE_FLG BIT(3) /* Audio Mute */ +#define MASK_CH_STATE BIT(2) /* Channel status */ +#define MASK_UNMUTE_FIFO BIT(1) /* Audio Unmute */ +#define MASK_ERROR_FIFO_PT BIT(0) /* Audio FIFO pointer error */ + +/* INT_FLG_CLR_AFE bits */ +#define MASK_AFE_WDL_UNLOCKED BIT(7) /* Wordlocker was unlocked */ +#define MASK_AFE_GAIN_DONE BIT(6) /* Gain calibration done */ +#define MASK_AFE_OFFSET_DONE BIT(5) /* Offset calibration done */ +#define MASK_AFE_ACTIVITY_DET BIT(4) /* Activity detected on data */ +#define MASK_AFE_PLL_LOCK BIT(3) /* TMDS PLL is locked */ +#define MASK_AFE_TRMCAL_DONE BIT(2) /* Termination calibration done */ +#define MASK_AFE_ASU_STATE BIT(1) /* ASU state is reached */ +#define MASK_AFE_ASU_READY BIT(0) /* AFE calibration done: TMDS ready */ + +/* Audio Output */ +#define AUDCFG_CLK_INVERT BIT(7) /* invert A_CLK polarity */ +#define AUDCFG_TEST_TONE BIT(6) /* enable test tone generator */ +#define AUDCFG_BUS_SHIFT 5 +#define AUDCFG_BUS_I2S 0L +#define AUDCFG_BUS_SPDIF 1L +#define AUDCFG_I2SW_SHIFT 4 +#define AUDCFG_I2SW_16 0L +#define AUDCFG_I2SW_32 1L +#define AUDCFG_AUTO_MUTE_EN BIT(3) /* Enable Automatic audio mute */ +#define AUDCFG_HBR_SHIFT 2 +#define AUDCFG_HBR_STRAIGHT 0L /* straight via AP0 */ +#define AUDCFG_HBR_DEMUX 1L /* demuxed via AP0:AP3 */ +#define AUDCFG_TYPE_MASK 0x03 +#define AUDCFG_TYPE_SHIFT 0 +#define AUDCFG_TYPE_DST 3L /* Direct Stream Transfer (DST) */ +#define AUDCFG_TYPE_OBA 2L /* One Bit Audio (OBA) */ +#define AUDCFG_TYPE_HBR 1L /* High Bit Rate (HBR) */ +#define AUDCFG_TYPE_PCM 0L /* Audio samples */ + +/* Video Formatter */ +#define OF_VP_ENABLE BIT(7) /* VP[35:0]/HS/VS/DE/CLK */ +#define OF_BLK BIT(4) /* blanking codes */ +#define OF_TRC BIT(3) /* timing codes (SAV/EAV) */ +#define OF_FMT_MASK 0x3 +#define OF_FMT_444 0L /* RGB444/YUV444 */ +#define OF_FMT_422_SMPT 1L /* YUV422 semi-planar */ +#define OF_FMT_422_CCIR 2L /* YUV422 CCIR656 */ + +/* HS/HREF output control */ +#define HS_HREF_DELAY_MASK 0xf0 +#define HS_HREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define HS_HREF_PXQ_SHIFT 3 /* Timing codes from HREF */ +#define HS_HREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define HS_HREF_SEL_MASK 0x03 +#define HS_HREF_SEL_SHIFT 0 +#define HS_HREF_SEL_HS_VHREF 0L /* HS from VHREF */ +#define HS_HREF_SEL_HREF_VHREF 1L /* HREF from VHREF */ +#define HS_HREF_SEL_HREF_HDMI 2L /* HREF from HDMI */ +#define HS_HREF_SEL_NONE 3L /* not generated */ + +/* VS output control */ +#define VS_VREF_DELAY_MASK 0xf0 +#define VS_VREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define VS_VREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define VS_VREF_SEL_MASK 0x03 +#define VS_VREF_SEL_SHIFT 0 +#define VS_VREF_SEL_VS_VHREF 0L /* VS from VHREF */ +#define VS_VREF_SEL_VREF_VHREF 1L /* VREF from VHREF */ +#define VS_VREF_SEL_VREF_HDMI 2L /* VREF from HDMI */ +#define VS_VREF_SEL_NONE 3L /* not generated */ + +/* DE/FREF output control */ +#define DE_FREF_DELAY_MASK 0xf0 +#define DE_FREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */ +#define DE_FREF_DE_PXQ_SHIFT 3 /* Timing codes from DE */ +#define DE_FREF_INV_SHIFT 2 /* polarity (1=invert) */ +#define DE_FREF_SEL_MASK 0x03 +#define DE_FREF_SEL_SHIFT 0 +#define DE_FREF_SEL_DE_VHREF 0L /* DE from VHREF (HREF and not(VREF) */ +#define DE_FREF_SEL_FREF_VHREF 1L /* FREF from VHREF */ +#define DE_FREF_SEL_FREF_HDMI 2L /* FREF from HDMI */ +#define DE_FREF_SEL_NONE 3L /* not generated */ + +/* HDMI_SOFT_RST bits */ +#define RESET_DC BIT(7) /* Reset deep color module */ +#define RESET_HDCP BIT(6) /* Reset HDCP module */ +#define RESET_KSV BIT(5) /* Reset KSV-FIFO */ +#define RESET_SCFG BIT(4) /* Reset HDCP and repeater function */ +#define RESET_HCFG BIT(3) /* Reset HDCP DDC part */ +#define RESET_PA BIT(2) /* Reset polarity adjust */ +#define RESET_EP BIT(1) /* Reset Error protection */ +#define RESET_TMDS BIT(0) /* Reset TMDS (calib, encoding, flow) */ + +/* HDMI_INFO_RST bits */ +#define NACK_HDCP BIT(7) /* No ACK on HDCP request */ +#define RESET_FIFO BIT(4) /* Reset Audio FIFO control */ +#define RESET_GAMUT BIT(3) /* Clear Gamut packet */ +#define RESET_AI BIT(2) /* Clear ACP and ISRC packets */ +#define RESET_IF BIT(1) /* Clear all Audio infoframe packets */ +#define RESET_AUDIO BIT(0) /* Reset Audio FIFO control */ + +/* HDCP_BCAPS bits */ +#define HDCP_HDMI BIT(7) /* HDCP suports HDMI (vs DVI only) */ +#define HDCP_REPEATER BIT(6) /* HDCP supports repeater function */ +#define HDCP_READY BIT(5) /* set by repeater function */ +#define HDCP_FAST BIT(4) /* Up to 400kHz */ +#define HDCP_11 BIT(1) /* HDCP 1.1 supported */ +#define HDCP_FAST_REAUTH BIT(0) /* fast reauthentication supported */ + +/* Audio output formatter */ +#define AUDIO_LAYOUT_SP_FLAG BIT(2) /* sp flag used by FIFO */ +#define AUDIO_LAYOUT_MANUAL BIT(1) /* manual layout (vs per pkt) */ +#define AUDIO_LAYOUT_LAYOUT1 BIT(0) /* Layout1: AP0-3 vs Layout0:AP0 */ + +/* masks for interrupt status registers */ +#define MASK_SUS_STATUS 0x1F +#define LAST_STATE_REACHED 0x1B +#define MASK_CLK_STABLE 0x04 +#define MASK_CLK_ACTIVE 0x02 +#define MASK_SUS_STATE 0x10 +#define MASK_SR_FIFO_FIFO_CTRL 0x30 +#define MASK_AUDIO_FLAG 0x10 + +/* Rate measurement */ +#define RATE_REFTIM_ENABLE 0x01 +#define CLK_MIN_RATE 0x0057e4 +#define CLK_MAX_RATE 0x0395f8 +#define WDL_CFG_VAL 0x82 +#define DC_FILTER_VAL 0x31 + +/* Infoframe */ +#define VS_HDMI_IF_UPDATE 0x0200 +#define VS_HDMI_IF 0x0201 +#define VS_BK1_IF_UPDATE 0x0220 +#define VS_BK1_IF 0x0221 +#define VS_BK2_IF_UPDATE 0x0240 +#define VS_BK2_IF 0x0241 +#define AVI_IF_UPDATE 0x0260 +#define AVI_IF 0x0261 +#define SPD_IF_UPDATE 0x0280 +#define SPD_IF 0x0281 +#define AUD_IF_UPDATE 0x02a0 +#define AUD_IF 0x02a1 +#define MPS_IF_UPDATE 0x02c0 +#define MPS_IF 0x02c1 -- cgit From 4395fb475a27ddcb33c27380e132ef5354ff67c6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Feb 2018 12:54:28 -0500 Subject: tda1997x: get rid of an unused var 1 warning regressions: + drivers/media/i2c/tda1997x.c: warning: variable 'last_irq_status' set but not used [-Wunused-but-set-variable]: => 1421:17 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index a480aafecbf6..3021913c28fa 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1418,13 +1418,13 @@ static void tda1997x_irq_rate(struct tda1997x_state *state, u8 *flags) struct v4l2_subdev *sd = &state->sd; u8 reg, source; - u8 irq_status, last_irq_status; + u8 irq_status; source = io_read(sd, REG_INT_FLG_CLR_RATE); io_write(sd, REG_INT_FLG_CLR_RATE, source); /* read status regs */ - last_irq_status = irq_status = tda1997x_read_activity_status_regs(sd); + irq_status = tda1997x_read_activity_status_regs(sd); /* * read clock status reg until INT_FLG_CLR_RATE is still 0 -- cgit From 859086ae3636eae0bf9f0fbbce2daf4d41ae9474 Mon Sep 17 00:00:00 2001 From: Edgar Thier Date: Thu, 12 Oct 2017 03:54:17 -0400 Subject: media: uvcvideo: Apply flags from device to actual properties Use flags the device exposes for UVC controls. This allows the device to define which property flags are set. Since some cameras offer auto-adjustments for properties (e.g. auto-gain), the values of other properties (e.g. gain) can change in the camera. Examining the flags ensures that the driver is aware of such properties. Signed-off-by: Edgar Thier Reviewed-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 52 ++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 20397aba6849..586f0e94061b 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1590,6 +1590,36 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, * Dynamic controls */ +/* + * Retrieve flags for a given control + */ +static int uvc_ctrl_get_flags(struct uvc_device *dev, + const struct uvc_control *ctrl, + struct uvc_control_info *info) +{ + u8 *data; + int ret; + + data = kmalloc(1, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, + info->selector, data, 1); + if (!ret) + info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX + | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF + | (data[0] & UVC_CONTROL_CAP_GET ? + UVC_CTRL_FLAG_GET_CUR : 0) + | (data[0] & UVC_CONTROL_CAP_SET ? + UVC_CTRL_FLAG_SET_CUR : 0) + | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? + UVC_CTRL_FLAG_AUTO_UPDATE : 0); + + kfree(data); + return ret; +} + static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev, const struct uvc_control *ctrl, struct uvc_control_info *info) { @@ -1659,25 +1689,14 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev, info->size = le16_to_cpup((__le16 *)data); - /* Query the control information (GET_INFO) */ - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum, - info->selector, data, 1); + ret = uvc_ctrl_get_flags(dev, ctrl, info); if (ret < 0) { uvc_trace(UVC_TRACE_CONTROL, - "GET_INFO failed on control %pUl/%u (%d).\n", + "Failed to get flags for control %pUl/%u (%d).\n", info->entity, info->selector, ret); goto done; } - info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX - | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF - | (data[0] & UVC_CONTROL_CAP_GET ? - UVC_CTRL_FLAG_GET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_SET ? - UVC_CTRL_FLAG_SET_CUR : 0) - | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? - UVC_CTRL_FLAG_AUTO_UPDATE : 0); - uvc_ctrl_fixup_xu_info(dev, ctrl, info); uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, " @@ -1902,6 +1921,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, goto done; } + /* + * Retrieve control flags from the device. Ignore errors and work with + * default flag values from the uvc_ctrl array when the device doesn't + * properly implement GET_INFO on standard controls. + */ + uvc_ctrl_get_flags(dev, ctrl, &ctrl->info); + ctrl->initialized = 1; uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " -- cgit From 07b7d9fc2ab5b510bfae51b9ccf29c9ec7fcb4cd Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 4 Jan 2018 17:51:29 -0500 Subject: media: uvcvideo: Support multiple frame descriptors with the same dimensions The Microsoft HoloLens Sensors device has two separate frame descriptors with the same dimensions, each with a single different frame interval: VideoStreaming Interface Descriptor: bLength 30 bDescriptorType 36 bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) bFrameIndex 1 bmCapabilities 0x00 Still image unsupported wWidth 1280 wHeight 481 dwMinBitRate 147763200 dwMaxBitRate 147763200 dwMaxVideoFrameBufferSize 615680 dwDefaultFrameInterval 333333 bFrameIntervalType 1 dwFrameInterval( 0) 333333 VideoStreaming Interface Descriptor: bLength 30 bDescriptorType 36 bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) bFrameIndex 2 bmCapabilities 0x00 Still image unsupported wWidth 1280 wHeight 481 dwMinBitRate 443289600 dwMaxBitRate 443289600 dwMaxVideoFrameBufferSize 615680 dwDefaultFrameInterval 111111 bFrameIntervalType 1 dwFrameInterval( 0) 111111 Skip duplicate dimensions in enum_framesizes, let enum_frameintervals list the intervals from both frame descriptors. Change set_streamparm to switch to the correct frame index when changing the interval. This enables 90 fps capture on a Lenovo Explorer Windows Mixed Reality headset. [laurent.pinchart@ideasonboard.com: Renamed tmp_ival to ival] Signed-off-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 71 +++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index a13ad4e178be..5ff6ca1fad2d 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, { struct uvc_streaming_control probe; struct v4l2_fract timeperframe; - uint32_t interval; + struct uvc_format *format; + struct uvc_frame *frame; + __u32 interval, maxd; + unsigned int i; int ret; if (parm->type != stream->type) @@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, return -EBUSY; } + format = stream->cur_format; + frame = stream->cur_frame; probe = stream->ctrl; - probe.dwFrameInterval = - uvc_try_frame_interval(stream->cur_frame, interval); + probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); + maxd = abs((__s32)probe.dwFrameInterval - interval); + + /* Try frames with matching size to find the best frame interval. */ + for (i = 0; i < format->nframes && maxd != 0; i++) { + __u32 d, ival; + + if (&format->frame[i] == stream->cur_frame) + continue; + + if (format->frame[i].wWidth != stream->cur_frame->wWidth || + format->frame[i].wHeight != stream->cur_frame->wHeight) + continue; + + ival = uvc_try_frame_interval(&format->frame[i], interval); + d = abs((__s32)ival - interval); + if (d >= maxd) + continue; + + frame = &format->frame[i]; + probe.bFrameIndex = frame->bFrameIndex; + probe.dwFrameInterval = ival; + maxd = d; + } /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); @@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, } stream->ctrl = probe; + stream->cur_frame = frame; mutex_unlock(&stream->mutex); /* Return the actual frame period. */ @@ -1146,7 +1174,8 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, struct uvc_streaming *stream = handle->stream; struct uvc_format *format = NULL; struct uvc_frame *frame; - int i; + unsigned int index; + unsigned int i; /* Look for the given pixel format */ for (i = 0; i < stream->nformats; i++) { @@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, if (format == NULL) return -EINVAL; - if (fsize->index >= format->nframes) + /* Skip duplicate frame sizes */ + for (i = 0, index = 0; i < format->nframes; i++) { + if (i && frame->wWidth == format->frame[i].wWidth && + frame->wHeight == format->frame[i].wHeight) + continue; + frame = &format->frame[i]; + if (index == fsize->index) + break; + index++; + } + + if (i == format->nframes) return -EINVAL; - frame = &format->frame[fsize->index]; fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = frame->wWidth; fsize->discrete.height = frame->wHeight; @@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, struct uvc_streaming *stream = handle->stream; struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; - int i; + unsigned int nintervals; + unsigned int index; + unsigned int i; /* Look for the given pixel format and frame size */ for (i = 0; i < stream->nformats; i++) { @@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, if (format == NULL) return -EINVAL; + index = fival->index; for (i = 0; i < format->nframes; i++) { if (format->frame[i].wWidth == fival->width && format->frame[i].wHeight == fival->height) { frame = &format->frame[i]; - break; + nintervals = frame->bFrameIntervalType ?: 1; + if (index < nintervals) + break; + index -= nintervals; } } - if (frame == NULL) + if (i == format->nframes) return -EINVAL; if (frame->bFrameIntervalType) { - if (fival->index >= frame->bFrameIntervalType) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete.numerator = - frame->dwFrameInterval[fival->index]; + frame->dwFrameInterval[index]; fival->discrete.denominator = 10000000; uvc_simplify_fraction(&fival->discrete.numerator, &fival->discrete.denominator, 8, 333); } else { - if (fival->index) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; fival->stepwise.min.numerator = frame->dwFrameInterval[0]; fival->stepwise.min.denominator = 10000000; -- cgit From cb9cd6c5c30b6032507aadde5d5d71221b19c3d7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Jan 2018 12:32:54 -0500 Subject: media: uvcvideo: Drop extern keyword in function declarations The extern keyword isn't needed to declare functions in header files. Drop it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvcvideo.h | 144 +++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 74 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index d9e7c70788d0..5e71160eea91 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -667,40 +667,38 @@ extern unsigned int uvc_hw_timestamps_param; /* Core driver */ extern struct uvc_driver uvc_driver; -extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); +struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -extern int uvc_queue_init(struct uvc_video_queue *queue, - enum v4l2_buf_type type, int drop_corrupted); -extern void uvc_queue_release(struct uvc_video_queue *queue); -extern int uvc_request_buffers(struct uvc_video_queue *queue, - struct v4l2_requestbuffers *rb); -extern int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_create_buffers(struct uvc_video_queue *queue, - struct v4l2_create_buffers *v4l2_cb); -extern int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf); -extern int uvc_export_buffer(struct uvc_video_queue *queue, - struct v4l2_exportbuffer *exp); -extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking); -extern int uvc_queue_streamon(struct uvc_video_queue *queue, - enum v4l2_buf_type type); -extern int uvc_queue_streamoff(struct uvc_video_queue *queue, - enum v4l2_buf_type type); -extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); -extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, - struct uvc_buffer *buf); -extern int uvc_queue_mmap(struct uvc_video_queue *queue, - struct vm_area_struct *vma); -extern __poll_t uvc_queue_poll(struct uvc_video_queue *queue, - struct file *file, poll_table *wait); +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + int drop_corrupted); +void uvc_queue_release(struct uvc_video_queue *queue); +int uvc_request_buffers(struct uvc_video_queue *queue, + struct v4l2_requestbuffers *rb); +int uvc_query_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf); +int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *v4l2_cb); +int uvc_queue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf); +int uvc_export_buffer(struct uvc_video_queue *queue, + struct v4l2_exportbuffer *exp); +int uvc_dequeue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *v4l2_buf, int nonblocking); +int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type); +int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); +void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); +struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, + struct uvc_buffer *buf); +int uvc_queue_mmap(struct uvc_video_queue *queue, + struct vm_area_struct *vma); +__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, + poll_table *wait); #ifndef CONFIG_MMU -extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, - unsigned long pgoff); +unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, + unsigned long pgoff); #endif -extern int uvc_queue_allocated(struct uvc_video_queue *queue); +int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return vb2_is_streaming(&queue->queue); @@ -711,18 +709,18 @@ extern const struct v4l2_ioctl_ops uvc_ioctl_ops; extern const struct v4l2_file_operations uvc_fops; /* Media controller */ -extern int uvc_mc_register_entities(struct uvc_video_chain *chain); -extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); +int uvc_mc_register_entities(struct uvc_video_chain *chain); +void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ -extern int uvc_video_init(struct uvc_streaming *stream); -extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream, int reset); -extern int uvc_video_enable(struct uvc_streaming *stream, int enable); -extern int uvc_probe_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe); -extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size); +int uvc_video_init(struct uvc_streaming *stream); +int uvc_video_suspend(struct uvc_streaming *stream); +int uvc_video_resume(struct uvc_streaming *stream, int reset); +int uvc_video_enable(struct uvc_streaming *stream, int enable); +int uvc_probe_video(struct uvc_streaming *stream, + struct uvc_streaming_control *probe); +int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, + __u8 intfnum, __u8 cs, void *data, __u16 size); void uvc_video_clock_update(struct uvc_streaming *stream, struct vb2_v4l2_buffer *vbuf, struct uvc_buffer *buf); @@ -737,32 +735,32 @@ int uvc_register_video_device(struct uvc_device *dev, const struct v4l2_ioctl_ops *ioctl_ops); /* Status */ -extern int uvc_status_init(struct uvc_device *dev); -extern void uvc_status_cleanup(struct uvc_device *dev); -extern int uvc_status_start(struct uvc_device *dev, gfp_t flags); -extern void uvc_status_stop(struct uvc_device *dev); +int uvc_status_init(struct uvc_device *dev); +void uvc_status_cleanup(struct uvc_device *dev); +int uvc_status_start(struct uvc_device *dev, gfp_t flags); +void uvc_status_stop(struct uvc_device *dev); /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; -extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, - struct v4l2_queryctrl *v4l2_ctrl); -extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu); - -extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, - const struct uvc_control_mapping *mapping); -extern int uvc_ctrl_init_device(struct uvc_device *dev); -extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); -extern int uvc_ctrl_restore_values(struct uvc_device *dev); - -extern int uvc_ctrl_begin(struct uvc_video_chain *chain); -extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count); +int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, + struct v4l2_queryctrl *v4l2_ctrl); +int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu); + +int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, + const struct uvc_control_mapping *mapping); +int uvc_ctrl_init_device(struct uvc_device *dev); +void uvc_ctrl_cleanup_device(struct uvc_device *dev); +int uvc_ctrl_restore_values(struct uvc_device *dev); + +int uvc_ctrl_begin(struct uvc_video_chain *chain); +int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count); static inline int uvc_ctrl_commit(struct uvc_fh *handle, - const struct v4l2_ext_control *xctrls, - unsigned int xctrls_count) + const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count) { return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count); } @@ -771,25 +769,23 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) return __uvc_ctrl_commit(handle, 1, NULL, 0); } -extern int uvc_ctrl_get(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); -extern int uvc_ctrl_set(struct uvc_video_chain *chain, - struct v4l2_ext_control *xctrl); +int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); +int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, - struct uvc_xu_control_query *xqry); +int uvc_xu_ctrl_query(struct uvc_video_chain *chain, + struct uvc_xu_control_query *xqry); /* Utility functions */ -extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, - unsigned int n_terms, unsigned int threshold); -extern uint32_t uvc_fraction_to_interval(uint32_t numerator, - uint32_t denominator); -extern struct usb_host_endpoint *uvc_find_endpoint( - struct usb_host_interface *alts, __u8 epaddr); +void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, + unsigned int n_terms, unsigned int threshold); +uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator); +struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, + __u8 epaddr); /* Quirks support */ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf, struct uvc_buffer *meta_buf); + struct uvc_buffer *buf, + struct uvc_buffer *meta_buf); /* debugfs and statistics */ void uvc_debugfs_init(void); -- cgit From 1e304c47ef12d442ef02d94bdbaed8b1f0adec3c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Jan 2018 12:35:17 -0500 Subject: media: uvcvideo: Use kernel integer types Replace the uint_{8,16,32} types with the corresponding native kernel types u{8,16,32}. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 16 ++++++++-------- drivers/media/usb/uvc/uvc_v4l2.c | 2 +- drivers/media/usb/uvc/uvcvideo.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index fd387bf3f02d..56d906dd7044 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -267,11 +267,11 @@ static __u32 uvc_colorspace(const __u8 primaries) * continued fraction decomposition. Using 8 and 333 for n_terms and threshold * respectively seems to give nice results. */ -void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, +void uvc_simplify_fraction(u32 *numerator, u32 *denominator, unsigned int n_terms, unsigned int threshold) { - uint32_t *an; - uint32_t x, y, r; + u32 *an; + u32 x, y, r; unsigned int i, n; an = kmalloc(n_terms * sizeof *an, GFP_KERNEL); @@ -318,21 +318,21 @@ void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, * to compute numerator / denominator * 10000000 using 32 bit fixed point * arithmetic only. */ -uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) +u32 uvc_fraction_to_interval(u32 numerator, u32 denominator) { - uint32_t multiplier; + u32 multiplier; /* Saturate the result if the operation would overflow. */ if (denominator == 0 || - numerator/denominator >= ((uint32_t)-1)/10000000) - return (uint32_t)-1; + numerator/denominator >= ((u32)-1)/10000000) + return (u32)-1; /* Divide both the denominator and the multiplier by two until * numerator * multiplier doesn't overflow. If anyone knows a better * algorithm please let me know. */ multiplier = 10000000; - while (numerator > ((uint32_t)-1)/multiplier) { + while (numerator > ((u32)-1)/multiplier) { multiplier /= 2; denominator /= 2; } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 5ff6ca1fad2d..ed6dcef3debc 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -336,7 +336,7 @@ done: static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { - uint32_t numerator, denominator; + u32 numerator, denominator; if (parm->type != stream->type) return -EINVAL; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 5e71160eea91..247a06dd098b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -776,9 +776,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry); /* Utility functions */ -void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, +void uvc_simplify_fraction(u32 *numerator, u32 *denominator, unsigned int n_terms, unsigned int threshold); -uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator); +u32 uvc_fraction_to_interval(u32 numerator, u32 denominator); struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, __u8 epaddr); -- cgit From 2c6b222cee2d68e30f059b8ca9194532416bb3f4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Jan 2018 12:45:36 -0500 Subject: media: uvcvideo: Use internal kernel integer types Replace the __[su]{8,16,32} variant of integer types with the non-underscored types as the code is internal to the driver, not exposed to userspace. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 56 ++++++------ drivers/media/usb/uvc/uvc_driver.c | 36 ++++---- drivers/media/usb/uvc/uvc_isight.c | 6 +- drivers/media/usb/uvc/uvc_status.c | 4 +- drivers/media/usb/uvc/uvc_v4l2.c | 62 ++++++------- drivers/media/usb/uvc/uvc_video.c | 40 ++++---- drivers/media/usb/uvc/uvcvideo.h | 182 ++++++++++++++++++------------------- 7 files changed, 193 insertions(+), 193 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 586f0e94061b..723c517474fc 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -366,10 +366,10 @@ static struct uvc_menu_info exposure_auto_controls[] = { { 8, "Aperture Priority Mode" }, }; -static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { - __s8 zoom = (__s8)data[0]; + s8 zoom = (s8)data[0]; switch (query) { case UVC_GET_CUR: @@ -385,17 +385,17 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, } static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; data[2] = min((int)abs(value), 0xff); } -static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { unsigned int first = mapping->offset / 8; - __s8 rel = (__s8)data[first]; + s8 rel = (s8)data[first]; switch (query) { case UVC_GET_CUR: @@ -412,7 +412,7 @@ static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, } static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { unsigned int first = mapping->offset / 8; @@ -745,17 +745,17 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { * Utility functions */ -static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) +static inline u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) { return ctrl->uvc_data + id * ctrl->info.size; } -static inline int uvc_test_bit(const __u8 *data, int bit) +static inline int uvc_test_bit(const u8 *data, int bit) { return (data[bit >> 3] >> (bit & 7)) & 1; } -static inline void uvc_clear_bit(__u8 *data, int bit) +static inline void uvc_clear_bit(u8 *data, int bit) { data[bit >> 3] &= ~(1 << (bit & 7)); } @@ -765,20 +765,20 @@ static inline void uvc_clear_bit(__u8 *data, int bit) * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */ -static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, - __u8 query, const __u8 *data) +static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, + u8 query, const u8 *data) { int bits = mapping->size; int offset = mapping->offset; - __s32 value = 0; - __u8 mask; + s32 value = 0; + u8 mask; data += offset / 8; offset &= 7; mask = ((1LL << bits) - 1) << offset; for (; bits > 0; data++) { - __u8 byte = *data & mask; + u8 byte = *data & mask; value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); bits -= 8 - (offset > 0 ? offset : 0); offset -= 8; @@ -796,11 +796,11 @@ static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, * in the little-endian data stored at 'data' to the value 'value'. */ static void uvc_set_le_value(struct uvc_control_mapping *mapping, - __s32 value, __u8 *data) + s32 value, u8 *data) { int bits = mapping->size; int offset = mapping->offset; - __u8 mask; + u8 mask; /* According to the v4l2 spec, writing any value to a button control * should result in the action belonging to the button control being @@ -826,13 +826,13 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, * Terminal and unit management */ -static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; -static const __u8 uvc_media_transport_input_guid[16] = +static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; +static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; +static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static int uvc_entity_match_guid(const struct uvc_entity *entity, - const __u8 guid[16]) + const u8 guid[16]) { switch (UVC_ENTITY_TYPE(entity)) { case UVC_ITT_CAMERA: @@ -857,7 +857,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity, * UVC Controls */ -static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, +static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, struct uvc_control_mapping **mapping, struct uvc_control **control, int next) { @@ -890,7 +890,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, } static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, - __u32 v4l2_id, struct uvc_control_mapping **mapping) + u32 v4l2_id, struct uvc_control_mapping **mapping) { struct uvc_control *ctrl = NULL; struct uvc_entity *entity; @@ -1742,9 +1742,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_entity *entity; struct uvc_control *ctrl; unsigned int i, found = 0; - __u32 reqflags; - __u16 size; - __u8 *data = NULL; + u32 reqflags; + u16 size; + u8 *data = NULL; int ret; /* Find the extension unit. */ @@ -2176,7 +2176,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) list_for_each_entry(entity, &dev->entities, list) { struct uvc_control *ctrl; unsigned int bControlSize = 0, ncontrols; - __u8 *bmControls = NULL; + u8 *bmControls = NULL; if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { bmControls = entity->extension.bmControls; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 56d906dd7044..718c3fcde287 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -216,7 +216,7 @@ static struct uvc_format_desc uvc_fmts[] = { */ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, - __u8 epaddr) + u8 epaddr) { struct usb_host_endpoint *ep; unsigned int i; @@ -230,7 +230,7 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, return NULL; } -static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16]) +static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) { unsigned int len = ARRAY_SIZE(uvc_fmts); unsigned int i; @@ -243,9 +243,9 @@ static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16]) return NULL; } -static __u32 uvc_colorspace(const __u8 primaries) +static u32 uvc_colorspace(const u8 primaries) { - static const __u8 colorprimaries[] = { + static const u8 colorprimaries[] = { 0, V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_470_SYSTEM_M, @@ -391,7 +391,7 @@ static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) static int uvc_parse_format(struct uvc_device *dev, struct uvc_streaming *streaming, struct uvc_format *format, - __u32 **intervals, unsigned char *buffer, int buflen) + u32 **intervals, unsigned char *buffer, int buflen) { struct usb_interface *intf = streaming->intf; struct usb_host_interface *alts = intf->cur_altsetting; @@ -401,7 +401,7 @@ static int uvc_parse_format(struct uvc_device *dev, unsigned int width_multiplier = 1; unsigned int interval; unsigned int i, n; - __u8 ftype; + u8 ftype; format->type = buffer[2]; format->index = buffer[3]; @@ -658,8 +658,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, int _buflen, buflen = alts->extralen; unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; - __u32 *interval; - __u16 psize; + u32 *interval; + u16 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -836,7 +836,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, } frame = (struct uvc_frame *)&format[nformats]; - interval = (__u32 *)&frame[nframes]; + interval = (u32 *)&frame[nframes]; streaming->format = format; streaming->nformats = nformats; @@ -930,7 +930,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; entity->bNrInPins = num_inputs; - entity->baSourceID = (__u8 *)(&entity->pads[num_pads]); + entity->baSourceID = (u8 *)(&entity->pads[num_pads]); return entity; } @@ -995,8 +995,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof(*unit); - unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit) + unit->extension.bmControls = (u8 *)unit + sizeof(*unit); + unit->extension.bmControlsType = (u8 *)unit + sizeof(*unit) + n; memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); @@ -1022,7 +1022,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, struct usb_interface *intf; struct usb_host_interface *alts = dev->intf->cur_altsetting; unsigned int i, n, p, len; - __u16 type; + u16 type; switch (buffer[2]) { case UVC_VC_HEADER: @@ -1101,7 +1101,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; - term->camera.bmControls = (__u8 *)term + sizeof *term; + term->camera.bmControls = (u8 *)term + sizeof *term; term->camera.wObjectiveFocalLengthMin = get_unaligned_le16(&buffer[8]); term->camera.wObjectiveFocalLengthMax = @@ -1112,9 +1112,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, } else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) { term->media.bControlSize = n; - term->media.bmControls = (__u8 *)term + sizeof *term; + term->media.bmControls = (u8 *)term + sizeof *term; term->media.bTransportModeSize = p; - term->media.bmTransportModes = (__u8 *)term + term->media.bmTransportModes = (u8 *)term + sizeof *term + n; memcpy(term->media.bmControls, &buffer[9], n); memcpy(term->media.bmTransportModes, &buffer[10+n], p); @@ -1213,7 +1213,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->processing.wMaxMultiplier = get_unaligned_le16(&buffer[5]); unit->processing.bControlSize = buffer[7]; - unit->processing.bmControls = (__u8 *)unit + sizeof *unit; + unit->processing.bmControls = (u8 *)unit + sizeof *unit; memcpy(unit->processing.bmControls, &buffer[8], n); if (dev->uvc_version >= 0x0110) unit->processing.bmVideoStandards = buffer[9+n]; @@ -1246,7 +1246,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (__u8 *)unit + sizeof *unit; + unit->extension.bmControls = (u8 *)unit + sizeof *unit; memcpy(unit->extension.bmControls, &buffer[23+p], n); if (buffer[23+p+n] != 0) diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c index 5059fbf41020..81e6f2187bfb 100644 --- a/drivers/media/usb/uvc/uvc_isight.c +++ b/drivers/media/usb/uvc/uvc_isight.c @@ -37,16 +37,16 @@ */ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, - const __u8 *data, unsigned int len) + const u8 *data, unsigned int len) { - static const __u8 hdr[] = { + static const u8 hdr[] = { 0x11, 0x22, 0x33, 0x44, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xfa, 0xce }; unsigned int maxlen, nbytes; - __u8 *mem; + u8 *mem; int is_header = 0; if (buf == NULL) diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 1ef20e74b7ac..7b710410584a 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -78,7 +78,7 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, /* -------------------------------------------------------------------------- * Status interrupt endpoint */ -static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) +static void uvc_event_streaming(struct uvc_device *dev, u8 *data, int len) { if (len < 3) { uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " @@ -99,7 +99,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) } } -static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len) +static void uvc_event_control(struct uvc_device *dev, u8 *data, int len) { char *attrs[3] = { "value", "info", "failure" }; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index ed6dcef3debc..5e1bfdc5b829 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -105,12 +105,12 @@ free_map: * the Video Probe and Commit negotiation, but some hardware don't implement * that feature. */ -static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) +static u32 uvc_try_frame_interval(struct uvc_frame *frame, u32 interval) { unsigned int i; if (frame->bFrameIntervalType) { - __u32 best = -1, dist; + u32 best = -1, dist; for (i = 0; i < frame->bFrameIntervalType; ++i) { dist = interval > frame->dwFrameInterval[i] @@ -125,9 +125,9 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) interval = frame->dwFrameInterval[i-1]; } else { - const __u32 min = frame->dwFrameInterval[0]; - const __u32 max = frame->dwFrameInterval[1]; - const __u32 step = frame->dwFrameInterval[2]; + const u32 min = frame->dwFrameInterval[0]; + const u32 max = frame->dwFrameInterval[1]; + const u32 step = frame->dwFrameInterval[2]; interval = min + (interval - min + step/2) / step * step; if (interval > max) @@ -137,7 +137,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) return interval; } -static __u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, +static u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, const struct uvc_frame *frame) { switch (format->fcc) { @@ -158,17 +158,17 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, { struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; - __u16 rw, rh; + u16 rw, rh; unsigned int d, maxd; unsigned int i; - __u32 interval; + u32 interval; int ret = 0; - __u8 *fcc; + u8 *fcc; if (fmt->type != stream->type) return -EINVAL; - fcc = (__u8 *)&fmt->fmt.pix.pixelformat; + fcc = (u8 *)&fmt->fmt.pix.pixelformat; uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n", fmt->fmt.pix.pixelformat, fcc[0], fcc[1], fcc[2], fcc[3], @@ -197,8 +197,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, maxd = (unsigned int)-1; for (i = 0; i < format->nframes; ++i) { - __u16 w = format->frame[i].wWidth; - __u16 h = format->frame[i].wHeight; + u16 w = format->frame[i].wWidth; + u16 h = format->frame[i].wHeight; d = min(w, rw) * min(h, rh); d = w*h + rw*rh - 2*d; @@ -375,7 +375,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, struct v4l2_fract timeperframe; struct uvc_format *format; struct uvc_frame *frame; - __u32 interval, maxd; + u32 interval, maxd; unsigned int i; int ret; @@ -403,11 +403,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, frame = stream->cur_frame; probe = stream->ctrl; probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); - maxd = abs((__s32)probe.dwFrameInterval - interval); + maxd = abs((s32)probe.dwFrameInterval - interval); /* Try frames with matching size to find the best frame interval. */ for (i = 0; i < format->nframes && maxd != 0; i++) { - __u32 d, ival; + u32 d, ival; if (&format->frame[i] == stream->cur_frame) continue; @@ -417,7 +417,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, continue; ival = uvc_try_frame_interval(&format->frame[i], interval); - d = abs((__s32)ival - interval); + d = abs((s32)ival - interval); if (d >= maxd) continue; @@ -605,7 +605,7 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, { struct uvc_format *format; enum v4l2_buf_type type = fmt->type; - __u32 index = fmt->index; + u32 index = fmt->index; if (fmt->type != stream->type || fmt->index >= stream->nformats) return -EINVAL; @@ -1300,20 +1300,20 @@ static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, #ifdef CONFIG_COMPAT struct uvc_xu_control_mapping32 { - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; + u32 id; + u8 name[32]; + u8 entity[16]; + u8 selector; - __u8 size; - __u8 offset; - __u32 v4l2_type; - __u32 data_type; + u8 size; + u8 offset; + u32 v4l2_type; + u32 data_type; compat_caddr_t menu_info; - __u32 menu_count; + u32 menu_count; - __u32 reserved[4]; + u32 reserved[4]; }; static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, @@ -1349,10 +1349,10 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, } struct uvc_xu_control_query32 { - __u8 unit; - __u8 selector; - __u8 query; - __u16 size; + u8 unit; + u8 selector; + u8 query; + u16 size; compat_caddr_t data; }; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 5441553f74e1..dfe13c55a067 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -30,11 +30,11 @@ * UVC Controls */ -static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size, +static int __uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size, int timeout) { - __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; unsigned int pipe; pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) @@ -45,7 +45,7 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, unit << 8 | intfnum, data, size, timeout); } -static const char *uvc_query_name(__u8 query) +static const char *uvc_query_name(u8 query) { switch (query) { case UVC_SET_CUR: @@ -69,8 +69,8 @@ static const char *uvc_query_name(__u8 query) } } -int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size) +int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size) { int ret; @@ -164,10 +164,10 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, } static int uvc_get_video_ctrl(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl, int probe, __u8 query) + struct uvc_streaming_control *ctrl, int probe, u8 query) { - __u8 *data; - __u16 size; + u8 *data; + u16 size; int ret; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; @@ -254,8 +254,8 @@ out: static int uvc_set_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe) { - __u8 *data; - __u16 size; + u8 *data; + u16 size; int ret; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; @@ -301,7 +301,7 @@ int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe) { struct uvc_streaming_control probe_min, probe_max; - __u16 bandwidth; + u16 bandwidth; unsigned int i; int ret; @@ -379,7 +379,7 @@ static inline ktime_t uvc_video_get_time(void) static void uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, - const __u8 *data, int len) + const u8 *data, int len) { struct uvc_clock_sample *sample; unsigned int header_size; @@ -705,7 +705,7 @@ done: */ static void uvc_video_stats_decode(struct uvc_streaming *stream, - const __u8 *data, int len) + const u8 *data, int len) { unsigned int header_size; bool has_pts = false; @@ -946,9 +946,9 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream) * uvc_video_decode_end will never be called with a NULL buffer. */ static int uvc_video_decode_start(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { - __u8 fid; + u8 fid; /* Sanity checks: * - packet must be at least 2 bytes long @@ -1043,7 +1043,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, } static void uvc_video_decode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { unsigned int maxlen, nbytes; void *mem; @@ -1067,7 +1067,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, } static void uvc_video_decode_end(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { /* Mark the buffer as done if the EOF marker is set. */ if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { @@ -1092,7 +1092,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, * video buffer to the transfer buffer. */ static int uvc_video_encode_header(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) + struct uvc_buffer *buf, u8 *data, int len) { data[0] = 2; /* Header length */ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF @@ -1101,7 +1101,7 @@ static int uvc_video_encode_header(struct uvc_streaming *stream, } static int uvc_video_encode_data(struct uvc_streaming *stream, - struct uvc_buffer *buf, __u8 *data, int len) + struct uvc_buffer *buf, u8 *data, int len) { struct uvc_video_queue *queue = &stream->queue; unsigned int nbytes; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 247a06dd098b..be5cf179228b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -208,60 +208,60 @@ struct uvc_device; struct uvc_control_info { struct list_head mappings; - __u8 entity[16]; - __u8 index; /* Bit index in bmControls */ - __u8 selector; + u8 entity[16]; + u8 index; /* Bit index in bmControls */ + u8 selector; - __u16 size; - __u32 flags; + u16 size; + u32 flags; }; struct uvc_control_mapping { struct list_head list; struct list_head ev_subs; - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; + u32 id; + u8 name[32]; + u8 entity[16]; + u8 selector; - __u8 size; - __u8 offset; + u8 size; + u8 offset; enum v4l2_ctrl_type v4l2_type; - __u32 data_type; + u32 data_type; struct uvc_menu_info *menu_info; - __u32 menu_count; + u32 menu_count; - __u32 master_id; - __s32 master_manual; - __u32 slave_ids[2]; + u32 master_id; + s32 master_manual; + u32 slave_ids[2]; - __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query, - const __u8 *data); - void (*set) (struct uvc_control_mapping *mapping, __s32 value, - __u8 *data); + s32 (*get)(struct uvc_control_mapping *mapping, u8 query, + const u8 *data); + void (*set)(struct uvc_control_mapping *mapping, s32 value, + u8 *data); }; struct uvc_control { struct uvc_entity *entity; struct uvc_control_info info; - __u8 index; /* Used to match the uvc_control entry with a + u8 index; /* Used to match the uvc_control entry with a uvc_control_info. */ - __u8 dirty:1, - loaded:1, - modified:1, - cached:1, - initialized:1; + u8 dirty:1, + loaded:1, + modified:1, + cached:1, + initialized:1; - __u8 *uvc_data; + u8 *uvc_data; }; struct uvc_format_desc { char *name; - __u8 guid[16]; - __u32 fcc; + u8 guid[16]; + u32 fcc; }; /* The term 'entity' refers to both UVC units and UVC terminals. @@ -287,8 +287,8 @@ struct uvc_entity { * chain. */ unsigned int flags; - __u8 id; - __u16 type; + u8 id; + u16 type; char name[64]; /* Media controller-related fields. */ @@ -300,69 +300,69 @@ struct uvc_entity { union { struct { - __u16 wObjectiveFocalLengthMin; - __u16 wObjectiveFocalLengthMax; - __u16 wOcularFocalLength; - __u8 bControlSize; - __u8 *bmControls; + u16 wObjectiveFocalLengthMin; + u16 wObjectiveFocalLengthMax; + u16 wOcularFocalLength; + u8 bControlSize; + u8 *bmControls; } camera; struct { - __u8 bControlSize; - __u8 *bmControls; - __u8 bTransportModeSize; - __u8 *bmTransportModes; + u8 bControlSize; + u8 *bmControls; + u8 bTransportModeSize; + u8 *bmTransportModes; } media; struct { } output; struct { - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 *bmControls; - __u8 bmVideoStandards; + u16 wMaxMultiplier; + u8 bControlSize; + u8 *bmControls; + u8 bmVideoStandards; } processing; struct { } selector; struct { - __u8 guidExtensionCode[16]; - __u8 bNumControls; - __u8 bControlSize; - __u8 *bmControls; - __u8 *bmControlsType; + u8 guidExtensionCode[16]; + u8 bNumControls; + u8 bControlSize; + u8 *bmControls; + u8 *bmControlsType; } extension; }; - __u8 bNrInPins; - __u8 *baSourceID; + u8 bNrInPins; + u8 *baSourceID; unsigned int ncontrols; struct uvc_control *controls; }; struct uvc_frame { - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u8 bFrameIntervalType; - __u32 dwDefaultFrameInterval; - __u32 *dwFrameInterval; + u8 bFrameIndex; + u8 bmCapabilities; + u16 wWidth; + u16 wHeight; + u32 dwMinBitRate; + u32 dwMaxBitRate; + u32 dwMaxVideoFrameBufferSize; + u8 bFrameIntervalType; + u32 dwDefaultFrameInterval; + u32 *dwFrameInterval; }; struct uvc_format { - __u8 type; - __u8 index; - __u8 bpp; - __u8 colorspace; - __u32 fcc; - __u32 flags; + u8 type; + u8 index; + u8 bpp; + u8 colorspace; + u32 fcc; + u32 flags; char name[32]; @@ -371,16 +371,16 @@ struct uvc_format { }; struct uvc_streaming_header { - __u8 bNumFormats; - __u8 bEndpointAddress; - __u8 bTerminalLink; - __u8 bControlSize; - __u8 *bmaControls; + u8 bNumFormats; + u8 bEndpointAddress; + u8 bTerminalLink; + u8 bControlSize; + u8 *bmaControls; /* The following fields are used by input headers only. */ - __u8 bmInfo; - __u8 bStillCaptureMethod; - __u8 bTriggerSupport; - __u8 bTriggerUsage; + u8 bmInfo; + u8 bStillCaptureMethod; + u8 bTriggerSupport; + u8 bTriggerUsage; }; enum uvc_buffer_state { @@ -490,7 +490,7 @@ struct uvc_streaming { struct usb_interface *intf; int intfnum; - __u16 maxpsize; + u16 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; @@ -517,16 +517,16 @@ struct uvc_streaming { struct { struct video_device vdev; struct uvc_video_queue queue; - __u32 format; + u32 format; } meta; /* Context data used by the bulk completion handler. */ struct { - __u8 header[256]; + u8 header[256]; unsigned int header_size; int skip_payload; - __u32 payload_size; - __u32 max_payload_size; + u32 payload_size; + u32 max_payload_size; } bulk; struct urb *urb[UVC_URBS]; @@ -534,8 +534,8 @@ struct uvc_streaming { dma_addr_t urb_dma[UVC_URBS]; unsigned int urb_size; - __u32 sequence; - __u8 last_fid; + u32 sequence; + u8 last_fid; /* debugfs */ struct dentry *debugfs_dir; @@ -570,8 +570,8 @@ struct uvc_device { struct usb_device *udev; struct usb_interface *intf; unsigned long warnings; - __u32 quirks; - __u32 meta_format; + u32 quirks; + u32 meta_format; int intfnum; char name[32]; @@ -584,8 +584,8 @@ struct uvc_device { struct media_device mdev; #endif struct v4l2_device vdev; - __u16 uvc_version; - __u32 clock_frequency; + u16 uvc_version; + u32 clock_frequency; struct list_head entities; struct list_head chains; @@ -597,7 +597,7 @@ struct uvc_device { /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; - __u8 *status; + u8 *status; struct input_dev *input; char input_phys[64]; }; @@ -719,8 +719,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset); int uvc_video_enable(struct uvc_streaming *stream, int enable); int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size); +int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, + u8 intfnum, u8 cs, void *data, u16 size); void uvc_video_clock_update(struct uvc_streaming *stream, struct vb2_v4l2_buffer *vbuf, struct uvc_buffer *buf); @@ -780,7 +780,7 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator, unsigned int n_terms, unsigned int threshold); u32 uvc_fraction_to_interval(u32 numerator, u32 denominator); struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, - __u8 epaddr); + u8 epaddr); /* Quirks support */ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, -- cgit From f14d4988c28e5243e43ba792ee34994951240b0f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Jan 2018 12:45:36 -0500 Subject: media: uvcvideo: Use parentheses around sizeof operand While the sizeof is an operator and not a function, the preferred coding style in the kernel is to enclose its operand in parentheses. To avoid mixing multiple coding styles in the driver, use parentheses around all sizeof operands. While at it replace a kmalloc() with a kmalloc_array() to silence a checkpatch warning triggered by this patch. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 6 ++--- drivers/media/usb/uvc/uvc_driver.c | 53 +++++++++++++++++++------------------- drivers/media/usb/uvc/uvc_v4l2.c | 12 ++++----- drivers/media/usb/uvc/uvc_video.c | 2 +- 4 files changed, 37 insertions(+), 36 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 723c517474fc..102594ec3e97 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1019,10 +1019,10 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct uvc_menu_info *menu; unsigned int i; - memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; - strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); + strlcpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name)); v4l2_ctrl->flags = 0; if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) @@ -1182,7 +1182,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, } } - strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); + strlcpy(query_menu->name, menu_info->name, sizeof(query_menu->name)); done: mutex_unlock(&chain->ctrl_mutex); diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 718c3fcde287..2469b49b2b30 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -274,7 +274,7 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator, u32 x, y, r; unsigned int i, n; - an = kmalloc(n_terms * sizeof *an, GFP_KERNEL); + an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL); if (an == NULL) return; @@ -423,7 +423,7 @@ static int uvc_parse_format(struct uvc_device *dev, if (fmtdesc != NULL) { strlcpy(format->name, fmtdesc->name, - sizeof format->name); + sizeof(format->name)); format->fcc = fmtdesc->fcc; } else { uvc_printk(KERN_INFO, "Unknown video format %pUl\n", @@ -466,7 +466,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strlcpy(format->name, "MJPEG", sizeof format->name); + strlcpy(format->name, "MJPEG", sizeof(format->name)); format->fcc = V4L2_PIX_FMT_MJPEG; format->flags = UVC_FMT_FLAG_COMPRESSED; format->bpp = 0; @@ -484,13 +484,13 @@ static int uvc_parse_format(struct uvc_device *dev, switch (buffer[8] & 0x7f) { case 0: - strlcpy(format->name, "SD-DV", sizeof format->name); + strlcpy(format->name, "SD-DV", sizeof(format->name)); break; case 1: - strlcpy(format->name, "SDL-DV", sizeof format->name); + strlcpy(format->name, "SDL-DV", sizeof(format->name)); break; case 2: - strlcpy(format->name, "HD-DV", sizeof format->name); + strlcpy(format->name, "HD-DV", sizeof(format->name)); break; default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " @@ -501,7 +501,7 @@ static int uvc_parse_format(struct uvc_device *dev, } strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", - sizeof format->name); + sizeof(format->name)); format->fcc = V4L2_PIX_FMT_DV; format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; @@ -510,7 +510,7 @@ static int uvc_parse_format(struct uvc_device *dev, /* Create a dummy frame descriptor. */ frame = &format->frame[0]; - memset(&format->frame[0], 0, sizeof format->frame[0]); + memset(&format->frame[0], 0, sizeof(format->frame[0])); frame->bFrameIntervalType = 1; frame->dwDefaultFrameInterval = 1; frame->dwFrameInterval = *intervals; @@ -677,7 +677,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, return -EINVAL; } - streaming = kzalloc(sizeof *streaming, GFP_KERNEL); + streaming = kzalloc(sizeof(*streaming), GFP_KERNEL); if (streaming == NULL) { usb_driver_release_interface(&uvc_driver.driver, intf); return -EINVAL; @@ -827,8 +827,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, goto error; } - size = nformats * sizeof *format + nframes * sizeof *frame - + nintervals * sizeof *interval; + size = nformats * sizeof(*format) + nframes * sizeof(*frame) + + nintervals * sizeof(*interval); format = kzalloc(size, GFP_KERNEL); if (format == NULL) { ret = -ENOMEM; @@ -1002,7 +1002,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, if (buffer[24+p+2*n] != 0) usb_string(udev, buffer[24+p+2*n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Extension %u", buffer[3]); @@ -1101,7 +1101,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; - term->camera.bmControls = (u8 *)term + sizeof *term; + term->camera.bmControls = (u8 *)term + sizeof(*term); term->camera.wObjectiveFocalLengthMin = get_unaligned_le16(&buffer[8]); term->camera.wObjectiveFocalLengthMax = @@ -1112,17 +1112,17 @@ static int uvc_parse_standard_control(struct uvc_device *dev, } else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) { term->media.bControlSize = n; - term->media.bmControls = (u8 *)term + sizeof *term; + term->media.bmControls = (u8 *)term + sizeof(*term); term->media.bTransportModeSize = p; term->media.bmTransportModes = (u8 *)term - + sizeof *term + n; + + sizeof(*term) + n; memcpy(term->media.bmControls, &buffer[9], n); memcpy(term->media.bmTransportModes, &buffer[10+n], p); } if (buffer[7] != 0) usb_string(udev, buffer[7], term->name, - sizeof term->name); + sizeof(term->name)); else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) sprintf(term->name, "Camera %u", buffer[3]); else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) @@ -1162,7 +1162,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (buffer[8] != 0) usb_string(udev, buffer[8], term->name, - sizeof term->name); + sizeof(term->name)); else sprintf(term->name, "Output %u", buffer[3]); @@ -1187,7 +1187,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (buffer[5+p] != 0) usb_string(udev, buffer[5+p], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Selector %u", buffer[3]); @@ -1213,14 +1213,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->processing.wMaxMultiplier = get_unaligned_le16(&buffer[5]); unit->processing.bControlSize = buffer[7]; - unit->processing.bmControls = (u8 *)unit + sizeof *unit; + unit->processing.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->processing.bmControls, &buffer[8], n); if (dev->uvc_version >= 0x0110) unit->processing.bmVideoStandards = buffer[9+n]; if (buffer[8+n] != 0) usb_string(udev, buffer[8+n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Processing %u", buffer[3]); @@ -1246,12 +1246,12 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; - unit->extension.bmControls = (u8 *)unit + sizeof *unit; + unit->extension.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->extension.bmControls, &buffer[23+p], n); if (buffer[23+p+n] != 0) usb_string(udev, buffer[23+p+n], unit->name, - sizeof unit->name); + sizeof(unit->name)); else sprintf(unit->name, "Extension %u", buffer[3]); @@ -1936,7 +1936,7 @@ int uvc_register_video_device(struct uvc_device *dev, break; } - strlcpy(vdev->name, dev->name, sizeof vdev->name); + strlcpy(vdev->name, dev->name, sizeof(vdev->name)); /* * Set the driver data before calling video_register_device, otherwise @@ -2070,7 +2070,8 @@ static int uvc_probe(struct usb_interface *intf, udev->devpath); /* Allocate memory for the device and initialize it. */ - if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL) + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) return -ENOMEM; INIT_LIST_HEAD(&dev->entities); @@ -2089,9 +2090,9 @@ static int uvc_probe(struct usb_interface *intf, dev->meta_format = info->meta_format; if (udev->product != NULL) - strlcpy(dev->name, udev->product, sizeof dev->name); + strlcpy(dev->name, udev->product, sizeof(dev->name)); else - snprintf(dev->name, sizeof dev->name, + snprintf(dev->name, sizeof(dev->name), "UVC Camera (%04x:%04x)", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 5e1bfdc5b829..818a4369a51a 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -40,13 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, unsigned int size; int ret; - map = kzalloc(sizeof *map, GFP_KERNEL); + map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) return -ENOMEM; map->id = xmap->id; - memcpy(map->name, xmap->name, sizeof map->name); - memcpy(map->entity, xmap->entity, sizeof map->entity); + memcpy(map->name, xmap->name, sizeof(map->name)); + memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; map->size = xmap->size; map->offset = xmap->offset; @@ -224,7 +224,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, (100000000/interval)%10); /* Set the format index, frame index and frame interval. */ - memset(probe, 0, sizeof *probe); + memset(probe, 0, sizeof(*probe)); probe->bmHint = 1; /* dwFrameInterval */ probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; @@ -348,7 +348,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, denominator = 10000000; uvc_simplify_fraction(&numerator, &denominator, 8, 333); - memset(parm, 0, sizeof *parm); + memset(parm, 0, sizeof(*parm)); parm->type = stream->type; if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -526,7 +526,7 @@ static int uvc_v4l2_open(struct file *file) return ret; /* Create the device handle. */ - handle = kzalloc(sizeof *handle, GFP_KERNEL); + handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (handle == NULL) { usb_autopm_put_interface(stream->dev->intf); return -ENOMEM; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index dfe13c55a067..2ddb1367e195 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -191,7 +191,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " "compliance - GET_MIN/MAX(PROBE) incorrectly " "supported. Enabling workaround.\n"); - memset(ctrl, 0, sizeof *ctrl); + memset(ctrl, 0, sizeof(*ctrl)); ctrl->wCompQuality = le16_to_cpup((__le16 *)data); ret = 0; goto out; -- cgit From 43df6ea0c6ae85ae81edda3261d8d257d88a78a2 Mon Sep 17 00:00:00 2001 From: Jasmin Jessich Date: Sun, 14 Jan 2018 05:21:43 -0500 Subject: media: uvcvideo: Fixed ktime_t to ns conversion Commit 828ee8c71950 ("media: uvcvideo: Use ktime_t for timestamps") changed to use ktime_t for timestamps. Older Kernels use a struct for ktime_t, which requires the conversion function ktime_to_ns to be used on some places. With this patch it will compile now also for older Kernel versions. Signed-off-by: Jasmin Jessich Acked-by: Arnd Bergmann Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 2ddb1367e195..aa0082fe5833 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1009,7 +1009,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, buf->buf.field = V4L2_FIELD_NONE; buf->buf.sequence = stream->sequence; - buf->buf.vb2_buf.timestamp = uvc_video_get_time(); + buf->buf.vb2_buf.timestamp = ktime_to_ns(uvc_video_get_time()); /* TODO: Handle PTS and SCR. */ buf->state = UVC_BUF_STATE_ACTIVE; @@ -1191,7 +1191,8 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, uvc_trace(UVC_TRACE_FRAME, "%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n", - __func__, time, meta->sof, meta->length, meta->flags, + __func__, ktime_to_ns(time), meta->sof, meta->length, + meta->flags, has_pts ? *(u32 *)meta->buf : 0, has_scr ? *(u32 *)scr : 0, has_scr ? *(u32 *)(scr + 4) & 0x7ff : 0); -- cgit From d69a5a2cd197344f552c1c620300d479e98877ef Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Thu, 8 Feb 2018 19:14:24 -0500 Subject: media: intel-ipu3: cio2: Disable and sync irq before stream off This is to avoid pending interrupts to be handled during stream off, in which case, the ready buffer will be removed from buffer list, thus not all buffers can be returned to VB2 as expected. Disable CIO2 irq at cio2_hw_exit() so no new interrupts are generated. Signed-off-by: Yong Zhi Signed-off-by: Tianshu Qiu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 6c4444b31f4b..b6b0cfe00ef5 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -526,6 +526,8 @@ static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q) unsigned int i, maxloops = 1000; /* Disable CSI receiver and MIPI backend devices */ + writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_MASK); + writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_ENABLE); writel(0, q->csi_rx_base + CIO2_REG_CSIRX_ENABLE); writel(0, q->csi_rx_base + CIO2_REG_MIPIBE_ENABLE); @@ -1035,6 +1037,7 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq) "failed to stop sensor streaming\n"); cio2_hw_exit(cio2, q); + synchronize_irq(cio2->pci_dev->irq); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR); media_pipeline_stop(&q->vdev.entity); pm_runtime_put(&cio2->pci_dev->dev); @@ -1976,6 +1979,7 @@ static int __maybe_unused cio2_suspend(struct device *dev) /* Stop stream */ cio2_hw_exit(cio2, q); + synchronize_irq(pci_dev->irq); pm_runtime_force_suspend(dev); -- cgit From b39082e2bea6539819432293c0deb23620cb8a2a Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Fri, 16 Feb 2018 18:48:34 -0500 Subject: media: intel-ipu3: cio2: Use SPDX license headers Adopt SPDX license headers for ipu3 cio2 driver. Signed-off-by: Yong Zhi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 12 ++---------- drivers/media/pci/intel/ipu3/ipu3-cio2.h | 14 ++------------ 2 files changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index b6b0cfe00ef5..7d768ec0f824 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2017 Intel Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2017 Intel Corporation * * Based partially on Intel IPU4 driver written by * Sakari Ailus diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 78a5799f08e7..240635be7a31 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2017 Intel Corporation */ #ifndef __IPU3_CIO2_H #define __IPU3_CIO2_H -- cgit From 0f966bec710fd3f113a44e521e796cd225278fd4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 16 Jan 2018 06:02:44 -0500 Subject: media: imx074: deprecate, move to staging This driver is unused and depends on the deprecated soc-camera framework. Move it to staging in preparation for being removed unless someone does the work to convert it to a proper V4L2 subdev driver. Signed-off-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/Kconfig | 6 - drivers/media/i2c/soc_camera/Makefile | 1 - drivers/media/i2c/soc_camera/imx074.c | 497 ---------------------------------- 3 files changed, 504 deletions(-) delete mode 100644 drivers/media/i2c/soc_camera/imx074.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 72b369895b37..d7136f2c2b20 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -1,11 +1,5 @@ comment "soc_camera sensor drivers" -config SOC_CAMERA_IMX074 - tristate "imx074 support" - depends on SOC_CAMERA && I2C - help - This driver supports IMX074 cameras from Sony - config SOC_CAMERA_MT9M001 tristate "mt9m001 support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index faa2df8901d2..a489b00e43b5 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c deleted file mode 100644 index 77f1e0243d6e..000000000000 --- a/drivers/media/i2c/soc_camera/imx074.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Driver for IMX074 CMOS Image Sensor from Sony - * - * Copyright (C) 2010, Guennadi Liakhovetski - * - * Partially inspired by the IMX074 driver from the Android / MSM tree - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* IMX074 registers */ - -#define MODE_SELECT 0x0100 -#define IMAGE_ORIENTATION 0x0101 -#define GROUPED_PARAMETER_HOLD 0x0104 - -/* Integration Time */ -#define COARSE_INTEGRATION_TIME_HI 0x0202 -#define COARSE_INTEGRATION_TIME_LO 0x0203 -/* Gain */ -#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 -#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 - -/* PLL registers */ -#define PRE_PLL_CLK_DIV 0x0305 -#define PLL_MULTIPLIER 0x0307 -#define PLSTATIM 0x302b -#define VNDMY_ABLMGSHLMT 0x300a -#define Y_OPBADDR_START_DI 0x3014 -/* mode setting */ -#define FRAME_LENGTH_LINES_HI 0x0340 -#define FRAME_LENGTH_LINES_LO 0x0341 -#define LINE_LENGTH_PCK_HI 0x0342 -#define LINE_LENGTH_PCK_LO 0x0343 -#define YADDR_START 0x0347 -#define YADDR_END 0x034b -#define X_OUTPUT_SIZE_MSB 0x034c -#define X_OUTPUT_SIZE_LSB 0x034d -#define Y_OUTPUT_SIZE_MSB 0x034e -#define Y_OUTPUT_SIZE_LSB 0x034f -#define X_EVEN_INC 0x0381 -#define X_ODD_INC 0x0383 -#define Y_EVEN_INC 0x0385 -#define Y_ODD_INC 0x0387 - -#define HMODEADD 0x3001 -#define VMODEADD 0x3016 -#define VAPPLINE_START 0x3069 -#define VAPPLINE_END 0x306b -#define SHUTTER 0x3086 -#define HADDAVE 0x30e8 -#define LANESEL 0x3301 - -/* IMX074 supported geometry */ -#define IMX074_WIDTH 1052 -#define IMX074_HEIGHT 780 - -/* IMX074 has only one fixed colorspace per pixelcode */ -struct imx074_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -struct imx074 { - struct v4l2_subdev subdev; - const struct imx074_datafmt *fmt; - struct v4l2_clk *clk; -}; - -static const struct imx074_datafmt imx074_colour_fmts[] = { - {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static struct imx074 *to_imx074(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct imx074, subdev); -} - -/* Find a data format by a pixel code in an array */ -static const struct imx074_datafmt *imx074_find_datafmt(u32 code) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++) - if (imx074_colour_fmts[i].code == code) - return imx074_colour_fmts + i; - - return NULL; -} - -static int reg_write(struct i2c_client *client, const u16 addr, const u8 data) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - unsigned char tx[3]; - int ret; - - msg.addr = client->addr; - msg.buf = tx; - msg.len = 3; - msg.flags = 0; - - tx[0] = addr >> 8; - tx[1] = addr & 0xff; - tx[2] = data; - - ret = i2c_transfer(adap, &msg, 1); - - mdelay(2); - - return ret == 1 ? 0 : -EIO; -} - -static int reg_read(struct i2c_client *client, const u16 addr) -{ - u8 buf[2] = {addr >> 8, addr & 0xff}; - int ret; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = buf, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 2, - .buf = buf, - }, - }; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) { - dev_warn(&client->dev, "Reading register %x from %x failed\n", - addr, client->addr); - return ret; - } - - return buf[0] & 0xff; /* no sign-extension */ -} - -static int imx074_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - if (format->pad) - return -EINVAL; - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - - if (!fmt) { - /* MIPI CSI could have changed the format, double-check */ - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - mf->code = imx074_colour_fmts[0].code; - mf->colorspace = imx074_colour_fmts[0].colorspace; - } - - mf->width = IMX074_WIDTH; - mf->height = IMX074_HEIGHT; - mf->field = V4L2_FIELD_NONE; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - priv->fmt = fmt; - else - cfg->try_fmt = *mf; - - return 0; -} - -static int imx074_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - const struct imx074_datafmt *fmt = priv->fmt; - - if (format->pad) - return -EINVAL; - - mf->code = fmt->code; - mf->colorspace = fmt->colorspace; - mf->width = IMX074_WIDTH; - mf->height = IMX074_HEIGHT; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int imx074_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = IMX074_WIDTH; - sel->r.height = IMX074_HEIGHT; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP: - return 0; - default: - return -EINVAL; - } -} - -static int imx074_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || - (unsigned int)code->index >= ARRAY_SIZE(imx074_colour_fmts)) - return -EINVAL; - - code->code = imx074_colour_fmts[code->index].code; - return 0; -} - -static int imx074_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* MODE_SELECT: stream or standby */ - return reg_write(client, MODE_SELECT, !!enable); -} - -static int imx074_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct imx074 *priv = to_imx074(client); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -static int imx074_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - cfg->type = V4L2_MBUS_CSI2; - cfg->flags = V4L2_MBUS_CSI2_2_LANE | - V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - - return 0; -} - -static const struct v4l2_subdev_video_ops imx074_subdev_video_ops = { - .s_stream = imx074_s_stream, - .g_mbus_config = imx074_g_mbus_config, -}; - -static const struct v4l2_subdev_core_ops imx074_subdev_core_ops = { - .s_power = imx074_s_power, -}; - -static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { - .enum_mbus_code = imx074_enum_mbus_code, - .get_selection = imx074_get_selection, - .get_fmt = imx074_get_fmt, - .set_fmt = imx074_set_fmt, -}; - -static const struct v4l2_subdev_ops imx074_subdev_ops = { - .core = &imx074_subdev_core_ops, - .video = &imx074_subdev_video_ops, - .pad = &imx074_subdev_pad_ops, -}; - -static int imx074_video_probe(struct i2c_client *client) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - int ret; - u16 id; - - ret = imx074_s_power(subdev, 1); - if (ret < 0) - return ret; - - /* Read sensor Model ID */ - ret = reg_read(client, 0); - if (ret < 0) - goto done; - - id = ret << 8; - - ret = reg_read(client, 1); - if (ret < 0) - goto done; - - id |= ret; - - dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); - - if (id != 0x74) { - ret = -ENODEV; - goto done; - } - - /* PLL Setting EXTCLK=24MHz, 22.5times */ - reg_write(client, PLL_MULTIPLIER, 0x2D); - reg_write(client, PRE_PLL_CLK_DIV, 0x02); - reg_write(client, PLSTATIM, 0x4B); - - /* 2-lane mode */ - reg_write(client, 0x3024, 0x00); - - reg_write(client, IMAGE_ORIENTATION, 0x00); - - /* select RAW mode: - * 0x08+0x08 = top 8 bits - * 0x0a+0x08 = compressed 8-bits - * 0x0a+0x0a = 10 bits - */ - reg_write(client, 0x0112, 0x08); - reg_write(client, 0x0113, 0x08); - - /* Base setting for High frame mode */ - reg_write(client, VNDMY_ABLMGSHLMT, 0x80); - reg_write(client, Y_OPBADDR_START_DI, 0x08); - reg_write(client, 0x3015, 0x37); - reg_write(client, 0x301C, 0x01); - reg_write(client, 0x302C, 0x05); - reg_write(client, 0x3031, 0x26); - reg_write(client, 0x3041, 0x60); - reg_write(client, 0x3051, 0x24); - reg_write(client, 0x3053, 0x34); - reg_write(client, 0x3057, 0xC0); - reg_write(client, 0x305C, 0x09); - reg_write(client, 0x305D, 0x07); - reg_write(client, 0x3060, 0x30); - reg_write(client, 0x3065, 0x00); - reg_write(client, 0x30AA, 0x08); - reg_write(client, 0x30AB, 0x1C); - reg_write(client, 0x30B0, 0x32); - reg_write(client, 0x30B2, 0x83); - reg_write(client, 0x30D3, 0x04); - reg_write(client, 0x3106, 0x78); - reg_write(client, 0x310C, 0x82); - reg_write(client, 0x3304, 0x05); - reg_write(client, 0x3305, 0x04); - reg_write(client, 0x3306, 0x11); - reg_write(client, 0x3307, 0x02); - reg_write(client, 0x3308, 0x0C); - reg_write(client, 0x3309, 0x06); - reg_write(client, 0x330A, 0x08); - reg_write(client, 0x330B, 0x04); - reg_write(client, 0x330C, 0x08); - reg_write(client, 0x330D, 0x06); - reg_write(client, 0x330E, 0x01); - reg_write(client, 0x3381, 0x00); - - /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */ - /* 1608 = 1560 + 48 (black lines) */ - reg_write(client, FRAME_LENGTH_LINES_HI, 0x06); - reg_write(client, FRAME_LENGTH_LINES_LO, 0x48); - reg_write(client, YADDR_START, 0x00); - reg_write(client, YADDR_END, 0x2F); - /* 0x838 == 2104 */ - reg_write(client, X_OUTPUT_SIZE_MSB, 0x08); - reg_write(client, X_OUTPUT_SIZE_LSB, 0x38); - /* 0x618 == 1560 */ - reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06); - reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18); - reg_write(client, X_EVEN_INC, 0x01); - reg_write(client, X_ODD_INC, 0x03); - reg_write(client, Y_EVEN_INC, 0x01); - reg_write(client, Y_ODD_INC, 0x03); - reg_write(client, HMODEADD, 0x00); - reg_write(client, VMODEADD, 0x16); - reg_write(client, VAPPLINE_START, 0x24); - reg_write(client, VAPPLINE_END, 0x53); - reg_write(client, SHUTTER, 0x00); - reg_write(client, HADDAVE, 0x80); - - reg_write(client, LANESEL, 0x00); - - reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */ - - ret = 0; - -done: - imx074_s_power(subdev, 0); - return ret; -} - -static int imx074_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct imx074 *priv; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "IMX074: missing platform data!\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); - return -EIO; - } - - priv = devm_kzalloc(&client->dev, sizeof(struct imx074), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); - - priv->fmt = &imx074_colour_fmts[0]; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) { - dev_info(&client->dev, "Error %ld getting clock\n", PTR_ERR(priv->clk)); - return -EPROBE_DEFER; - } - - ret = soc_camera_power_init(&client->dev, ssdd); - if (ret < 0) - goto epwrinit; - - ret = imx074_video_probe(client); - if (ret < 0) - goto eprobe; - - ret = v4l2_async_register_subdev(&priv->subdev); - if (!ret) - return 0; - -epwrinit: -eprobe: - v4l2_clk_put(priv->clk); - return ret; -} - -static int imx074_remove(struct i2c_client *client) -{ - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct imx074 *priv = to_imx074(client); - - v4l2_async_unregister_subdev(&priv->subdev); - v4l2_clk_put(priv->clk); - - if (ssdd->free_bus) - ssdd->free_bus(ssdd); - - return 0; -} - -static const struct i2c_device_id imx074_id[] = { - { "imx074", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, imx074_id); - -static struct i2c_driver imx074_i2c_driver = { - .driver = { - .name = "imx074", - }, - .probe = imx074_probe, - .remove = imx074_remove, - .id_table = imx074_id, -}; - -module_i2c_driver(imx074_i2c_driver); - -MODULE_DESCRIPTION("Sony IMX074 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -- cgit From 40de44bbe09bcb9cc7b8dd648ca2cacf752796ec Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 16 Jan 2018 06:02:45 -0500 Subject: media: mt9t031: deprecate, move to staging This driver is unused and depends on the deprecated soc-camera framework. Move it to staging in preparation for being removed unless someone does the work to convert it to a proper V4L2 subdev driver. Signed-off-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/Kconfig | 6 - drivers/media/i2c/soc_camera/Makefile | 1 - drivers/media/i2c/soc_camera/mt9t031.c | 858 --------------------------------- 3 files changed, 865 deletions(-) delete mode 100644 drivers/media/i2c/soc_camera/mt9t031.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index d7136f2c2b20..7c2aabc8a3f6 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -17,12 +17,6 @@ config SOC_CAMERA_MT9M111 This is the legacy configuration which shouldn't be used anymore, while VIDEO_MT9M111 should be used instead. -config SOC_CAMERA_MT9T031 - tristate "mt9t031 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T031 cameras from Micron. - config SOC_CAMERA_MT9T112 tristate "mt9t112 support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index a489b00e43b5..8c7770f62997 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c deleted file mode 100644 index 4802d30e47de..000000000000 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Driver for MT9T031 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * ATTENTION: this driver still cannot be used outside of the soc-camera - * framework because of its PM implementation, using the video_device node. - * If hardware becomes available for testing, alternative PM approaches shall - * be considered and tested. - */ - -/* - * mt9t031 i2c address 0x5d - * The platform has to define struct i2c_board_info objects and link to them - * from struct soc_camera_host_desc - */ - -/* mt9t031 selected register addresses */ -#define MT9T031_CHIP_VERSION 0x00 -#define MT9T031_ROW_START 0x01 -#define MT9T031_COLUMN_START 0x02 -#define MT9T031_WINDOW_HEIGHT 0x03 -#define MT9T031_WINDOW_WIDTH 0x04 -#define MT9T031_HORIZONTAL_BLANKING 0x05 -#define MT9T031_VERTICAL_BLANKING 0x06 -#define MT9T031_OUTPUT_CONTROL 0x07 -#define MT9T031_SHUTTER_WIDTH_UPPER 0x08 -#define MT9T031_SHUTTER_WIDTH 0x09 -#define MT9T031_PIXEL_CLOCK_CONTROL 0x0a -#define MT9T031_FRAME_RESTART 0x0b -#define MT9T031_SHUTTER_DELAY 0x0c -#define MT9T031_RESET 0x0d -#define MT9T031_READ_MODE_1 0x1e -#define MT9T031_READ_MODE_2 0x20 -#define MT9T031_READ_MODE_3 0x21 -#define MT9T031_ROW_ADDRESS_MODE 0x22 -#define MT9T031_COLUMN_ADDRESS_MODE 0x23 -#define MT9T031_GLOBAL_GAIN 0x35 -#define MT9T031_CHIP_ENABLE 0xF8 - -#define MT9T031_MAX_HEIGHT 1536 -#define MT9T031_MAX_WIDTH 2048 -#define MT9T031_MIN_HEIGHT 2 -#define MT9T031_MIN_WIDTH 18 -#define MT9T031_HORIZONTAL_BLANK 142 -#define MT9T031_VERTICAL_BLANK 25 -#define MT9T031_COLUMN_SKIP 32 -#define MT9T031_ROW_SKIP 20 - -struct mt9t031 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/auto-exposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct v4l2_rect rect; /* Sensor window */ - struct v4l2_clk *clk; - u16 xskip; - u16 yskip; - unsigned int total_h; - unsigned short y_skip_top; /* Lines to skip at the top */ -}; - -static struct mt9t031 *to_mt9t031(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9t031, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - return i2c_smbus_read_word_swapped(client, reg); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_swapped(client, reg, data); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int set_shutter(struct i2c_client *client, const u32 data) -{ - int ret; - - ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); - - if (ret >= 0) - ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff); - - return ret; -} - -static int get_shutter(struct i2c_client *client, u32 *data) -{ - int ret; - - ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); - *data = ret << 16; - - if (ret >= 0) - ret = reg_read(client, MT9T031_SHUTTER_WIDTH); - *data |= ret & 0xffff; - - return ret < 0 ? ret : 0; -} - -static int mt9t031_idle(struct i2c_client *client) -{ - int ret; - - /* Disable chip output, synchronous option update */ - ret = reg_write(client, MT9T031_RESET, 1); - if (ret >= 0) - ret = reg_write(client, MT9T031_RESET, 0); - if (ret >= 0) - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - return ret >= 0 ? 0 : -EIO; -} - -static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (enable) - /* Switch to master "normal" mode */ - ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2); - else - /* Stop sensor readout */ - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); - - if (ret < 0) - return -EIO; - - return 0; -} - -/* target must be _even_ */ -static u16 mt9t031_skip(s32 *source, s32 target, s32 max) -{ - unsigned int skip; - - if (*source < target + target / 2) { - *source = target; - return 1; - } - - skip = min(max, *source + target / 2) / target; - if (skip > 8) - skip = 8; - *source = target * skip; - - return skip; -} - -/* rect is the sensor rectangle, the caller guarantees parameter validity */ -static int mt9t031_set_params(struct i2c_client *client, - struct v4l2_rect *rect, u16 xskip, u16 yskip) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - int ret; - u16 xbin, ybin; - const u16 hblank = MT9T031_HORIZONTAL_BLANK, - vblank = MT9T031_VERTICAL_BLANK; - - xbin = min(xskip, (u16)3); - ybin = min(yskip, (u16)3); - - /* - * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper. - * There is always a valid suitably aligned value. The worst case is - * xbin = 3, width = 2048. Then we will start at 36, the last read out - * pixel will be 2083, which is < 2085 - first black pixel. - * - * MT9T031 datasheet imposes window left border alignment, depending on - * the selected xskip. Failing to conform to this requirement produces - * dark horizontal stripes in the image. However, even obeying to this - * requirement doesn't eliminate the stripes in all configurations. They - * appear "locally reproducibly," but can differ between tests under - * different lighting conditions. - */ - switch (xbin) { - case 1: - rect->left &= ~1; - break; - case 2: - rect->left &= ~3; - break; - case 3: - rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ? - (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6); - } - - rect->top &= ~1; - - dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", - xskip, yskip, rect->width, rect->height, rect->left, rect->top); - - /* Disable register update, reconfigure atomically */ - ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); - if (ret < 0) - return ret; - - /* Blanking and start values - default... */ - ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank); - if (ret >= 0) - ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank); - - if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { - /* Binning, skipping */ - if (ret >= 0) - ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, - ((xbin - 1) << 4) | (xskip - 1)); - if (ret >= 0) - ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, - ((ybin - 1) << 4) | (yskip - 1)); - } - dev_dbg(&client->dev, "new physical left %u, top %u\n", - rect->left, rect->top); - - /* - * The caller provides a supported format, as guaranteed by - * .set_fmt(FORMAT_TRY), soc_camera_s_selection() and soc_camera_cropcap() - */ - if (ret >= 0) - ret = reg_write(client, MT9T031_COLUMN_START, rect->left); - if (ret >= 0) - ret = reg_write(client, MT9T031_ROW_START, rect->top); - if (ret >= 0) - ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); - if (ret >= 0) - ret = reg_write(client, MT9T031_WINDOW_HEIGHT, - rect->height + mt9t031->y_skip_top - 1); - if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { - mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; - - ret = set_shutter(client, mt9t031->total_h); - } - - /* Re-enable register update, commit all changes */ - if (ret >= 0) - ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); - - if (ret >= 0) { - mt9t031->rect = *rect; - mt9t031->xskip = xskip; - mt9t031->yskip = yskip; - } - - return ret < 0 ? ret : 0; -} - -static int mt9t031_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - struct v4l2_rect rect = sel->r; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - rect.width = ALIGN(rect.width, 2); - rect.height = ALIGN(rect.height, 2); - - soc_camera_limit_side(&rect.left, &rect.width, - MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); - - return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); -} - -static int mt9t031_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.left = MT9T031_COLUMN_SKIP; - sel->r.top = MT9T031_ROW_SKIP; - sel->r.width = MT9T031_MAX_WIDTH; - sel->r.height = MT9T031_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = mt9t031->rect; - return 0; - default: - return -EINVAL; - } -} - -static int mt9t031_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - if (format->pad) - return -EINVAL; - - mf->width = mt9t031->rect.width / mt9t031->xskip; - mf->height = mt9t031->rect.height / mt9t031->yskip; - mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -/* - * If a user window larger than sensor window is requested, we'll increase the - * sensor window. - */ -static int mt9t031_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - u16 xskip, yskip; - struct v4l2_rect rect = mt9t031->rect; - - if (format->pad) - return -EINVAL; - - mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - v4l_bound_align_image( - &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, - &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *mf; - return 0; - } - - /* - * Width and height are within limits. - * S_FMT: use binning and skipping for scaling - */ - xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); - yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT); - - mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - /* mt9t031_set_params() doesn't change width and height */ - return mt9t031_set_params(client, &rect, xskip, yskip); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t031_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - reg->size = 1; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9t031_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9t031 *mt9t031 = container_of(ctrl->handler, - struct mt9t031, hdl); - const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; - s32 min, max; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_AUTO: - min = mt9t031->exposure->minimum; - max = mt9t031->exposure->maximum; - mt9t031->exposure->val = - (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) - / shutter_max + min; - break; - } - return 0; -} - -static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9t031 *mt9t031 = container_of(ctrl->handler, - struct mt9t031, hdl); - struct v4l2_subdev *sd = &mt9t031->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_ctrl *exp = mt9t031->exposure; - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->val) - data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); - else - data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_HFLIP: - if (ctrl->val) - data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); - else - data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_GAIN: - /* See Datasheet Table 7, Gain settings. */ - if (ctrl->val <= ctrl->default_value) { - /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = ctrl->default_value - ctrl->minimum; - data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range; - - dev_dbg(&client->dev, "Setting gain %d\n", data); - data = reg_write(client, MT9T031_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } else { - /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ - /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = ctrl->maximum - ctrl->default_value - 1; - /* calculated gain: map 65..127 to 9..1024 step 0.125 */ - unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) * - 1015 + range / 2) / range + 9; - - if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ - data = gain; - else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */ - data = ((gain - 32) * 16 + 16) / 32 + 80; - else - /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ - data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; - - dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n", - reg_read(client, MT9T031_GLOBAL_GAIN), data); - data = reg_write(client, MT9T031_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; - } - return 0; - - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_MANUAL) { - unsigned int range = exp->maximum - exp->minimum; - unsigned int shutter = ((exp->val - (s32)exp->minimum) * 1048 + - range / 2) / range + 1; - u32 old; - - get_shutter(client, &old); - dev_dbg(&client->dev, "Set shutter from %u to %u\n", - old, shutter); - if (set_shutter(client, shutter) < 0) - return -EIO; - } else { - const u16 vblank = MT9T031_VERTICAL_BLANK; - mt9t031->total_h = mt9t031->rect.height + - mt9t031->y_skip_top + vblank; - - if (set_shutter(client, mt9t031->total_h) < 0) - return -EIO; - } - return 0; - default: - return -EINVAL; - } - return 0; -} - -/* - * Power Management: - * This function does nothing for now but must be present for pm to work - */ -static int mt9t031_runtime_suspend(struct device *dev) -{ - return 0; -} - -/* - * Power Management: - * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged - * they are however changed at reset if the platform hook is present - * thus we rewrite them with the values stored by the driver - */ -static int mt9t031_runtime_resume(struct device *dev) -{ - struct video_device *vdev = to_video_device(dev); - struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - int ret; - u16 xbin, ybin; - - xbin = min(mt9t031->xskip, (u16)3); - ybin = min(mt9t031->yskip, (u16)3); - - ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, - ((xbin - 1) << 4) | (mt9t031->xskip - 1)); - if (ret < 0) - return ret; - - ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, - ((ybin - 1) << 4) | (mt9t031->yskip - 1)); - if (ret < 0) - return ret; - - return 0; -} - -static const struct dev_pm_ops mt9t031_dev_pm_ops = { - .runtime_suspend = mt9t031_runtime_suspend, - .runtime_resume = mt9t031_runtime_resume, -}; - -static const struct device_type mt9t031_dev_type = { - .name = "MT9T031", - .pm = &mt9t031_dev_pm_ops, -}; - -static int mt9t031_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct video_device *vdev = soc_camera_i2c_to_vdev(client); - struct mt9t031 *mt9t031 = to_mt9t031(client); - int ret; - - if (on) { - ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk); - if (ret < 0) - return ret; - if (vdev) - /* Not needed during probing, when vdev isn't available yet */ - vdev->dev.type = &mt9t031_dev_type; - } else { - if (vdev) - vdev->dev.type = NULL; - soc_camera_power_off(&client->dev, ssdd, mt9t031->clk); - } - - return 0; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9t031_video_probe(struct i2c_client *client) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - s32 data; - int ret; - - ret = mt9t031_s_power(&mt9t031->subdev, 1); - if (ret < 0) - return ret; - - ret = mt9t031_idle(client); - if (ret < 0) { - dev_err(&client->dev, "Failed to initialise the camera\n"); - goto done; - } - - /* Read out the chip version register */ - data = reg_read(client, MT9T031_CHIP_VERSION); - - switch (data) { - case 0x1621: - break; - default: - dev_err(&client->dev, - "No MT9T031 chip detected, register read %x\n", data); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); - - ret = v4l2_ctrl_handler_setup(&mt9t031->hdl); - -done: - mt9t031_s_power(&mt9t031->subdev, 0); - - return ret; -} - -static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - - *lines = mt9t031->y_skip_top; - - return 0; -} - -static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { - .g_volatile_ctrl = mt9t031_g_volatile_ctrl, - .s_ctrl = mt9t031_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { - .s_power = mt9t031_s_power, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9t031_g_register, - .s_register = mt9t031_s_register, -#endif -}; - -static int mt9t031_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - if (soc_camera_apply_board_flags(ssdd, cfg) & - V4L2_MBUS_PCLK_SAMPLE_FALLING) - return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); - else - return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); -} - -static const struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { - .s_stream = mt9t031_s_stream, - .g_mbus_config = mt9t031_g_mbus_config, - .s_mbus_config = mt9t031_s_mbus_config, -}; - -static const struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { - .g_skip_top_lines = mt9t031_g_skip_top_lines, -}; - -static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { - .enum_mbus_code = mt9t031_enum_mbus_code, - .get_selection = mt9t031_get_selection, - .set_selection = mt9t031_set_selection, - .get_fmt = mt9t031_get_fmt, - .set_fmt = mt9t031_set_fmt, -}; - -static const struct v4l2_subdev_ops mt9t031_subdev_ops = { - .core = &mt9t031_subdev_core_ops, - .video = &mt9t031_subdev_video_ops, - .sensor = &mt9t031_subdev_sensor_ops, - .pad = &mt9t031_subdev_pad_ops, -}; - -static int mt9t031_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9t031 *mt9t031; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9t031 = devm_kzalloc(&client->dev, sizeof(struct mt9t031), GFP_KERNEL); - if (!mt9t031) - return -ENOMEM; - - v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); - v4l2_ctrl_handler_init(&mt9t031->hdl, 5); - v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, - V4L2_CID_GAIN, 0, 127, 1, 64); - - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, - &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, - V4L2_EXPOSURE_AUTO); - mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 255, 1, 255); - - mt9t031->subdev.ctrl_handler = &mt9t031->hdl; - if (mt9t031->hdl.error) - return mt9t031->hdl.error; - - v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, - V4L2_EXPOSURE_MANUAL, true); - - mt9t031->y_skip_top = 0; - mt9t031->rect.left = MT9T031_COLUMN_SKIP; - mt9t031->rect.top = MT9T031_ROW_SKIP; - mt9t031->rect.width = MT9T031_MAX_WIDTH; - mt9t031->rect.height = MT9T031_MAX_HEIGHT; - - mt9t031->xskip = 1; - mt9t031->yskip = 1; - - mt9t031->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(mt9t031->clk)) { - ret = PTR_ERR(mt9t031->clk); - goto eclkget; - } - - ret = mt9t031_video_probe(client); - if (ret) { - v4l2_clk_put(mt9t031->clk); -eclkget: - v4l2_ctrl_handler_free(&mt9t031->hdl); - } - - return ret; -} - -static int mt9t031_remove(struct i2c_client *client) -{ - struct mt9t031 *mt9t031 = to_mt9t031(client); - - v4l2_clk_put(mt9t031->clk); - v4l2_device_unregister_subdev(&mt9t031->subdev); - v4l2_ctrl_handler_free(&mt9t031->hdl); - - return 0; -} - -static const struct i2c_device_id mt9t031_id[] = { - { "mt9t031", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9t031_id); - -static struct i2c_driver mt9t031_i2c_driver = { - .driver = { - .name = "mt9t031", - }, - .probe = mt9t031_probe, - .remove = mt9t031_remove, - .id_table = mt9t031_id, -}; - -module_i2c_driver(mt9t031_i2c_driver); - -MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_LICENSE("GPL v2"); -- cgit From 8a77009be4bed02dc00c0a84841c98e320ad2ecf Mon Sep 17 00:00:00 2001 From: Shunqian Zheng Date: Tue, 16 Jan 2018 04:21:59 -0500 Subject: media: ov5695: add support for OV5695 sensor This patch adds driver for Omnivision's ov5695 sensor, the driver supports following features: - supported resolutions + 2592x1944 at 30fps + 1920x1080 at 30fps + 1296x972 at 60fps + 1280x720 at 30fps + 640x480 at 120fps - test patterns - manual exposure/gain(analog and digital) control - vblank and hblank - media controller - runtime pm Signed-off-by: Shunqian Zheng Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov5695.c | 1399 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1411 insertions(+) create mode 100644 drivers/media/i2c/ov5695.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 8fdd673d449f..00377fe06504 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -654,6 +654,17 @@ config VIDEO_OV5670 To compile this driver as a module, choose M here: the module will be called ov5670. +config VIDEO_OV5695 + tristate "OmniVision OV5695 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV5695 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5695. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 26b19a2e9d04..0cef61e4bdcb 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c new file mode 100644 index 000000000000..2db7d2e535b9 --- /dev/null +++ b/drivers/media/i2c/ov5695.c @@ -0,0 +1,1399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ov5695 driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef V4L2_CID_DIGITAL_GAIN +#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN +#endif + +/* 45Mhz * 4 Binning */ +#define OV5695_PIXEL_RATE (45 * 1000 * 1000 * 4) +#define OV5695_XVCLK_FREQ 24000000 + +#define CHIP_ID 0x005695 +#define OV5695_REG_CHIP_ID 0x300a + +#define OV5695_REG_CTRL_MODE 0x0100 +#define OV5695_MODE_SW_STANDBY 0x0 +#define OV5695_MODE_STREAMING BIT(0) + +#define OV5695_REG_EXPOSURE 0x3500 +#define OV5695_EXPOSURE_MIN 4 +#define OV5695_EXPOSURE_STEP 1 +#define OV5695_VTS_MAX 0x7fff + +#define OV5695_REG_ANALOG_GAIN 0x3509 +#define ANALOG_GAIN_MIN 0x10 +#define ANALOG_GAIN_MAX 0xf8 +#define ANALOG_GAIN_STEP 1 +#define ANALOG_GAIN_DEFAULT 0xf8 + +#define OV5695_REG_DIGI_GAIN_H 0x350a +#define OV5695_REG_DIGI_GAIN_L 0x350b +#define OV5695_DIGI_GAIN_L_MASK 0x3f +#define OV5695_DIGI_GAIN_H_SHIFT 6 +#define OV5695_DIGI_GAIN_MIN 0 +#define OV5695_DIGI_GAIN_MAX (0x4000 - 1) +#define OV5695_DIGI_GAIN_STEP 1 +#define OV5695_DIGI_GAIN_DEFAULT 1024 + +#define OV5695_REG_TEST_PATTERN 0x4503 +#define OV5695_TEST_PATTERN_ENABLE 0x80 +#define OV5695_TEST_PATTERN_DISABLE 0x0 + +#define OV5695_REG_VTS 0x380e + +#define REG_NULL 0xFFFF + +#define OV5695_REG_VALUE_08BIT 1 +#define OV5695_REG_VALUE_16BIT 2 +#define OV5695_REG_VALUE_24BIT 3 + +#define OV5695_LANES 2 +#define OV5695_BITS_PER_SAMPLE 10 + +static const char * const ov5695_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV5695_NUM_SUPPLIES ARRAY_SIZE(ov5695_supply_names) + +struct regval { + u16 addr; + u8 val; +}; + +struct ov5695_mode { + u32 width; + u32 height; + u32 max_fps; + u32 hts_def; + u32 vts_def; + u32 exp_def; + const struct regval *reg_list; +}; + +struct ov5695 { + struct i2c_client *client; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV5695_NUM_SUPPLIES]; + + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *anal_gain; + struct v4l2_ctrl *digi_gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + struct mutex mutex; + bool streaming; + const struct ov5695_mode *cur_mode; +}; + +#define to_ov5695(sd) container_of(sd, struct ov5695, subdev) + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1296 + * grabwindow_height 972 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_global_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0301, 0x00}, + {0x0302, 0x69}, + {0x0303, 0x00}, + {0x0304, 0x00}, + {0x0305, 0x01}, + {0x0307, 0x00}, + {0x030b, 0x00}, + {0x030c, 0x00}, + {0x030d, 0x1e}, + {0x030e, 0x04}, + {0x030f, 0x03}, + {0x0312, 0x01}, + {0x3000, 0x00}, + {0x3002, 0xa1}, + {0x3008, 0x00}, + {0x3010, 0x00}, + {0x3022, 0x51}, + {0x3106, 0x15}, + {0x3107, 0x01}, + {0x3108, 0x05}, + {0x3500, 0x00}, + {0x3501, 0x45}, + {0x3502, 0x00}, + {0x3503, 0x08}, + {0x3504, 0x03}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0x55}, + {0x3602, 0x58}, + {0x3614, 0x30}, + {0x3615, 0x77}, + {0x3621, 0x08}, + {0x3624, 0x40}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3638, 0x00}, + {0x3639, 0x00}, + {0x363a, 0x00}, + {0x363b, 0x00}, + {0x363c, 0xff}, + {0x363d, 0xfa}, + {0x3650, 0x44}, + {0x3651, 0x44}, + {0x3652, 0x44}, + {0x3653, 0x44}, + {0x3654, 0x44}, + {0x3655, 0x44}, + {0x3656, 0x44}, + {0x3657, 0x44}, + {0x3660, 0x00}, + {0x3661, 0x00}, + {0x3662, 0x00}, + {0x366a, 0x00}, + {0x366e, 0x0c}, + {0x3673, 0x04}, + {0x3700, 0x14}, + {0x3703, 0x0c}, + {0x3715, 0x01}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x373f, 0xa0}, + {0x3765, 0x20}, + {0x37a1, 0x1d}, + {0x37a8, 0x26}, + {0x37ab, 0x14}, + {0x37c2, 0x04}, + {0x37cb, 0x09}, + {0x37cc, 0x13}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3810, 0x00}, + {0x3811, 0x06}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x381a, 0x00}, + {0x381b, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3c80, 0x08}, + {0x3c82, 0x00}, + {0x3c83, 0x00}, + {0x3c88, 0x00}, + {0x3d85, 0x14}, + {0x3f02, 0x08}, + {0x3f03, 0x10}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x404e, 0x20}, + {0x4501, 0x00}, + {0x4502, 0x10}, + {0x4800, 0x00}, + {0x481f, 0x2a}, + {0x4837, 0x13}, + {0x5000, 0x17}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5b00, 0x00}, + {0x5b01, 0x1c}, + {0x5b02, 0x00}, + {0x5b03, 0x7f}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x4010, 0xf1}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0xf8}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 740(0x2e4) + * framelength 2024(0x7e8) + * grabwindow_width 2592 + * grabwindow_height 1944 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_2592x1944_regs[] = { + {0x3501, 0x7e}, + {0x366e, 0x18}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xab}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x02}, + {0x380d, 0xe4}, + {0x380e, 0x07}, + {0x380f, 0xe8}, + {0x3811, 0x06}, + {0x3813, 0x08}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x3820, 0x88}, + {0x3821, 0x00}, + {0x4501, 0x00}, + {0x4008, 0x04}, + {0x4009, 0x13}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1920 + * grabwindow_height 1080 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1920x1080_regs[] = { + {0x3501, 0x45}, + {0x366e, 0x18}, + {0x3800, 0x01}, + {0x3801, 0x50}, + {0x3802, 0x01}, + {0x3803, 0xb8}, + {0x3804, 0x08}, + {0x3805, 0xef}, + {0x3806, 0x05}, + {0x3807, 0xf7}, + {0x3808, 0x07}, + {0x3809, 0x80}, + {0x380a, 0x04}, + {0x380b, 0x38}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3811, 0x06}, + {0x3813, 0x04}, + {0x3814, 0x01}, + {0x3816, 0x01}, + {0x3817, 0x01}, + {0x3820, 0x88}, + {0x3821, 0x00}, + {0x4501, 0x00}, + {0x4008, 0x04}, + {0x4009, 0x13}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 740(0x02e4) + * framelength 1012(0x03f4) + * grabwindow_width 1296 + * grabwindow_height 972 + * max_framerate 60fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1296x972_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0300, 0x04}, + {0x0301, 0x00}, + {0x0302, 0x69}, + {0x0303, 0x00}, + {0x0304, 0x00}, + {0x0305, 0x01}, + {0x0307, 0x00}, + {0x030b, 0x00}, + {0x030c, 0x00}, + {0x030d, 0x1e}, + {0x030e, 0x04}, + {0x030f, 0x03}, + {0x0312, 0x01}, + {0x3000, 0x00}, + {0x3002, 0xa1}, + {0x3008, 0x00}, + {0x3010, 0x00}, + {0x3016, 0x32}, + {0x3022, 0x51}, + {0x3106, 0x15}, + {0x3107, 0x01}, + {0x3108, 0x05}, + {0x3500, 0x00}, + {0x3501, 0x3e}, + {0x3502, 0x00}, + {0x3503, 0x08}, + {0x3504, 0x03}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0x55}, + {0x3602, 0x58}, + {0x3611, 0x58}, + {0x3614, 0x30}, + {0x3615, 0x77}, + {0x3621, 0x08}, + {0x3624, 0x40}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3638, 0x00}, + {0x3639, 0x00}, + {0x363a, 0x00}, + {0x363b, 0x00}, + {0x363c, 0xff}, + {0x363d, 0xfa}, + {0x3650, 0x44}, + {0x3651, 0x44}, + {0x3652, 0x44}, + {0x3653, 0x44}, + {0x3654, 0x44}, + {0x3655, 0x44}, + {0x3656, 0x44}, + {0x3657, 0x44}, + {0x3660, 0x00}, + {0x3661, 0x00}, + {0x3662, 0x00}, + {0x366a, 0x00}, + {0x366e, 0x0c}, + {0x3673, 0x04}, + {0x3700, 0x14}, + {0x3703, 0x0c}, + {0x3706, 0x24}, + {0x3714, 0x27}, + {0x3715, 0x01}, + {0x3716, 0x00}, + {0x3717, 0x02}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x373f, 0xa0}, + {0x3765, 0x20}, + {0x37a1, 0x1d}, + {0x37a8, 0x26}, + {0x37ab, 0x14}, + {0x37c2, 0x04}, + {0x37c3, 0xf0}, + {0x37cb, 0x09}, + {0x37cc, 0x13}, + {0x37cd, 0x1f}, + {0x37ce, 0x1f}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, + {0x380c, 0x02}, + {0x380d, 0xe4}, + {0x380e, 0x03}, + {0x380f, 0xf4}, + {0x3810, 0x00}, + {0x3811, 0x00}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x381a, 0x00}, + {0x381b, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x3c80, 0x08}, + {0x3c82, 0x00}, + {0x3c83, 0x00}, + {0x3c88, 0x00}, + {0x3d85, 0x14}, + {0x3f02, 0x08}, + {0x3f03, 0x10}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x404e, 0x20}, + {0x4501, 0x00}, + {0x4502, 0x10}, + {0x4800, 0x00}, + {0x481f, 0x2a}, + {0x4837, 0x13}, + {0x5000, 0x13}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5b00, 0x00}, + {0x5b01, 0x1c}, + {0x5b02, 0x00}, + {0x5b03, 0x7f}, + {0x5b05, 0x6c}, + {0x5e10, 0xfc}, + {0x4010, 0xf1}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0xf8}, + {0x0100, 0x01}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 2232(0x8b8) + * grabwindow_width 1280 + * grabwindow_height 720 + * max_framerate 30fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_1280x720_regs[] = { + {0x3501, 0x45}, + {0x366e, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x01}, + {0x3803, 0x00}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x06}, + {0x3807, 0xaf}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x08}, + {0x380f, 0xb8}, + {0x3811, 0x06}, + {0x3813, 0x02}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3817, 0x01}, + {0x3820, 0x8b}, + {0x3821, 0x01}, + {0x4501, 0x00}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {REG_NULL, 0x00} +}; + +/* + * Xclk 24Mhz + * Pclk 45Mhz + * linelength 672(0x2a0) + * framelength 558(0x22e) + * grabwindow_width 640 + * grabwindow_height 480 + * max_framerate 120fps + * mipi_datarate per lane 840Mbps + */ +static const struct regval ov5695_640x480_regs[] = { + {0x3501, 0x22}, + {0x366e, 0x0c}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x08}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0xa7}, + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0xe0}, + {0x380c, 0x02}, + {0x380d, 0xa0}, + {0x380e, 0x02}, + {0x380f, 0x2e}, + {0x3811, 0x06}, + {0x3813, 0x04}, + {0x3814, 0x07}, + {0x3816, 0x05}, + {0x3817, 0x03}, + {0x3820, 0x8d}, + {0x3821, 0x01}, + {0x4501, 0x00}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {REG_NULL, 0x00} +}; + +static const struct ov5695_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02e4 * 4, + .vts_def = 0x07e8, + .reg_list = ov5695_2592x1944_regs, + }, + { + .width = 1920, + .height = 1080, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x08b8, + .reg_list = ov5695_1920x1080_regs, + }, + { + .width = 1296, + .height = 972, + .max_fps = 60, + .exp_def = 0x03e0, + .hts_def = 0x02e4 * 4, + .vts_def = 0x03f4, + .reg_list = ov5695_1296x972_regs, + }, + { + .width = 1280, + .height = 720, + .max_fps = 30, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x08b8, + .reg_list = ov5695_1280x720_regs, + }, + { + .width = 640, + .height = 480, + .max_fps = 120, + .exp_def = 0x0450, + .hts_def = 0x02a0 * 4, + .vts_def = 0x022e, + .reg_list = ov5695_640x480_regs, + }, +}; + +#define OV5695_LINK_FREQ_420MHZ 420000000 +static const s64 link_freq_menu_items[] = { + OV5695_LINK_FREQ_420MHZ +}; + +static const char * const ov5695_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +/* Write registers up to 4 at a time */ +static int ov5695_write_reg(struct i2c_client *client, u16 reg, + u32 len, u32 val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val_be = cpu_to_be32(val); + val_p = (u8 *)&val_be; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov5695_write_array(struct i2c_client *client, + const struct regval *regs) +{ + u32 i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) + ret = ov5695_write_reg(client, regs[i].addr, + OV5695_REG_VALUE_08BIT, regs[i].val); + + return ret; +} + +/* Read registers up to 4 at a time */ +static int ov5695_read_reg(struct i2c_client *client, u16 reg, unsigned int len, + u32 *val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +static int ov5695_get_reso_dist(const struct ov5695_mode *mode, + struct v4l2_mbus_framefmt *framefmt) +{ + return abs(mode->width - framefmt->width) + + abs(mode->height - framefmt->height); +} + +static const struct ov5695_mode * +ov5695_find_best_fit(struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt = &fmt->format; + int dist; + int cur_best_fit = 0; + int cur_best_fit_dist = -1; + int i; + + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + dist = ov5695_get_reso_dist(&supported_modes[i], framefmt); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + cur_best_fit = i; + } + } + + return &supported_modes[cur_best_fit]; +} + +static int ov5695_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + const struct ov5695_mode *mode; + s64 h_blank, vblank_def; + + mutex_lock(&ov5695->mutex); + + mode = ov5695_find_best_fit(fmt); + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; +#else + mutex_unlock(&ov5695->mutex); + return -ENOTTY; +#endif + } else { + ov5695->cur_mode = mode; + h_blank = mode->hts_def - mode->width; + __v4l2_ctrl_modify_range(ov5695->hblank, h_blank, + h_blank, 1, h_blank); + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov5695->vblank, vblank_def, + OV5695_VTS_MAX - mode->height, + 1, vblank_def); + } + + mutex_unlock(&ov5695->mutex); + + return 0; +} + +static int ov5695_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + const struct ov5695_mode *mode = ov5695->cur_mode; + + mutex_lock(&ov5695->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); +#else + mutex_unlock(&ov5695->mutex); + return -ENOTTY; +#endif + } else { + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.field = V4L2_FIELD_NONE; + } + mutex_unlock(&ov5695->mutex); + + return 0; +} + +static int ov5695_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = supported_modes[fse->index].width; + fse->max_height = supported_modes[fse->index].height; + fse->min_height = supported_modes[fse->index].height; + + return 0; +} + +static int ov5695_enable_test_pattern(struct ov5695 *ov5695, u32 pattern) +{ + u32 val; + + if (pattern) + val = (pattern - 1) | OV5695_TEST_PATTERN_ENABLE; + else + val = OV5695_TEST_PATTERN_DISABLE; + + return ov5695_write_reg(ov5695->client, OV5695_REG_TEST_PATTERN, + OV5695_REG_VALUE_08BIT, val); +} + +static int __ov5695_start_stream(struct ov5695 *ov5695) +{ + int ret; + + ret = ov5695_write_array(ov5695->client, ov5695_global_regs); + if (ret) + return ret; + ret = ov5695_write_array(ov5695->client, ov5695->cur_mode->reg_list); + if (ret) + return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&ov5695->ctrl_handler); + if (ret) + return ret; + + return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE, + OV5695_REG_VALUE_08BIT, OV5695_MODE_STREAMING); +} + +static int __ov5695_stop_stream(struct ov5695 *ov5695) +{ + return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE, + OV5695_REG_VALUE_08BIT, OV5695_MODE_SW_STANDBY); +} + +static int ov5695_s_stream(struct v4l2_subdev *sd, int on) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + struct i2c_client *client = ov5695->client; + int ret = 0; + + mutex_lock(&ov5695->mutex); + on = !!on; + if (on == ov5695->streaming) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = __ov5695_start_stream(ov5695); + if (ret) { + v4l2_err(sd, "start stream failed while write regs\n"); + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + } else { + __ov5695_stop_stream(ov5695); + pm_runtime_put(&client->dev); + } + + ov5695->streaming = on; + +unlock_and_return: + mutex_unlock(&ov5695->mutex); + + return ret; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 ov5695_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000); +} + +static int __ov5695_power_on(struct ov5695 *ov5695) +{ + int ret; + u32 delay_us; + struct device *dev = &ov5695->client->dev; + + ret = clk_prepare_enable(ov5695->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + gpiod_set_value_cansleep(ov5695->reset_gpio, 1); + + ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + gpiod_set_value_cansleep(ov5695->reset_gpio, 0); + + /* 8192 cycles prior to first SCCB transaction */ + delay_us = ov5695_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); + + return 0; + +disable_clk: + clk_disable_unprepare(ov5695->xvclk); + + return ret; +} + +static void __ov5695_power_off(struct ov5695 *ov5695) +{ + clk_disable_unprepare(ov5695->xvclk); + gpiod_set_value_cansleep(ov5695->reset_gpio, 1); + regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies); +} + +static int ov5695_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + return __ov5695_power_on(ov5695); +} + +static int ov5695_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + __ov5695_power_off(ov5695); + + return 0; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov5695 *ov5695 = to_ov5695(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + const struct ov5695_mode *def_mode = &supported_modes[0]; + + mutex_lock(&ov5695->mutex); + /* Initialize try_fmt */ + try_fmt->width = def_mode->width; + try_fmt->height = def_mode->height; + try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + try_fmt->field = V4L2_FIELD_NONE; + + mutex_unlock(&ov5695->mutex); + /* No crop or compose */ + + return 0; +} +#endif + +static const struct dev_pm_ops ov5695_pm_ops = { + SET_RUNTIME_PM_OPS(ov5695_runtime_suspend, + ov5695_runtime_resume, NULL) +}; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops ov5695_internal_ops = { + .open = ov5695_open, +}; +#endif + +static const struct v4l2_subdev_video_ops ov5695_video_ops = { + .s_stream = ov5695_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov5695_pad_ops = { + .enum_mbus_code = ov5695_enum_mbus_code, + .enum_frame_size = ov5695_enum_frame_sizes, + .get_fmt = ov5695_get_fmt, + .set_fmt = ov5695_set_fmt, +}; + +static const struct v4l2_subdev_ops ov5695_subdev_ops = { + .video = &ov5695_video_ops, + .pad = &ov5695_pad_ops, +}; + +static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5695 *ov5695 = container_of(ctrl->handler, + struct ov5695, ctrl_handler); + struct i2c_client *client = ov5695->client; + s64 max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = ov5695->cur_mode->height + ctrl->val - 4; + __v4l2_ctrl_modify_range(ov5695->exposure, + ov5695->exposure->minimum, max, + ov5695->exposure->step, + ov5695->exposure->default_value); + break; + } + + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of expsoure are fractional part */ + ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE, + OV5695_REG_VALUE_24BIT, ctrl->val << 4); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_ANALOG_GAIN, + OV5695_REG_VALUE_08BIT, ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_L, + OV5695_REG_VALUE_08BIT, + ctrl->val & OV5695_DIGI_GAIN_L_MASK); + ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H, + OV5695_REG_VALUE_08BIT, + ctrl->val >> OV5695_DIGI_GAIN_H_SHIFT); + break; + case V4L2_CID_VBLANK: + ret = ov5695_write_reg(ov5695->client, OV5695_REG_VTS, + OV5695_REG_VALUE_16BIT, + ctrl->val + ov5695->cur_mode->height); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov5695_enable_test_pattern(ov5695, ctrl->val); + break; + default: + dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + }; + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov5695_ctrl_ops = { + .s_ctrl = ov5695_set_ctrl, +}; + +static int ov5695_initialize_controls(struct ov5695 *ov5695) +{ + const struct ov5695_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + s64 exposure_max, vblank_def; + u32 h_blank; + int ret; + + handler = &ov5695->ctrl_handler; + mode = ov5695->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 8); + if (ret) + return ret; + handler->lock = &ov5695->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, OV5695_PIXEL_RATE, 1, OV5695_PIXEL_RATE); + + h_blank = mode->hts_def - mode->width; + ov5695->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov5695->hblank) + ov5695->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_def = mode->vts_def - mode->height; + ov5695->vblank = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV5695_VTS_MAX - mode->height, + 1, vblank_def); + + exposure_max = mode->vts_def - 4; + ov5695->exposure = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_EXPOSURE, OV5695_EXPOSURE_MIN, + exposure_max, OV5695_EXPOSURE_STEP, + mode->exp_def); + + ov5695->anal_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, ANALOG_GAIN_MIN, + ANALOG_GAIN_MAX, ANALOG_GAIN_STEP, + ANALOG_GAIN_DEFAULT); + + /* Digital gain */ + ov5695->digi_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, OV5695_DIGI_GAIN_MIN, + OV5695_DIGI_GAIN_MAX, OV5695_DIGI_GAIN_STEP, + OV5695_DIGI_GAIN_DEFAULT); + + ov5695->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &ov5695_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5695_test_pattern_menu) - 1, + 0, 0, ov5695_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_err(&ov5695->client->dev, + "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ov5695->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov5695_check_sensor_id(struct ov5695 *ov5695, + struct i2c_client *client) +{ + struct device *dev = &ov5695->client->dev; + u32 id = 0; + int ret; + + ret = ov5695_read_reg(client, OV5695_REG_CHIP_ID, + OV5695_REG_VALUE_24BIT, &id); + if (id != CHIP_ID) { + dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret); + return ret; + } + + dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); + + return 0; +} + +static int ov5695_configure_regulators(struct ov5695 *ov5695) +{ + int i; + + for (i = 0; i < OV5695_NUM_SUPPLIES; i++) + ov5695->supplies[i].supply = ov5695_supply_names[i]; + + return devm_regulator_bulk_get(&ov5695->client->dev, + OV5695_NUM_SUPPLIES, + ov5695->supplies); +} + +static int ov5695_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ov5695 *ov5695; + struct v4l2_subdev *sd; + int ret; + + ov5695 = devm_kzalloc(dev, sizeof(*ov5695), GFP_KERNEL); + if (!ov5695) + return -ENOMEM; + + ov5695->client = client; + ov5695->cur_mode = &supported_modes[0]; + + ov5695->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov5695->xvclk)) { + dev_err(dev, "Failed to get xvclk\n"); + return -EINVAL; + } + ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ); + if (ret < 0) { + dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); + return ret; + } + if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov5695->reset_gpio)) { + dev_err(dev, "Failed to get reset-gpios\n"); + return -EINVAL; + } + + ret = ov5695_configure_regulators(ov5695); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + + mutex_init(&ov5695->mutex); + + sd = &ov5695->subdev; + v4l2_i2c_subdev_init(sd, client, &ov5695_subdev_ops); + ret = ov5695_initialize_controls(ov5695); + if (ret) + goto err_destroy_mutex; + + ret = __ov5695_power_on(ov5695); + if (ret) + goto err_free_handler; + + ret = ov5695_check_sensor_id(ov5695, client); + if (ret) + goto err_power_off; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sd->internal_ops = &ov5695_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif +#if defined(CONFIG_MEDIA_CONTROLLER) + ov5695->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad); + if (ret < 0) + goto err_power_off; +#endif + + ret = v4l2_async_register_subdev(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +err_clean_entity: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif +err_power_off: + __ov5695_power_off(ov5695); +err_free_handler: + v4l2_ctrl_handler_free(&ov5695->ctrl_handler); +err_destroy_mutex: + mutex_destroy(&ov5695->mutex); + + return ret; +} + +static int ov5695_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5695 *ov5695 = to_ov5695(sd); + + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + v4l2_ctrl_handler_free(&ov5695->ctrl_handler); + mutex_destroy(&ov5695->mutex); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + __ov5695_power_off(ov5695); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov5695_of_match[] = { + { .compatible = "ovti,ov5695" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov5695_of_match); +#endif + +static struct i2c_driver ov5695_i2c_driver = { + .driver = { + .name = "ov5695", + .owner = THIS_MODULE, + .pm = &ov5695_pm_ops, + .of_match_table = of_match_ptr(ov5695_of_match), + }, + .probe = &ov5695_probe, + .remove = &ov5695_remove, +}; + +module_i2c_driver(ov5695_i2c_driver); + +MODULE_DESCRIPTION("OmniVision ov5695 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit From e3861d9118c815c4cf1ef2f7365005205c07c65a Mon Sep 17 00:00:00 2001 From: Shunqian Zheng Date: Tue, 16 Jan 2018 04:22:01 -0500 Subject: media: ov2685: add support for OV2685 sensor This patch adds driver for Omnivision's ov2685 sensor. Though the ov2685 can output yuv data, this driver only supports the raw bayer format, including the following features: - output 1600x1200 at 30fps - test patterns - manual exposure/gain control - vblank and hblank - media controller - runtime pm [Sakari Ailus: trivial: ov5695_of_match -> ov2685_of_match] Signed-off-by: Shunqian Zheng Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 12 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov2685.c | 845 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 858 insertions(+) create mode 100644 drivers/media/i2c/ov2685.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 00377fe06504..26549f765536 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -595,6 +595,18 @@ config VIDEO_OV2659 To compile this driver as a module, choose M here: the module will be called ov2659. +config VIDEO_OV2685 + tristate "OmniVision OV2685 sensor support" + depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV2685 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2685. + config VIDEO_OV5640 tristate "OmniVision OV5640 sensor support" depends on OF diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 0cef61e4bdcb..e4f420d730e8 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_OV2640) += ov2640.o +obj-$(CONFIG_VIDEO_OV2685) += ov2685.o obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c new file mode 100644 index 000000000000..df4abecd8d74 --- /dev/null +++ b/drivers/media/i2c/ov2685.c @@ -0,0 +1,845 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ov2685 driver + * + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHIP_ID 0x2685 +#define OV2685_REG_CHIP_ID 0x300a + +#define OV2685_XVCLK_FREQ 24000000 + +#define REG_SC_CTRL_MODE 0x0100 +#define SC_CTRL_MODE_STANDBY 0x0 +#define SC_CTRL_MODE_STREAMING BIT(0) + +#define OV2685_REG_EXPOSURE 0x3500 +#define OV2685_EXPOSURE_MIN 4 +#define OV2685_EXPOSURE_STEP 1 + +#define OV2685_REG_VTS 0x380e +#define OV2685_VTS_MAX 0x7fff + +#define OV2685_REG_GAIN 0x350a +#define OV2685_GAIN_MIN 0 +#define OV2685_GAIN_MAX 0x07ff +#define OV2685_GAIN_STEP 0x1 +#define OV2685_GAIN_DEFAULT 0x0036 + +#define OV2685_REG_TEST_PATTERN 0x5080 +#define OV2685_TEST_PATTERN_DISABLED 0x00 +#define OV2685_TEST_PATTERN_COLOR_BAR 0x80 +#define OV2685_TEST_PATTERN_RANDOM 0x81 +#define OV2685_TEST_PATTERN_COLOR_BAR_FADE 0x88 +#define OV2685_TEST_PATTERN_BW_SQUARE 0x92 +#define OV2685_TEST_PATTERN_COLOR_SQUARE 0x82 + +#define REG_NULL 0xFFFF + +#define OV2685_REG_VALUE_08BIT 1 +#define OV2685_REG_VALUE_16BIT 2 +#define OV2685_REG_VALUE_24BIT 3 + +#define OV2685_LANES 1 +#define OV2685_BITS_PER_SAMPLE 10 + +static const char * const ov2685_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names) + +struct regval { + u16 addr; + u8 val; +}; + +struct ov2685_mode { + u32 width; + u32 height; + u32 exp_def; + u32 hts_def; + u32 vts_def; + const struct regval *reg_list; +}; + +struct ov2685 { + struct i2c_client *client; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES]; + + bool streaming; + struct mutex mutex; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_ctrl *anal_gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl_handler ctrl_handler; + + const struct ov2685_mode *cur_mode; +}; + +#define to_ov2685(sd) container_of(sd, struct ov2685, subdev) + +/* PLL settings bases on 24M xvclk */ +static struct regval ov2685_1600x1200_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x3002, 0x00}, + {0x3016, 0x1c}, + {0x3018, 0x44}, + {0x301d, 0xf0}, + {0x3020, 0x00}, + {0x3082, 0x37}, + {0x3083, 0x03}, + {0x3084, 0x09}, + {0x3085, 0x04}, + {0x3086, 0x00}, + {0x3087, 0x00}, + {0x3501, 0x4e}, + {0x3502, 0xe0}, + {0x3503, 0x07}, + {0x350b, 0x36}, + {0x3600, 0xb4}, + {0x3603, 0x35}, + {0x3604, 0x24}, + {0x3605, 0x00}, + {0x3620, 0x24}, + {0x3621, 0x34}, + {0x3622, 0x03}, + {0x3628, 0x10}, + {0x3705, 0x3c}, + {0x370a, 0x21}, + {0x370c, 0x50}, + {0x370d, 0xc0}, + {0x3717, 0x58}, + {0x3718, 0x80}, + {0x3720, 0x00}, + {0x3721, 0x09}, + {0x3722, 0x06}, + {0x3723, 0x59}, + {0x3738, 0x99}, + {0x3781, 0x80}, + {0x3784, 0x0c}, + {0x3789, 0x60}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x06}, + {0x3805, 0x4f}, + {0x3806, 0x04}, + {0x3807, 0xbf}, + {0x3808, 0x06}, + {0x3809, 0x40}, + {0x380a, 0x04}, + {0x380b, 0xb0}, + {0x380c, 0x06}, + {0x380d, 0xa4}, + {0x380e, 0x05}, + {0x380f, 0x0e}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3819, 0x04}, + {0x3820, 0xc0}, + {0x3821, 0x00}, + {0x3a06, 0x01}, + {0x3a07, 0x84}, + {0x3a08, 0x01}, + {0x3a09, 0x43}, + {0x3a0a, 0x24}, + {0x3a0b, 0x60}, + {0x3a0c, 0x28}, + {0x3a0d, 0x60}, + {0x3a0e, 0x04}, + {0x3a0f, 0x8c}, + {0x3a10, 0x05}, + {0x3a11, 0x0c}, + {0x4000, 0x81}, + {0x4001, 0x40}, + {0x4008, 0x02}, + {0x4009, 0x09}, + {0x4300, 0x00}, + {0x430e, 0x00}, + {0x4602, 0x02}, + {0x481b, 0x40}, + {0x481f, 0x40}, + {0x4837, 0x18}, + {0x5000, 0x1f}, + {0x5001, 0x05}, + {0x5002, 0x30}, + {0x5003, 0x04}, + {0x5004, 0x00}, + {0x5005, 0x0c}, + {0x5280, 0x15}, + {0x5281, 0x06}, + {0x5282, 0x06}, + {0x5283, 0x08}, + {0x5284, 0x1c}, + {0x5285, 0x1c}, + {0x5286, 0x20}, + {0x5287, 0x10}, + {REG_NULL, 0x00} +}; + +#define OV2685_LINK_FREQ_330MHZ 330000000 +static const s64 link_freq_menu_items[] = { + OV2685_LINK_FREQ_330MHZ +}; + +static const char * const ov2685_test_pattern_menu[] = { + "Disabled", + "Color Bar", + "Color Bar FADE", + "Random Data", + "Black White Square", + "Color Square" +}; + +static const int ov2685_test_pattern_val[] = { + OV2685_TEST_PATTERN_DISABLED, + OV2685_TEST_PATTERN_COLOR_BAR, + OV2685_TEST_PATTERN_COLOR_BAR_FADE, + OV2685_TEST_PATTERN_RANDOM, + OV2685_TEST_PATTERN_BW_SQUARE, + OV2685_TEST_PATTERN_COLOR_SQUARE, +}; + +static const struct ov2685_mode supported_modes[] = { + { + .width = 1600, + .height = 1200, + .exp_def = 0x04ee, + .hts_def = 0x06a4, + .vts_def = 0x050e, + .reg_list = ov2685_1600x1200_regs, + }, +}; + +/* Write registers up to 4 at a time */ +static int ov2685_write_reg(struct i2c_client *client, u16 reg, + u32 len, u32 val) +{ + u32 val_i, buf_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val_be = cpu_to_be32(val); + val_p = (u8 *)&val_be; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov2685_write_array(struct i2c_client *client, + const struct regval *regs) +{ + int ret = 0; + u32 i; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) + ret = ov2685_write_reg(client, regs[i].addr, + OV2685_REG_VALUE_08BIT, regs[i].val); + + return ret; +} + +/* Read registers up to 4 at a time */ +static int ov2685_read_reg(struct i2c_client *client, u16 reg, + u32 len, u32 *val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +static void ov2685_fill_fmt(const struct ov2685_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov2685_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + + /* only one mode supported for now */ + ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt); + + return 0; +} + +static int ov2685_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + + ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt); + + return 0; +} + +static int ov2685_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + fse->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + fse->min_width = supported_modes[index].width; + fse->max_width = supported_modes[index].width; + fse->max_height = supported_modes[index].height; + fse->min_height = supported_modes[index].height; + + return 0; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 ov2685_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000); +} + +static int __ov2685_power_on(struct ov2685 *ov2685) +{ + int ret; + u32 delay_us; + struct device *dev = &ov2685->client->dev; + + ret = clk_prepare_enable(ov2685->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + gpiod_set_value_cansleep(ov2685->reset_gpio, 1); + + ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + /* The minimum delay between power supplies and reset rising can be 0 */ + gpiod_set_value_cansleep(ov2685->reset_gpio, 0); + /* 8192 xvclk cycles prior to the first SCCB transaction */ + delay_us = ov2685_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); + + /* HACK: ov2685 would output messy data after reset(R0103), + * writing register before .s_stream() as a workaround + */ + ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list); + if (ret) + goto disable_supplies; + + return 0; + +disable_supplies: + regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies); +disable_clk: + clk_disable_unprepare(ov2685->xvclk); + + return ret; +} + +static void __ov2685_power_off(struct ov2685 *ov2685) +{ + /* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */ + u32 delay_us = ov2685_cal_delay(512); + + usleep_range(delay_us, delay_us * 2); + clk_disable_unprepare(ov2685->xvclk); + gpiod_set_value_cansleep(ov2685->reset_gpio, 1); + regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies); +} + +static int ov2685_s_stream(struct v4l2_subdev *sd, int on) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct i2c_client *client = ov2685->client; + int ret = 0; + + mutex_lock(&ov2685->mutex); + + on = !!on; + if (on == ov2685->streaming) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&ov2685->client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler); + if (ret) { + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + ret = ov2685_write_reg(client, REG_SC_CTRL_MODE, + OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING); + if (ret) { + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + } else { + ov2685_write_reg(client, REG_SC_CTRL_MODE, + OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY); + pm_runtime_put(&ov2685->client->dev); + } + + ov2685->streaming = on; + +unlock_and_return: + mutex_unlock(&ov2685->mutex); + + return ret; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov2685 *ov2685 = to_ov2685(sd); + struct v4l2_mbus_framefmt *try_fmt; + + mutex_lock(&ov2685->mutex); + + try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0); + /* Initialize try_fmt */ + ov2685_fill_fmt(&supported_modes[0], try_fmt); + + mutex_unlock(&ov2685->mutex); + + return 0; +} +#endif + +static int ov2685_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + return __ov2685_power_on(ov2685); +} + +static int ov2685_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + __ov2685_power_off(ov2685); + + return 0; +} + +static const struct dev_pm_ops ov2685_pm_ops = { + SET_RUNTIME_PM_OPS(ov2685_runtime_suspend, + ov2685_runtime_resume, NULL) +}; + +static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2685 *ov2685 = container_of(ctrl->handler, + struct ov2685, ctrl_handler); + struct i2c_client *client = ov2685->client; + s64 max_expo; + int ret; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max_expo = ov2685->cur_mode->height + ctrl->val - 4; + __v4l2_ctrl_modify_range(ov2685->exposure, + ov2685->exposure->minimum, max_expo, + ov2685->exposure->step, + ov2685->exposure->default_value); + break; + } + + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE, + OV2685_REG_VALUE_24BIT, ctrl->val << 4); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN, + OV2685_REG_VALUE_16BIT, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS, + OV2685_REG_VALUE_16BIT, + ctrl->val + ov2685->cur_mode->height); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN, + OV2685_REG_VALUE_08BIT, + ov2685_test_pattern_val[ctrl->val]); + break; + default: + dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + }; + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops ov2685_video_ops = { + .s_stream = ov2685_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov2685_pad_ops = { + .enum_mbus_code = ov2685_enum_mbus_code, + .enum_frame_size = ov2685_enum_frame_sizes, + .get_fmt = ov2685_get_fmt, + .set_fmt = ov2685_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2685_subdev_ops = { + .video = &ov2685_video_ops, + .pad = &ov2685_pad_ops, +}; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops ov2685_internal_ops = { + .open = ov2685_open, +}; +#endif + +static const struct v4l2_ctrl_ops ov2685_ctrl_ops = { + .s_ctrl = ov2685_set_ctrl, +}; + +static int ov2685_initialize_controls(struct ov2685 *ov2685) +{ + const struct ov2685_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + u64 exposure_max; + u32 pixel_rate, h_blank; + int ret; + + handler = &ov2685->ctrl_handler; + mode = ov2685->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 8); + if (ret) + return ret; + handler->lock = &ov2685->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = (link_freq_menu_items[0] * 2 * OV2685_LANES) / + OV2685_BITS_PER_SAMPLE; + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts_def - mode->width; + ov2685->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov2685->hblank) + ov2685->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov2685->vblank = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_VBLANK, mode->vts_def - mode->height, + OV2685_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + + exposure_max = mode->vts_def - 4; + ov2685->exposure = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_EXPOSURE, OV2685_EXPOSURE_MIN, + exposure_max, OV2685_EXPOSURE_STEP, + mode->exp_def); + + ov2685->anal_gain = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, OV2685_GAIN_MIN, + OV2685_GAIN_MAX, OV2685_GAIN_STEP, + OV2685_GAIN_DEFAULT); + + ov2685->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &ov2685_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2685_test_pattern_menu) - 1, + 0, 0, ov2685_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_err(&ov2685->client->dev, + "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ov2685->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov2685_check_sensor_id(struct ov2685 *ov2685, + struct i2c_client *client) +{ + struct device *dev = &ov2685->client->dev; + int ret; + u32 id = 0; + + ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID, + OV2685_REG_VALUE_16BIT, &id); + if (id != CHIP_ID) { + dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret); + return ret; + } + + dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID); + + return 0; +} + +static int ov2685_configure_regulators(struct ov2685 *ov2685) +{ + int i; + + for (i = 0; i < OV2685_NUM_SUPPLIES; i++) + ov2685->supplies[i].supply = ov2685_supply_names[i]; + + return devm_regulator_bulk_get(&ov2685->client->dev, + OV2685_NUM_SUPPLIES, + ov2685->supplies); +} + +static int ov2685_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ov2685 *ov2685; + int ret; + + ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL); + if (!ov2685) + return -ENOMEM; + + ov2685->client = client; + ov2685->cur_mode = &supported_modes[0]; + + ov2685->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov2685->xvclk)) { + dev_err(dev, "Failed to get xvclk\n"); + return -EINVAL; + } + ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ); + if (ret < 0) { + dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); + return ret; + } + if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov2685->reset_gpio)) { + dev_err(dev, "Failed to get reset-gpios\n"); + return -EINVAL; + } + + ret = ov2685_configure_regulators(ov2685); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + + mutex_init(&ov2685->mutex); + v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops); + ret = ov2685_initialize_controls(ov2685); + if (ret) + goto err_destroy_mutex; + + ret = __ov2685_power_on(ov2685); + if (ret) + goto err_free_handler; + + ret = ov2685_check_sensor_id(ov2685, client); + if (ret) + goto err_power_off; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + ov2685->subdev.internal_ops = &ov2685_internal_ops; + ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif +#if defined(CONFIG_MEDIA_CONTROLLER) + ov2685->pad.flags = MEDIA_PAD_FL_SOURCE; + ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad); + if (ret < 0) + goto err_power_off; +#endif + + ret = v4l2_async_register_subdev(&ov2685->subdev); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +err_clean_entity: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&ov2685->subdev.entity); +#endif +err_power_off: + __ov2685_power_off(ov2685); +err_free_handler: + v4l2_ctrl_handler_free(&ov2685->ctrl_handler); +err_destroy_mutex: + mutex_destroy(&ov2685->mutex); + + return ret; +} + +static int ov2685_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2685 *ov2685 = to_ov2685(sd); + + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + v4l2_ctrl_handler_free(&ov2685->ctrl_handler); + mutex_destroy(&ov2685->mutex); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + __ov2685_power_off(ov2685); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2685_of_match[] = { + { .compatible = "ovti,ov2685" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov2685_of_match); +#endif + +static struct i2c_driver ov2685_i2c_driver = { + .driver = { + .name = "ov2685", + .owner = THIS_MODULE, + .pm = &ov2685_pm_ops, + .of_match_table = of_match_ptr(ov2685_of_match), + }, + .probe = &ov2685_probe, + .remove = &ov2685_remove, +}; + +module_i2c_driver(ov2685_i2c_driver); + +MODULE_DESCRIPTION("OmniVision ov2685 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit From c723001f3b5951bd017b2a24360ad188f488e994 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 19 Jan 2018 05:49:02 -0500 Subject: media: ov2685: Assign ret in default case in s_ctrl callback Assign ret in the default case for s_ctrl callback. This can't happen but still may result in compiler warnings. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2685.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index df4abecd8d74..904ac305d499 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -574,6 +574,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) default: dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); + ret = -EINVAL; break; }; -- cgit From d365bc92475205312c0064e92398ead059156bd9 Mon Sep 17 00:00:00 2001 From: Chiranjeevi Rapolu Date: Wed, 24 Jan 2018 23:34:39 -0500 Subject: media: ov13858: Avoid possible null first frame Previously, the sensor, with default settings, was outputting SOF without data. This results in frame sync error on the receiver side. Now, configure the sensor to output SOF with MIPI data for all frames. This avoids possible null first frame on the bus. Signed-off-by: Chiranjeevi Rapolu Signed-off-by: Tianshu Qiu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index bf7d06f3f21a..2964d5cae1fb 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -194,6 +194,7 @@ static const struct ov13858_reg mode_4224x3136_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x12}, {0x3664, 0x73}, @@ -384,6 +385,7 @@ static const struct ov13858_reg mode_2112x1568_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x10}, {0x3664, 0x73}, @@ -574,6 +576,7 @@ static const struct ov13858_reg mode_2112x1188_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x10}, {0x3664, 0x73}, @@ -764,6 +767,7 @@ static const struct ov13858_reg mode_1056x784_regs[] = { {0x3624, 0x1c}, {0x3640, 0x10}, {0x3641, 0x70}, + {0x3660, 0x04}, {0x3661, 0x80}, {0x3662, 0x08}, {0x3664, 0x73}, -- cgit From f4b32c292aa66788ba7d4db54a76b4a08f60784a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 12:49:29 -0500 Subject: media: ov13858: Use false for boolean value Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 2964d5cae1fb..1f260d346a29 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1569,7 +1569,7 @@ static int __maybe_unused ov13858_resume(struct device *dev) error: ov13858_stop_streaming(ov13858); - ov13858->streaming = 0; + ov13858->streaming = false; return ret; } -- cgit From b1f5d0ae930d92bfddb74e99324542456083141a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 21 Jan 2018 10:14:14 -0500 Subject: media: ov9650: support device tree probing The ov9650 driver currently only supports legacy platform data probe. This change adds device tree probing. There has been an attempt to add device tree support for ov9650 driver by Hugues Fruchet as a part of the patchset that adds support of OV9655 camera (http://www.spinics.net/lists/linux-media/msg117903.html), but it wasn't merged into mainline because creating a separate driver for OV9655 is preferred. This is very similar to Hugues's patch, but not supporting new device. Cc: Jacopo Mondi Cc: H. Nikolaus Schaller Cc: Hugues Fruchet Cc: Mauro Carvalho Chehab Cc: Rob Herring Reviewed-by: Sylwester Nawrocki Signed-off-by: Akinobu Mita Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9650.c | 130 ++++++++++++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 38 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index e519f278d5f9..bfd90162a297 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -11,8 +11,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include +#include #include #include #include @@ -249,9 +251,10 @@ struct ov965x { struct v4l2_subdev sd; struct media_pad pad; enum v4l2_mbus_type bus_type; - int gpios[NUM_GPIOS]; + struct gpio_desc *gpios[NUM_GPIOS]; /* External master clock frequency */ unsigned long mclk_frequency; + struct clk *clk; /* Protects the struct fields below */ struct mutex lock; @@ -513,24 +516,27 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x) return 0; } -static void ov965x_gpio_set(int gpio, int val) -{ - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, val); -} - -static void __ov965x_set_power(struct ov965x *ov965x, int on) +static int __ov965x_set_power(struct ov965x *ov965x, int on) { if (on) { - ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 0); - ov965x_gpio_set(ov965x->gpios[GPIO_RST], 0); + int ret = clk_prepare_enable(ov965x->clk); + + if (ret) + return ret; + + gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 0); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 0); msleep(25); } else { - ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1); - ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 1); + gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 1); + + clk_disable_unprepare(ov965x->clk); } ov965x->streaming = 0; + + return 0; } static int ov965x_s_power(struct v4l2_subdev *sd, int on) @@ -543,8 +549,8 @@ static int ov965x_s_power(struct v4l2_subdev *sd, int on) mutex_lock(&ov965x->lock); if (ov965x->power == !on) { - __ov965x_set_power(ov965x, on); - if (on) { + ret = __ov965x_set_power(ov965x, on); + if (!ret && on) { ret = ov965x_write_array(client, ov965x_init_regs); ov965x->apply_frame_fmt = 1; @@ -1410,16 +1416,17 @@ static const struct v4l2_subdev_ops ov965x_subdev_ops = { /* * Reset and power down GPIOs configuration */ -static int ov965x_configure_gpios(struct ov965x *ov965x, - const struct ov9650_platform_data *pdata) +static int ov965x_configure_gpios_pdata(struct ov965x *ov965x, + const struct ov9650_platform_data *pdata) { int ret, i; + int gpios[NUM_GPIOS]; - ov965x->gpios[GPIO_PWDN] = pdata->gpio_pwdn; - ov965x->gpios[GPIO_RST] = pdata->gpio_reset; + gpios[GPIO_PWDN] = pdata->gpio_pwdn; + gpios[GPIO_RST] = pdata->gpio_reset; for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) { - int gpio = ov965x->gpios[i]; + int gpio = gpios[i]; if (!gpio_is_valid(gpio)) continue; @@ -1429,9 +1436,30 @@ static int ov965x_configure_gpios(struct ov965x *ov965x, return ret; v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio); - gpio_set_value(gpio, 1); + gpio_set_value_cansleep(gpio, 1); gpio_export(gpio, 0); - ov965x->gpios[i] = gpio; + ov965x->gpios[i] = gpio_to_desc(gpio); + } + + return 0; +} + +static int ov965x_configure_gpios(struct ov965x *ov965x) +{ + struct device *dev = &ov965x->client->dev; + + ov965x->gpios[GPIO_PWDN] = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov965x->gpios[GPIO_PWDN])) { + dev_info(dev, "can't get %s GPIO\n", "powerdown"); + return PTR_ERR(ov965x->gpios[GPIO_PWDN]); + } + + ov965x->gpios[GPIO_RST] = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov965x->gpios[GPIO_RST])) { + dev_info(dev, "can't get %s GPIO\n", "reset"); + return PTR_ERR(ov965x->gpios[GPIO_RST]); } return 0; @@ -1445,7 +1473,10 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) int ret; mutex_lock(&ov965x->lock); - __ov965x_set_power(ov965x, 1); + ret = __ov965x_set_power(ov965x, 1); + if (ret) + goto out; + msleep(25); /* Check sensor revision */ @@ -1465,6 +1496,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd) ret = -ENODEV; } } +out: mutex_unlock(&ov965x->lock); return ret; @@ -1478,23 +1510,39 @@ static int ov965x_probe(struct i2c_client *client, struct ov965x *ov965x; int ret; - if (!pdata) { - dev_err(&client->dev, "platform data not specified\n"); - return -EINVAL; - } - - if (pdata->mclk_frequency == 0) { - dev_err(&client->dev, "MCLK frequency not specified\n"); - return -EINVAL; - } - ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL); if (!ov965x) return -ENOMEM; - mutex_init(&ov965x->lock); ov965x->client = client; - ov965x->mclk_frequency = pdata->mclk_frequency; + + if (pdata) { + if (pdata->mclk_frequency == 0) { + dev_err(&client->dev, "MCLK frequency not specified\n"); + return -EINVAL; + } + ov965x->mclk_frequency = pdata->mclk_frequency; + + ret = ov965x_configure_gpios_pdata(ov965x, pdata); + if (ret < 0) + return ret; + } else if (dev_fwnode(&client->dev)) { + ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL); + if (IS_ERR(ov965x->clk)) + return PTR_ERR(ov965x->clk); + ov965x->mclk_frequency = clk_get_rate(ov965x->clk); + + ret = ov965x_configure_gpios(ov965x); + if (ret < 0) + return ret; + } else { + dev_err(&client->dev, + "Neither platform data nor device property specified\n"); + + return -EINVAL; + } + + mutex_init(&ov965x->lock); sd = &ov965x->sd; v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops); @@ -1504,10 +1552,6 @@ static int ov965x_probe(struct i2c_client *client, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - ret = ov965x_configure_gpios(ov965x, pdata); - if (ret < 0) - goto err_mutex; - ov965x->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad); @@ -1563,9 +1607,19 @@ static const struct i2c_device_id ov965x_id[] = { }; MODULE_DEVICE_TABLE(i2c, ov965x_id); +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov965x_of_match[] = { + { .compatible = "ovti,ov9650", }, + { .compatible = "ovti,ov9652", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov965x_of_match); +#endif + static struct i2c_driver ov965x_i2c_driver = { .driver = { .name = DRIVER_NAME, + .of_match_table = of_match_ptr(ov965x_of_match), }, .probe = ov965x_probe, .remove = ov965x_remove, -- cgit From 36e49ffb978ef7284ae235b915a7bd6713aa20de Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jan 2018 19:32:01 -0500 Subject: media: i2c: ov9650: fix potential integer overflow in __ov965x_set_frame_interval Cast fi->interval.numerator to u64 in order to avoid a potential integer overflow. This variable is being used in a context that expects an expression of type u64. Addresses-Coverity-ID: 1324146 ("Unintentional integer overflow") [Sakari Ailus: use do_div() to make this work on 32-bit systems] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9650.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index bfd90162a297..5bea31cd41aa 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1136,8 +1136,8 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x, if (fi->interval.denominator == 0) return -EINVAL; - req_int = (u64)(fi->interval.numerator * 10000) / - fi->interval.denominator; + req_int = (u64)fi->interval.numerator * 10000; + do_div(req_int, fi->interval.denominator); for (i = 0; i < ARRAY_SIZE(ov965x_intervals); i++) { const struct ov965x_interval *iv = &ov965x_intervals[i]; -- cgit From 01b8444828fc04b27b90bfebb50006219e930433 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 24 Jan 2018 04:30:50 -0500 Subject: media: v4l2: i2c: ov7670: Implement OF mbus configuration ov7670 driver supports two optional properties supplied through platform data, but currently does not support any standard video interface property. Add support through OF parsing for 2 generic properties (vsync and hsync polarities) and for one custom property already supported through platform data to suppress pixel clock output during horizontal blanking. While at there, check return value of register writes in set_fmt function and rationalize spacings. Signal polarities and pixel clock blanking verified through scope and image capture. Signed-off-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/ov7670.c | 98 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 26549f765536..ef2e1dea253b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -692,6 +692,7 @@ config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE ---help--- This is a Video4Linux2 sensor-level driver for the OmniVision OV7670 VGA camera. It currently only works with the M88ALP01 diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 31b0c33cfc5b..3474ef832c1e 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +243,7 @@ struct ov7670_info { struct clk *clk; struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; + unsigned int mbus_config; /* Media bus configuration flags */ int min_width; /* Filter out smaller sizes */ int min_height; /* Filter out smaller sizes */ int clock_speed; /* External clock speed (MHz) */ @@ -1014,7 +1016,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; #endif - unsigned char com7; + unsigned char com7, com10 = 0; int ret; if (format->pad) @@ -1034,7 +1036,6 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, } ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); - if (ret) return ret; /* @@ -1045,16 +1046,41 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, */ com7 = ovfmt->regs[0].value; com7 |= wsize->com7_bit; - ov7670_write(sd, REG_COM7, com7); + ret = ov7670_write(sd, REG_COM7, com7); + if (ret) + return ret; + + /* + * Configure the media bus through COM10 register + */ + if (info->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW) + com10 |= COM10_VS_NEG; + if (info->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW) + com10 |= COM10_HREF_REV; + if (info->pclk_hb_disable) + com10 |= COM10_PCLK_HB; + ret = ov7670_write(sd, REG_COM10, com10); + if (ret) + return ret; + /* * Now write the rest of the array. Also store start/stops */ - ov7670_write_array(sd, ovfmt->regs + 1); - ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, - wsize->vstop); - ret = 0; - if (wsize->regs) + ret = ov7670_write_array(sd, ovfmt->regs + 1); + if (ret) + return ret; + + ret = ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, + wsize->vstop); + if (ret) + return ret; + + if (wsize->regs) { ret = ov7670_write_array(sd, wsize->regs); + if (ret) + return ret; + } + info->fmt = ovfmt; /* @@ -1067,8 +1093,10 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, * to write it unconditionally, and that will make the frame * rate persistent too. */ - if (ret == 0) - ret = ov7670_write(sd, REG_CLKRC, info->clkrc); + ret = ov7670_write(sd, REG_CLKRC, info->clkrc); + if (ret) + return ret; + return 0; } @@ -1692,6 +1720,45 @@ static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info) return 0; } +/* + * ov7670_parse_dt() - Parse device tree to collect mbus configuration + * properties + */ +static int ov7670_parse_dt(struct device *dev, + struct ov7670_info *info) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg; + struct fwnode_handle *ep; + int ret; + + if (!fwnode) + return -EINVAL; + + info->pclk_hb_disable = false; + if (fwnode_property_present(fwnode, "ov7670,pclk-hb-disable")) + info->pclk_hb_disable = true; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_parse(ep, &bus_cfg); + if (ret) { + fwnode_handle_put(ep); + return ret; + } + + if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) { + dev_err(dev, "Unsupported media bus type\n"); + fwnode_handle_put(ep); + return ret; + } + info->mbus_config = bus_cfg.bus.parallel.flags; + + return 0; +} + static int ov7670_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1712,7 +1779,13 @@ static int ov7670_probe(struct i2c_client *client, #endif info->clock_speed = 30; /* default: a guess */ - if (client->dev.platform_data) { + + if (dev_fwnode(&client->dev)) { + ret = ov7670_parse_dt(&client->dev, info); + if (ret) + return ret; + + } else if (client->dev.platform_data) { struct ov7670_config *config = client->dev.platform_data; /* @@ -1779,9 +1852,6 @@ static int ov7670_probe(struct i2c_client *client, tpf.denominator = 30; info->devtype->set_framerate(sd, &tpf); - if (info->pclk_hb_disable) - ov7670_write(sd, REG_COM10, COM10_PCLK_HB); - v4l2_ctrl_handler_init(&info->hdl, 10); v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); -- cgit From d47c412639f0d283f377ff01d9e6a9cfa44f2adc Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 31 Jan 2018 04:08:10 -0500 Subject: media: ov5640: add JPEG support Add YUV422 encoded JPEG support. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index e2dd352224c7..99a590263070 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -34,6 +34,8 @@ #define OV5640_DEFAULT_SLAVE_ID 0x3c +#define OV5640_REG_SYS_RESET02 0x3002 +#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 #define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_CHIP_ID 0x300a #define OV5640_REG_IO_MIPI_CTRL00 0x300e @@ -114,6 +116,7 @@ struct ov5640_pixfmt { }; static const struct ov5640_pixfmt ov5640_formats[] = { + { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, @@ -1915,6 +1918,7 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, { int ret = 0; bool is_rgb = false; + bool is_jpeg = false; u8 val; switch (format->code) { @@ -1936,6 +1940,11 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, val = 0x61; is_rgb = true; break; + case MEDIA_BUS_FMT_JPEG_1X8: + /* YUV422, YUYV */ + val = 0x30; + is_jpeg = true; + break; default: return -EINVAL; } @@ -1946,8 +1955,40 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - return ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, - is_rgb ? 0x01 : 0x00); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, + is_rgb ? 0x01 : 0x00); + if (ret) + return ret; + + /* + * TIMING TC REG21: + * - [5]: JPEG enable + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, + BIT(5), is_jpeg ? BIT(5) : 0); + if (ret) + return ret; + + /* + * SYSTEM RESET02: + * - [4]: Reset JFIFO + * - [3]: Reset SFIFO + * - [2]: Reset JPEG + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, + BIT(4) | BIT(3) | BIT(2), + is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); + if (ret) + return ret; + + /* + * CLOCK ENABLE02: + * - [5]: Enable JPEG 2x clock + * - [3]: Enable JPEG clock + */ + return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, + BIT(5) | BIT(3), + is_jpeg ? (BIT(5) | BIT(3)) : 0); } /* -- cgit From 3924c62383ade455d6242f2b017cb67b92aa50a7 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 31 Jan 2018 07:46:17 -0500 Subject: media: ov5640: add error trace in case of i2c read failure Add an error trace in ov5640_read_reg() in case of i2c_transfer() failure. Uniformize error traces using dev_err instead v4l2_err. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 99a590263070..6f1846081dbe 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -839,7 +839,7 @@ static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) ret = i2c_transfer(client->adapter, &msg, 1); if (ret < 0) { - v4l2_err(&sensor->sd, "%s: error: reg=%x, val=%x\n", + dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", __func__, reg, val); return ret; } @@ -868,8 +868,11 @@ static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) msg[1].len = 1; ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) + if (ret < 0) { + dev_err(&client->dev, "%s: error: reg=%x\n", + __func__, reg); return ret; + } *val = buf[0]; return 0; -- cgit From 41d8d7f517126fa104a67c2b0cc23cf5c12fadc4 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 1 Feb 2018 03:44:06 -0500 Subject: media: ov5640: various typo & style fixes Various typo & style fixes either detected by code review or checkpatch. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 6f1846081dbe..696a28bde1b4 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -14,14 +14,14 @@ #include #include #include +#include #include #include #include #include +#include #include #include -#include -#include #include #include #include @@ -139,7 +139,7 @@ static const int ov5640_framerates[] = { /* regulator supplies */ static const char * const ov5640_supply_name[] = { - "DOVDD", /* Digital I/O (1.8V) suppply */ + "DOVDD", /* Digital I/O (1.8V) supply */ "DVDD", /* Digital Core (1.5V) supply */ "AVDD", /* Analog (2.8V) supply */ }; @@ -245,7 +245,6 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) */ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { - {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, @@ -334,7 +333,6 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { }; static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = { - {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, @@ -377,7 +375,6 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = { }; static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { - {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, @@ -484,6 +481,7 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; + static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, @@ -886,7 +884,7 @@ static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) ret = ov5640_read_reg(sensor, reg, &hi); if (ret) return ret; - ret = ov5640_read_reg(sensor, reg+1, &lo); + ret = ov5640_read_reg(sensor, reg + 1, &lo); if (ret) return ret; @@ -947,7 +945,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, break; if (delay_ms) - usleep_range(1000*delay_ms, 1000*delay_ms+100); + usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } return ret; @@ -1289,7 +1287,6 @@ static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) return ret; prev_vts = ret; - /* calculate banding filter */ /* 60Hz */ band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; @@ -1405,8 +1402,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, * sensor changes between scaling and subsampling, go through * exposure calculation */ -static int ov5640_set_mode_exposure_calc( - struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) +static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) { u32 prev_shutter, prev_gain16; u32 cap_shutter, cap_gain16; @@ -1416,7 +1413,7 @@ static int ov5640_set_mode_exposure_calc( u8 average; int ret; - if (mode->reg_data == NULL) + if (!mode->reg_data) return -EINVAL; /* read preview shutter */ @@ -1570,7 +1567,7 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, { int ret; - if (mode->reg_data == NULL) + if (!mode->reg_data) return -EINVAL; /* Write capture setting */ @@ -2117,7 +2114,8 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, int auto_gain) if (ctrls->auto_gain->is_new) { ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, - BIT(1), ctrls->auto_gain->val ? 0 : BIT(1)); + BIT(1), + ctrls->auto_gain->val ? 0 : BIT(1)); if (ret) return ret; } @@ -2297,10 +2295,12 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= OV5640_NUM_MODES) return -EINVAL; - fse->min_width = fse->max_width = + fse->min_width = ov5640_mode_data[0][fse->index].width; - fse->min_height = fse->max_height = + fse->max_width = fse->min_width; + fse->min_height = ov5640_mode_data[0][fse->index].height; + fse->max_height = fse->min_height; return 0; } @@ -2376,8 +2376,8 @@ out: } static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { if (code->pad != 0) return -EINVAL; -- cgit From 8670d70a4286fc9be47f4c9654e071bce97111f2 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Tue, 6 Feb 2018 08:24:09 -0500 Subject: media: ov5640: fix virtual_channel parameter permissions Fix module_param(virtual_channel) permissions. This problem was detected by checkpatch: $ scripts/checkpatch.pl -f drivers/media/i2c/ov5640.c ERROR: Use 4 digit octal (0777) not decimal permissions +module_param(virtual_channel, int, 0); Also add an error trace in case of virtual_channel not in the valid range of values. Signed-off-by: Hugues Fruchet Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 696a28bde1b4..3e7b43ce2b7a 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -128,7 +128,7 @@ static const struct ov5640_pixfmt ov5640_formats[] = { * to set the MIPI CSI-2 virtual channel. */ static unsigned int virtual_channel; -module_param(virtual_channel, int, 0); +module_param(virtual_channel, uint, 0444); MODULE_PARM_DESC(virtual_channel, "MIPI CSI-2 virtual channel (0..3), default 0"); @@ -1358,11 +1358,16 @@ static int ov5640_binning_on(struct ov5640_dev *sensor) static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) { + struct i2c_client *client = sensor->i2c_client; u8 temp, channel = virtual_channel; int ret; - if (channel > 3) + if (channel > 3) { + dev_err(&client->dev, + "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", + __func__, channel); return -EINVAL; + } ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); if (ret) -- cgit From 3b498424002755b06a86d56acf9e4c8e5e5085ff Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 8 Feb 2018 07:22:14 -0500 Subject: media: ov5640: fix framerate update After a framerate update through s_frame_interval(), the new framerate was not taken into account when streaming, but was taken into account on next session. This was due to sensor->current_mode not updated accordingly to new framerate setting in ov5640_s_frame_interval(). Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 3e7b43ce2b7a..03940f0cdfa6 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2374,6 +2374,8 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, sensor->current_fr = frame_rate; sensor->frame_interval = fi->interval; + sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->width, + mode->height, true); sensor->pending_mode_change = true; out: mutex_unlock(&sensor->lock); -- cgit From a7bc5773cd166032e35e343dfb6067a93d8402d1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Feb 2018 03:15:42 -0500 Subject: ov13858: fix endiannes warnings 3 warning regressions: + drivers/media/i2c/ov13858.c: warning: cast to restricted __be32: => 1093:16 + drivers/media/i2c/ov13858.c: warning: incorrect type in assignment (different base types): => 1111:13 + drivers/media/i2c/ov13858.c: warning: incorrect type in initializer (different base types): => 1071:27 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 1f260d346a29..d4156eb62dab 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1061,14 +1061,15 @@ struct ov13858 { #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) /* Read registers up to 4 at a time */ -static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val) +static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct i2c_msg msgs[2]; u8 *data_be_p; int ret; - u32 data_be = 0; - u16 reg_addr_be = cpu_to_be16(reg); + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); if (len > 4) return -EINVAL; @@ -1096,11 +1097,13 @@ static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val) } /* Write registers up to 4 at a time */ -static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val) +static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, + u32 __val) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int buf_i, val_i; u8 buf[6], *val_p; + __be32 val; if (len > 4) return -EINVAL; @@ -1108,7 +1111,7 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val) buf[0] = reg >> 8; buf[1] = reg & 0xff; - val = cpu_to_be32(val); + val = cpu_to_be32(__val); val_p = (u8 *)&val; buf_i = 2; val_i = 4 - len; -- cgit From 8d0f6e13f9e5bacbd62ae0e8b16ab2e21728efd3 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 5 Dec 2017 09:51:07 -0500 Subject: media: platform: stm32: Adopt SPDX identifier Add SPDX identifiers to files under stm32 directory Signed-off-by: Benjamin Gaignard Acked-by: Philippe Ombredanne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-cec.c | 5 +---- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 0e5aa17bdd40..7c496bc1cf38 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 CEC driver * Copyright (C) STMicroelectronics SA 2017 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 9460b3080dca..3319d9cb1b12 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for STM32 Digital Camera Memory Interface * @@ -5,7 +6,6 @@ * Authors: Yannick Fertre * Hugues Fruchet * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 * * This driver is based on atmel_isi.c * -- cgit From 1d1ca23bcbf84b8c169733ebe7ed8eb69330be31 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 18 Dec 2017 05:16:29 -0500 Subject: media: coda: Add i.MX51 (CodaHx4) support Add support for the CodaHx4 VPU used on i.MX51. Decoding h.264, MPEG-4, and MPEG-2 video works, as well as encoding h.264. MPEG-4 encoding is not enabled, it currently produces visual artifacts. Signed-off-by: Philipp Zabel Reviewed-by: Fabio Estevam Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: fix (bogus) sparse warning about uninited me_bits] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 46 +++++++++++++++++++++++-------- drivers/media/platform/coda/coda-common.c | 44 ++++++++++++++++++++++++++--- drivers/media/platform/coda/coda.h | 1 + 3 files changed, 75 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9fe113cb901f..68ed2a564ad1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -68,8 +68,9 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd) { struct coda_dev *dev = ctx->dev; - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_960) { /* Restore context related registers to CODA */ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -506,7 +507,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, goto err; } - if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) { + if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541)) { ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); if (ret < 0) @@ -594,6 +596,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) int dbk_bits; int bit_bits; int ip_bits; + int me_bits; memset(iram_info, 0, sizeof(*iram_info)); iram_info->next_paddr = dev->iram.paddr; @@ -603,15 +606,23 @@ static void coda_setup_iram(struct coda_ctx *ctx) return; switch (dev->devtype->product) { + case CODA_HX4: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE; + break; case CODA_7541: dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; break; case CODA_960: dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = 0; break; default: /* CODA_DX6 */ return; @@ -626,7 +637,8 @@ static void coda_setup_iram(struct coda_ctx *ctx) w64 = mb_width * 64; /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { iram_info->search_ram_size = round_up(mb_width * 16 * 36 + 2048, 1024); iram_info->search_ram_paddr = coda_iram_alloc(iram_info, @@ -635,8 +647,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) pr_err("IRAM is smaller than the search ram size\n"); goto out; } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; + iram_info->axi_sram_use |= me_bits; } /* Only H.264BP and H.263P3 are considered */ @@ -688,7 +699,8 @@ out: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "IRAM smaller than needed\n"); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { /* TODO - Enabling these causes picture errors on CODA7541 */ if (ctx->inst_type == CODA_INST_DECODER) { /* fw 1.4.50 */ @@ -706,6 +718,7 @@ out: static u32 coda_supported_firmwares[] = { CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), @@ -890,6 +903,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) case CODA_960: coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); /* fallthrough */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); @@ -919,6 +933,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; + case CODA_HX4: case CODA_7541: if (dst_fourcc == V4L2_PIX_FMT_H264) { value = (round_up(q_data_src->width, 16) & @@ -1086,6 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = FMO_SLICE_SAVE_BUF_SIZE << 7; coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); break; + case CODA_HX4: case CODA_7541: coda_write(dev, ctx->iram_info.search_ram_paddr, CODA7_CMD_ENC_SEQ_SEARCH_BASE); @@ -1131,7 +1147,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, q_data_src->bytesperline, CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); } @@ -1570,7 +1587,8 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; int profile, level; - if (dev->devtype->product != CODA_7541 && + if (dev->devtype->product != CODA_HX4 && + dev->devtype->product != CODA_7541 && dev->devtype->product != CODA_960) return false; @@ -1664,7 +1682,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); } if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, ctx->psbuf.paddr, CODA_CMD_DEC_SEQ_PS_BB_START); coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), @@ -1791,7 +1810,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_SET_FRAME_SLICE_BB_SIZE); } - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { int max_mb_x = 1920 / 16; int max_mb_y = 1088 / 16; int max_mb_num = max_mb_x * max_mb_y; @@ -1909,6 +1929,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) switch (dev->devtype->product) { case CODA_DX6: /* TBD */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); break; @@ -2049,7 +2070,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "errors in %d macroblocks\n", err_mb); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); if (val == 0) { /* not enough bitstream data */ diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index e8a7554a61d2..04e35d70ce2e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -128,7 +128,8 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, /* * Arrays of codecs supported by each given version of Coda: * i.MX27 -> codadx6 - * i.MX5x -> coda7 + * i.MX51 -> codahx4 + * i.MX53 -> coda7 * i.MX6 -> coda960 * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants */ @@ -137,6 +138,13 @@ static const struct coda_codec codadx6_codecs[] = { CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), }; +static const struct coda_codec codahx4_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), +}; + static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), @@ -234,6 +242,11 @@ static const struct coda_video_device *codadx6_video_devices[] = { &coda_bit_encoder, }; +static const struct coda_video_device *codahx4_video_devices[] = { + &coda_bit_encoder, + &coda_bit_decoder, +}; + static const struct coda_video_device *coda7_video_devices[] = { &coda_bit_jpeg_encoder, &coda_bit_jpeg_decoder, @@ -332,6 +345,8 @@ const char *coda_product_name(int product) switch (product) { case CODA_DX6: return "CodaDx6"; + case CODA_HX4: + return "CodaHx4"; case CODA_7541: return "CODA7541"; case CODA_960: @@ -1775,7 +1790,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); - if (ctx->dev->devtype->product == CODA_7541) { + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_3_1, @@ -1803,7 +1819,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); - if (ctx->dev->devtype->product == CODA_7541 || + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541 || ctx->dev->devtype->product == CODA_960) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, @@ -2004,6 +2021,7 @@ static int coda_open(struct file *file) if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; /* fallthrough */ + case CODA_HX4: case CODA_7541: ctx->reg_idx = 0; break; @@ -2182,7 +2200,8 @@ static int coda_hw_init(struct coda_dev *dev) /* Tell the BIT where to find everything it needs */ if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_HX4) { coda_write(dev, dev->tempbuf.paddr, CODA_REG_BIT_TEMP_BUF_ADDR); coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -2387,6 +2406,7 @@ put_pm: enum coda_platform { CODA_IMX27, + CODA_IMX51, CODA_IMX53, CODA_IMX6Q, CODA_IMX6DL, @@ -2407,6 +2427,21 @@ static const struct coda_devtype coda_devdata[] = { .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, .iram_size = 0xb000, }, + [CODA_IMX51] = { + .firmware = { + "vpu_fw_imx51.bin", + "vpu/vpu_fw_imx51.bin", + "v4l-codahx4-imx51.bin" + }, + .product = CODA_HX4, + .codecs = codahx4_codecs, + .num_codecs = ARRAY_SIZE(codahx4_codecs), + .vdevs = codahx4_video_devices, + .num_vdevs = ARRAY_SIZE(codahx4_video_devices), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, [CODA_IMX53] = { .firmware = { "vpu_fw_imx53.bin", @@ -2463,6 +2498,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids); #ifdef CONFIG_OF static const struct of_device_id coda_dt_ids[] = { { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, + { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c5f504d8cf67..12fab3f1dbfe 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -43,6 +43,7 @@ enum coda_inst_type { enum coda_product { CODA_DX6 = 0xf001, + CODA_HX4 = 0xf00a, CODA_7541 = 0xf012, CODA_960 = 0xf020, }; -- cgit From c7b7187b4626e8a52248699e1dc7e4ff50a5aa6e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 22 Dec 2017 20:57:04 -0500 Subject: media: atmel-isc: Make local symbol fmt_configs_list static Fixes the following sparse warning: drivers/media/platform/atmel/atmel-isc.c:338:19: warning: symbol 'fmt_configs_list' was not declared. Should it be static? Signed-off-by: Wei Yongjun Acked-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 92d695b29fa9..d89e14524d42 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -335,7 +335,7 @@ static struct isc_format formats_list[] = { }, }; -struct fmt_config fmt_configs_list[] = { +static struct fmt_config fmt_configs_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, -- cgit From c5f3f1047e57aa1e2c9a66df6b86c5c802023b6f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Jan 2018 08:43:50 -0500 Subject: media: au0828: fix VIDEO_V4L2 dependency After the move of videobuf2 into the common directory, selecting the au0828 driver with CONFIG_V4L2 disabled started causing a link failure, as we now attempt to build videobuf2 but it still requires v4l2: ERROR: "v4l2_event_pending" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "v4l2_fh_release" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "video_devdata" [drivers/media/common/videobuf/videobuf2-v4l2.ko] undefined! ERROR: "__tracepoint_vb2_buf_done" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! ERROR: "__tracepoint_vb2_dqbuf" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! ERROR: "v4l_vb2q_enable_media_source" [drivers/media/common/videobuf/videobuf2-core.ko] undefined! We want to be able to build the core au0828 support without V4L2, so this makes the 'select' conditional on V4L2, and refines the dependencies in VIDEO_AU0828_V4L2 so it can only be enabled in the exact conditions that have VIDEOBUF2_VMALLOC reachable. Fixes: 03fbdb2fc2b8 ("media: move videobuf2 to drivers/media/common") Fixes: 05439b1a3693 ("[media] media: au0828 - convert to use videobuf2") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 70521e0b4c53..18630b033d5b 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on I2C && INPUT && DVB_CORE && USB select I2C_ALGOBIT select VIDEO_TVEEPROM - select VIDEOBUF2_VMALLOC + select VIDEOBUF2_VMALLOC if VIDEO_V4L2 select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT @@ -18,7 +18,8 @@ config VIDEO_AU0828 config VIDEO_AU0828_V4L2 bool "Auvitek AU0828 v4l2 analog video support" - depends on VIDEO_AU0828 && VIDEO_V4L2 + depends on VIDEO_AU0828 + depends on VIDEO_V4L2=y || VIDEO_V4L2=VIDEO_AU0828 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y -- cgit From 664878184f831c87031988a03078cb7bc0a990d2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 4 Jan 2018 10:58:55 -0500 Subject: media: coda: bump maximum number of internal framebuffers to 19 While the h.264 standard only allows up to 16 reference frames, the CODA firmware needs two more buffers: one to hold the currently decoded frame and one for the display frame. Adding the framebuffer needed by the driver for VDOA operation brings the total to a maximum of 19 internal framebuffers. Lift the current maximum of 17 internal framebuffers to allow playback of high profile streams that require more than 14 reference frames. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 12fab3f1dbfe..c70cfab2433f 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -28,7 +28,7 @@ #include "coda_regs.h" -#define CODA_MAX_FRAMEBUFFERS 17 +#define CODA_MAX_FRAMEBUFFERS 19 #define FMO_SLICE_SAVE_BUF_SIZE (32) enum { -- cgit From 81b9de43599c59a3d5bd3e6e8645cb20b87840bc Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 8 Jan 2018 07:40:59 -0500 Subject: media: media-device: use strlcpy() instead of strncpy() gcc-8 reports drivers/media/media-device.c: In function 'media_device_get_topology': ./include/linux/string.h:245:9: warning: '__builtin_strncpy' specified bound 64 equals destination size [-Wstringop-truncation] We need to use strlcpy() to make sure the dest string is nul-terminated. Signed-off-by: Xiongfeng Wang Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index e79f72b8b858..f44244415124 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -255,7 +255,7 @@ static long media_device_get_topology(struct media_device *mdev, memset(&kentity, 0, sizeof(kentity)); kentity.id = entity->graph_obj.id; kentity.function = entity->function; - strncpy(kentity.name, entity->name, + strlcpy(kentity.name, entity->name, sizeof(kentity.name)); if (copy_to_user(uentity, &kentity, sizeof(kentity))) -- cgit From 50e7044535537b2a54c7ab798cd34c7f6d900bd2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 8 Jan 2018 09:21:07 -0500 Subject: media: usbtv: prevent double free in error case Quoting the original report: It looks like there is a double-free vulnerability in Linux usbtv driver on an error path of usbtv_probe function. When audio registration fails, usbtv_video_free function ends up freeing usbtv data structure, which gets freed the second time under usbtv_video_fail label. usbtv_audio_fail: usbtv_video_free(usbtv); => v4l2_device_put(&usbtv->v4l2_dev); => v4l2_device_put => kref_put => v4l2_device_release => usbtv_release (CALLBACK) => kfree(usbtv) (1st time) usbtv_video_fail: usb_set_intfdata(intf, NULL); usb_put_dev(usbtv->udev); kfree(usbtv); (2nd time) So, as we have refcounting, use it Reported-by: Yavuz, Tuba Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 127f8a0c098b..0c2e628e8723 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -112,6 +112,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_audio_fail: + /* we must not free at this point */ + usb_get_dev(usbtv->udev); usbtv_video_free(usbtv); usbtv_video_fail: -- cgit From c2e0e1ba6c5c25e45ff3da1f16e013c5910bee58 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 9 Jan 2018 03:42:47 -0500 Subject: media: mtk-vcodec: Always signal source change event on format change Currently the driver signals the source change event only in case of a midstream resolution change, however the initial format detection is also defined as a source change by the V4L2 codec API specification. Fix this by signaling the event after the initial header is parsed as well. Signed-off-by: Tomasz Figa Reviewed-by: Wu-Cheng Li Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 843510979ad8..86f0a7134365 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1224,6 +1224,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) ctx->dpb_size = dpbsize; ctx->state = MTK_STATE_HEADER; mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); + + mtk_vdec_queue_res_chg_event(ctx); } static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) -- cgit From f61c7bd9c9aff16cb727305769e1eeff732d9f28 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 11 Jan 2018 17:26:22 -0500 Subject: media: v4l2-core: v4l2-mc: Add SPDX license identifier Replace GPL license statement with SPDX GPL-2.0 license identifier. Signed-off-by: Shuah Khan Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mc.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index 1d550afeda13..0fc185a2ce90 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Media Controller ancillary functions * @@ -5,16 +7,6 @@ * Copyright (C) 2016 Shuah Khan * Copyright (C) 2006-2010 Nokia Corporation * Copyright (c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- cgit From 8a695a6cfabec094bb4281b3d47c2f7d021713c3 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sun, 14 Jan 2018 19:27:55 -0500 Subject: media: usbtv: Add USB ID 1f71:3306 to the UTV007 driver Add support for a new USB ID in this driver. Signed-off-by: Ian Douglas Scott [hans.verkuil@cisco.com: add commit message] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 0c2e628e8723..5095c380b2c1 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -147,6 +147,7 @@ static void usbtv_disconnect(struct usb_interface *intf) static const struct usb_device_id usbtv_id_table[] = { { USB_DEVICE(0x1b71, 0x3002) }, { USB_DEVICE(0x1f71, 0x3301) }, + { USB_DEVICE(0x1f71, 0x3306) }, {} }; MODULE_DEVICE_TABLE(usb, usbtv_id_table); -- cgit From 648f828c1fd028dc0426dfcbd2c407b412b27691 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jan 2018 06:24:52 -0500 Subject: media: rcar_drif: fix error return code in rcar_drif_alloc_dmachannels() Fix to return error code -ENODEV from the dma_request_slave_channel() error handling case instead of 0, as done elsewhere in this function. rc can be overwrite to 0 by dmaengine_slave_config() in the for loop. Signed-off-by: Wei Yongjun Reviewed-by: Geert Uytterhoeven Reviewed-by: Ramesh Shanmugasundaram Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_drif.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index b2e080ef5391..dc7e280c91b4 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -274,7 +274,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) { struct dma_slave_config dma_cfg; unsigned int i; - int ret = -ENODEV; + int ret; for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { struct rcar_drif *ch = sdr->ch[i]; @@ -282,6 +282,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx"); if (!ch->dmach) { rdrif_err(sdr, "ch%u: dma channel req failed\n", i); + ret = -ENODEV; goto dmach_error; } -- cgit From ee9568aa5830f607edc4c21b80b82b0e0fd1be77 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 12:54:53 -0500 Subject: media: venus: hfi: use true for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_msgs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index a681ae5381d6..90c93d9603dc 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -659,10 +659,10 @@ static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst, prop->buffer_type == HFI_BUFFER_OUTPUT2) { switch (prop->data[i]) { case HFI_BUFFER_MODE_STATIC: - inst->cap_bufs_mode_static = 1; + inst->cap_bufs_mode_static = true; break; case HFI_BUFFER_MODE_DYNAMIC: - inst->cap_bufs_mode_dynamic = 1; + inst->cap_bufs_mode_dynamic = true; break; default: break; -- cgit From d2d476b705b4930427d2efc38cfe0ea0c5d1cb4c Mon Sep 17 00:00:00 2001 From: Christopher Díaz Riveros Date: Wed, 24 Jan 2018 16:40:43 -0500 Subject: media: s2255drv: Remove unneeded if else blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given the following definitions from s2255drv.c #define LINE_SZ_4CIFS_NTSC 640 #define LINE_SZ_2CIFS_NTSC 640 #define LINE_SZ_1CIFS_NTSC 320 and #define LINE_SZ_4CIFS_PAL 704 #define LINE_SZ_2CIFS_PAL 704 #define LINE_SZ_1CIFS_PAL 352 f->fmt.pix.width possible values can be reduced to LINE_SZ_4CIFS_NTSC or LINE_SZ_1CIFS_NTSC. This patch removes unneeded if else blocks in vidioc_try_fmt_vid_cap function. This issue was detected by using the Coccinelle software. Signed-off-by: Christopher Díaz Riveros Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 8c2a86d71e8a..a00a15f55d37 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -803,10 +803,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_2CIFS_NTSC; - else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC) - f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; else f->fmt.pix.width = LINE_SZ_1CIFS_NTSC; } else { @@ -820,10 +816,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) f->fmt.pix.width = LINE_SZ_4CIFS_PAL; - else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) - f->fmt.pix.width = LINE_SZ_2CIFS_PAL; - else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) - f->fmt.pix.width = LINE_SZ_1CIFS_PAL; else f->fmt.pix.width = LINE_SZ_1CIFS_PAL; } -- cgit From 67300abdbe9f1717532aaf4e037222762716d0f6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 31 Jan 2018 12:33:09 -0500 Subject: media: cx25821: prevent out-of-bounds read on array card Currently an out of range dev->nr is detected by just reporting the issue and later on an out-of-bounds read on array card occurs because of this. Fix this by checking the upper range of dev->nr with the size of array card (removes the hard coded size), move this check earlier and also exit with the error -ENOSYS to avoid the later out-of-bounds array read. Detected by CoverityScan, CID#711191 ("Out-of-bounds-read") Fixes: commit 02b20b0b4cde ("V4L/DVB (12730): Add conexant cx25821 driver") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: %ld -> %zd] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 04aa4a68a0ae..040c6c251d3a 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -867,6 +867,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); + if (dev->nr >= ARRAY_SIZE(card)) { + CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card)); + return -ENODEV; + } if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -882,9 +886,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->channels[i].sram_channels = &cx25821_sram_channels[i]; } - if (dev->nr > 1) - CX25821_INFO("dev->nr > 1!"); - /* board config */ dev->board = 1; /* card[dev->nr]; */ dev->_max_num_decoders = MAX_DECODERS; -- cgit From 65243386f41d38460bfd4375d231a7c0346d0401 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Feb 2018 02:36:33 -0500 Subject: media: vivid: fix incorrect capabilities for radio The vivid driver has two custom controls that change the behavior of RDS. Depending on the control setting the V4L2_CAP_READWRITE capability is toggled. However, after an earlier commit the capability was no longer set correctly. This is now fixed. Fixes: 9765a32cd8 ("vivid: set device_caps in video_device") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-ctrls.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 4b6b5d715031..6b0bfa091592 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1196,6 +1196,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; break; case V4L2_CID_RDS_RECEPTION: dev->radio_rx_rds_enabled = ctrl->val; @@ -1270,6 +1271,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; if (!dev->radio_tx_rds_controls) dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; break; case V4L2_CID_RDS_TX_PTY: if (dev->radio_rx_rds_controls) -- cgit From 03703ed1debf777ea845aa9b50ba2e80a5e7dd3c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 2 Feb 2018 05:08:59 -0500 Subject: media: vb2: core: Finish buffers at the end of the stream If buffers were prepared or queued and the buffers were released without starting the queue, the finish mem op (corresponding to the prepare mem op) was never called to the buffers. Before commit a136f59c0a1f there was no need to do this as in such a case the prepare mem op had not been called yet. Address the problem by explicitly calling finish mem op when the queue is stopped if the buffer is in either prepared or queued state. Fixes: a136f59c0a1f ("[media] vb2: Move buffer cache synchronisation to prepare from queue") Cc: stable@vger.kernel.org # for v4.13 and up Signed-off-by: Sakari Ailus Tested-by: Devin Heitmueller Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index debe35fc66b4..d3f7bb33a54d 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1696,6 +1696,15 @@ static void __vb2_queue_cancel(struct vb2_queue *q) for (i = 0; i < q->num_buffers; ++i) { struct vb2_buffer *vb = q->bufs[i]; + if (vb->state == VB2_BUF_STATE_PREPARED || + vb->state == VB2_BUF_STATE_QUEUED) { + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, finish, + vb->planes[plane].mem_priv); + } + if (vb->state != VB2_BUF_STATE_DEQUEUED) { vb->state = VB2_BUF_STATE_PREPARED; call_void_vb_qop(vb, buf_finish, vb); -- cgit From d13a0139d7874a0577b5955d6eed895517d23b72 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 6 Feb 2018 03:02:23 -0500 Subject: media: vb2: Fix videobuf2 to map correct area Fixes vb2_vmalloc_get_userptr() to ioremap correct area. Since the current code does ioremap the page address, if the offset > 0, it does not do ioremap the last page and results in kernel panic. This fixes to pass the size + offset to ioremap so that ioremap can map correct area. Also, this uses __pfn_to_phys() to get the physical address of given PFN. Signed-off-by: Masami Hiramatsu Reported-by: Takao Orito Reported-by: Fumihiro ATSUMI Reviewed-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 3a7c80cd1a17..359fb9804d16 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) - ioremap_nocache(nums[0] << PAGE_SHIFT, size); + ioremap_nocache(__pfn_to_phys(nums[0]), size + offset); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); -- cgit From 1ae207fa7b70e7bd3bc0f3e5e3704edf55e45b68 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:46:59 -0500 Subject: media: rtl2832: use 64-bit arithmetic instead of 32-bit in rtl2832_set_frontend Add suffix ULL to constant 7 in order to give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type u64 (64 bits, unsigned). The expression dev->pdata->clk * 7 is currently being evaluated using 32-bit arithmetic. Addresses-Coverity-ID: 1271223 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 94bf5b7d6f3f..fa3b8169c1a5 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -498,7 +498,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) * / ConstWithBandwidthMode) */ - num = dev->pdata->clk * 7; + num = dev->pdata->clk * 7ULL; num *= 0x400000; num = div_u64(num, bw_mode); resamp_ratio = num & 0x3ffffff; @@ -511,7 +511,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * / (CrystalFreqHz * 7)) */ num = bw_mode << 20; - num2 = dev->pdata->clk * 7; + num2 = dev->pdata->clk * 7ULL; num = div_u64(num, num2); num = -num; cfreq_off_ratio = num & 0xfffff; -- cgit From 91e0c0c1b05230d703395965d4bf298705819641 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:47:09 -0500 Subject: media: dvb-frontends: ves1820: use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 10 in order to give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type u64 (64 bits, unsigned). The expression fpxin = state->config->xin * 10 is currently being evaluated using 32-bit arithmetic. Addresses-Coverity-ID: 200604 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/ves1820.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c index 1d8979289915..17600989f121 100644 --- a/drivers/media/dvb-frontends/ves1820.c +++ b/drivers/media/dvb-frontends/ves1820.c @@ -137,7 +137,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) NDEC = 3; /* yeuch! */ - fpxin = state->config->xin * 10; + fpxin = state->config->xin * 10ULL; fptmp = fpxin; do_div(fptmp, 123); if (symbolrate < fptmp) SFIL = 1; -- cgit From a2603d1748fddaa44b70b027737ba077145f261c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:47:37 -0500 Subject: media: i2c: max2175: use 64-bit arithmetic instead of 32-bit Add suffix LL to constant 2 in order to give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type s64 (64 bits, signed). The expression 2 * (clock_rate - abs_nco_freq) is currently being evaluated using 32-bit arithmetic. Addresses-Coverity-ID: 1446589 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/max2175.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 2f1966bdc473..87cba15b2977 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -643,7 +643,7 @@ static int max2175_set_nco_freq(struct max2175 *ctx, s32 nco_freq) if (abs_nco_freq < clock_rate / 2) { nco_val_desired = 2 * nco_freq; } else { - nco_val_desired = 2 * (clock_rate - abs_nco_freq); + nco_val_desired = 2LL * (clock_rate - abs_nco_freq); if (nco_freq < 0) nco_val_desired = -nco_val_desired; } -- cgit From 07837433ca4d7cf1bfd27d4776956cc7a7bf921d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:49:04 -0500 Subject: media: pci: cx88-input: use 64-bit arithmetic instead of 32-bit Add suffix LL to constant 1000000 in order to give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type ktime_t (64 bits, signed). The expression ir->polling * 1000000 is currently being evaluated using 32-bit arithmetic. Addresses-Coverity-ID: 1392628 ("Unintentional integer overflow") Addresses-Coverity-ID: 1392630 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 4e9953e61a12..6f4e6923a91a 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -180,7 +180,7 @@ static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); cx88_ir_handle_key(ir); - missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000); + missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000LL); if (missed > 1) ir_dprintk("Missed ticks %ld\n", missed - 1); @@ -200,7 +200,7 @@ static int __cx88_ir_start(void *priv) if (ir->polling) { hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ir->timer.function = cx88_ir_work; - hrtimer_start(&ir->timer, ir->polling * 1000000, + hrtimer_start(&ir->timer, ir->polling * 1000000LL, HRTIMER_MODE_REL); } if (ir->sampling) { -- cgit From 8328ad0f8274d7e432124d84622c06a286b81177 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:51:18 -0500 Subject: media: rockchip/rga: use 64-bit arithmetic instead of 32-bit Cast p to dma_addr_t in order to avoid a potential integer overflow. This variable is being used in a context that expects an expression of type dma_addr_t (u64). The expression p << PAGE_SHIFT is currently being evaluated using 32-bit arithmetic. Addresses-Coverity-ID: 1458347 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga-buf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 49cacc7a48d1..fa1ba98c96dc 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -140,7 +140,8 @@ void rga_buf_map(struct vb2_buffer *vb) address = sg_phys(sgl); for (p = 0; p < len; p++) { - dma_addr_t phys = address + (p << PAGE_SHIFT); + dma_addr_t phys = address + + ((dma_addr_t)p << PAGE_SHIFT); pages[mapped_size + p] = phys; } -- cgit From eb64311ffc693e6e7b646a9b53631194f79b77c3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:52:24 -0500 Subject: media: platform: sh_veu: use 64-bit arithmetic instead of 32-bit Cast left and top to dma_addr_t in order to give the compiler complete information about the proper arithmetic to use. Notice that these variables are being used in contexts that expect expressions of type dma_addr_t (64 bit, unsigned). Such expressions are currently being evaluated using 32-bit arithmetic. Also, move the expression (((dma_addr_t)left * veu->vfmt_out.fmt->depth) >> 3) at the end in order to avoid a line wrapping checkpatch.pl warning. Addresses-Coverity-ID: 1056807 ("Unintentional integer overflow") Addresses-Coverity-ID: 1056808 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 976ea0bb5b6c..1a0cde017fdf 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -520,8 +520,8 @@ static void sh_veu_colour_offset(struct sh_veu_dev *veu, struct sh_veu_vfmt *vfm /* dst_left and dst_top validity will be verified in CROP / COMPOSE */ unsigned int left = vfmt->frame.left & ~0x03; unsigned int top = vfmt->frame.top; - dma_addr_t offset = ((left * veu->vfmt_out.fmt->depth) >> 3) + - top * veu->vfmt_out.bytesperline; + dma_addr_t offset = (dma_addr_t)top * veu->vfmt_out.bytesperline + + (((dma_addr_t)left * veu->vfmt_out.fmt->depth) >> 3); unsigned int y_line; vfmt->offset_y = offset; -- cgit From fc49d3d7dc26a43f8d3b1874c7ddb975a49e8a8c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 6 Feb 2018 11:53:44 -0500 Subject: media: platform: vivid-cec: use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 10 in order to give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type u64 (64 bits, unsigned). The expression len * 10 * CEC_TIM_DATA_BIT_TOTAL is currently being evaluated using 32-bit arithmetic. Also, remove unnecessary parentheses and add a code comment to make it clear what is the reason of the code change. Addresses-Coverity-ID: 1454996 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-cec.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index 619bd8435b7f..c2c889d6dcf5 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -70,8 +70,15 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, if (adap == NULL) return; - ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL + - len * 10 * CEC_TIM_DATA_BIT_TOTAL)); + + /* + * Suffix ULL on constant 10 makes the expression + * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL + * to be evaluated using 64-bit unsigned arithmetic (u64), which + * is what ktime_sub_us expects as second argument. + */ + ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); cec_queue_pin_cec_event(adap, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); cec_queue_pin_cec_event(adap, true, ts); -- cgit From 26a6181f3453ea108baa3e6242196d791df6e666 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 8 Feb 2018 03:26:14 -0500 Subject: media: cx18: remove unused cx18-alsa-mixer cx18-alsa-mixer functions are not used since commit 4cb565cc2700 ("V4L/DVB: cx18: make it so cx18-alsa-main.c compiles") 9 year later, let's just remove them. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-alsa-main.c | 1 - drivers/media/pci/cx18/cx18-alsa-mixer.c | 170 ------------------------------- drivers/media/pci/cx18/cx18-alsa-mixer.h | 18 ---- 3 files changed, 189 deletions(-) delete mode 100644 drivers/media/pci/cx18/cx18-alsa-mixer.c delete mode 100644 drivers/media/pci/cx18/cx18-alsa-mixer.h (limited to 'drivers/media') diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index 2531e4b81b60..93443d1457c5 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -32,7 +32,6 @@ #include "cx18-driver.h" #include "cx18-version.h" #include "cx18-alsa.h" -#include "cx18-alsa-mixer.h" #include "cx18-alsa-pcm.h" int cx18_alsa_debug; diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c deleted file mode 100644 index cb04c3d820e2..000000000000 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "cx18-alsa.h" -#include "cx18-driver.h" - -/* - * Note the cx18-av-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx18_av_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx18_av_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); - snd_cx18_unlock(cxsc); - - if (!ret) - uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - - /* Fetch current state */ - ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); - - if (ret || - (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - ret = v4l2_s_ctrl(cx->sd_av->ctrl_handler, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_cx18_unlock(cxsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_cx18_mixer_tv_volume_info, - .get = snd_cx18_mixer_tv_volume_get, - .put = snd_cx18_mixer_tv_volume_put, - .tlv.p = snd_cx18_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add CS5345 I2S volume for HVR-1600 */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) -{ - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct snd_card *sc = cxsc->sc; - int ret; - - strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(&snd_cx18_mixer_tv_vol, cxsc)); - if (ret) { - CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_cx18_mixer_tv_vol.name, ret); - } - return ret; -} diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.h b/drivers/media/pci/cx18/cx18-alsa-mixer.h deleted file mode 100644 index 3aed123955dd..000000000000 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc); -- cgit From 47b934875b00fefe16a2b8a9daa88eb82be169a8 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 8 Feb 2018 03:31:07 -0500 Subject: media: ivtv: remove ivtv-alsa-mixer ivtv-alsa-mixer functions was introduced in commit 269c11fbac4f ("[media] ivtv, ivtv-alsa: Add initial ivtv-alsa interface driver for ivtv") But according to commit message, ivtv-alsa-mixer.c was already dead code. 5 years after, we should remove it. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: removed forgotten ivtv-alsa-mixer.h include] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-alsa-main.c | 11 +-- drivers/media/pci/ivtv/ivtv-alsa-mixer.c | 165 ------------------------------- drivers/media/pci/ivtv/ivtv-alsa-mixer.h | 18 ---- 3 files changed, 1 insertion(+), 193 deletions(-) delete mode 100644 drivers/media/pci/ivtv/ivtv-alsa-mixer.c delete mode 100644 drivers/media/pci/ivtv/ivtv-alsa-mixer.h (limited to 'drivers/media') diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 029f52733f70..c1856f609d2c 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -20,7 +20,6 @@ #include "ivtv-driver.h" #include "ivtv-version.h" #include "ivtv-alsa.h" -#include "ivtv-alsa-mixer.h" #include "ivtv-alsa-pcm.h" #include @@ -160,15 +159,7 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev) /* (4) Set the driver ID and name strings */ snd_ivtv_card_set_names(itvsc); - /* (5) Create other components: mixer, PCM, & proc files */ -#if 0 - ret = snd_ivtv_mixer_create(itvsc); - if (ret) { - IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d: proceeding anyway\n", - __func__, ret); - } -#endif - + /* (5) Create other components: PCM, & proc files */ ret = snd_ivtv_pcm_create(itvsc); if (ret) { IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n", diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c deleted file mode 100644 index aee453fcff37..000000000000 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to ivtv PCM capture streams - * - * Copyright (C) 2009,2012 Andy Walls - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ivtv-alsa.h" -#include "ivtv-alsa-mixer.h" -#include "ivtv-driver.h" - -#include - -#include -#include -#include - -/* - * Note the cx25840-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx25840_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx25840_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_ivtv_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_ivtv_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl); - struct ivtv *itv = to_ivtv(itvsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - - snd_ivtv_lock(itvsc); - ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - snd_ivtv_unlock(itvsc); - - if (!ret) - uctl->value.integer.value[0] = cx25840_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl); - struct ivtv *itv = to_ivtv(itvsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - - snd_ivtv_lock(itvsc); - - /* Fetch current state */ - ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - - if (ret || - (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); - ret = v4l2_s_ctrl(itv->sd_audio->ctrl_handler, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_ivtv_unlock(itvsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_ivtv_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_ivtv_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_ivtv_mixer_tv_volume_info, - .get = snd_ivtv_mixer_tv_volume_get, - .put = snd_ivtv_mixer_tv_volume_put, - .tlv.p = snd_ivtv_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add I2S volume */ - -int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc) -{ - struct v4l2_device *v4l2_dev = itvsc->v4l2_dev; - struct snd_card *sc = itvsc->sc; - int ret; - - strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(&snd_ivtv_mixer_tv_vol, itvsc)); - if (ret) { - IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_ivtv_mixer_tv_vol.name, ret); - } - return ret; -} diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h b/drivers/media/pci/ivtv/ivtv-alsa-mixer.h deleted file mode 100644 index 382bc36bc529..000000000000 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to ivtv PCM capture streams - * - * Copyright (C) 2009,2012 Andy Walls - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc); -- cgit From 1b3963509a469c70b965c2211db4eb3427c4ef86 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Feb 2018 11:55:48 -0500 Subject: media: cec: improve debugging cec_transmit_msg_fh() first checked the message for errors, and only after the message was found to be valid did it log the message contents. However, that makes it hard to associate an error in the kernel log with the message since the message contents was never logged in that case. So swap the order: first log the message (once some very basic checks are done), and only after that check for errors. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 768f7d70b55c..cf6dc3f3a17e 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -699,16 +699,31 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, else msg->flags = 0; + if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } + /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { dprintk(1, "%s: invalid length %d\n", __func__, msg->len); return -EINVAL; } + + memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); + + if (msg->timeout) + dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", + __func__, msg->len, msg->msg, msg->reply, + !block ? ", nb" : ""); + else + dprintk(2, "%s: %*ph%s\n", + __func__, msg->len, msg->msg, !block ? " (nb)" : ""); + if (msg->timeout && msg->len == 1) { - dprintk(1, "%s: can't reply for poll msg\n", __func__); + dprintk(1, "%s: can't reply to poll msg\n", __func__); return -EINVAL; } - memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); if (msg->len == 1) { if (cec_msg_destination(msg) == 0xf) { dprintk(1, "%s: invalid poll message\n", __func__); @@ -768,19 +783,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (!msg->sequence) msg->sequence = ++adap->sequence; - if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } - - if (msg->timeout) - dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", - __func__, msg->len, msg->msg, msg->reply, - !block ? ", nb" : ""); - else - dprintk(2, "%s: %*ph%s\n", - __func__, msg->len, msg->msg, !block ? " (nb)" : ""); - data->msg = *msg; data->fh = fh; data->adap = adap; -- cgit From 290ef7d846b35205975786296388c082e50d4319 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Fri, 9 Feb 2018 09:13:26 -0500 Subject: media: em28xx: use %*phC to print small buffers Use %*phC format to print small buffers as hex strings Suggested-by: Andy Shevchenko Signed-off-by: Antonio Cardace Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9bf49d666e5a..9ad958004990 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -710,8 +710,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ dev_info(&dev->intf->dev, - "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n", + data, dev->hash); dev_info(&dev->intf->dev, "EEPROM info:\n"); dev_info(&dev->intf->dev, @@ -776,8 +776,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); dev_info(&dev->intf->dev, - "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n", + data, dev->hash); dev_info(&dev->intf->dev, "EEPROM info:\n"); } else { -- cgit From ed356f110403f6acc64dcbbbfdc38662ab9b06c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 12 Feb 2018 06:45:32 -0500 Subject: media: vivid: check if the cec_adapter is valid If CEC is not enabled for the vivid driver, then the adap pointer is NULL and 'adap->phys_addr' will fail. Cc: # for v4.12 and up Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index cc67f403a808..e5914be0e12d 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -862,7 +862,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (edid->start_block + edid->blocks > dev->edid_blocks) edid->blocks = dev->edid_blocks - edid->start_block; - cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); + if (adap) + cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); return 0; } -- cgit From c32678eac48ad3c0ecad47f8879f9017390e358a Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Mon, 12 Feb 2018 13:35:25 -0500 Subject: media: gspca: dtcs033: use %*ph to print small buffer Use %*ph format to print small buffer as hex string. Remove newline at the end of the format string as it would be duplicated by the one supplied as last argument. Suggested-by: Andy Shevchenko Signed-off-by: Antonio Cardace Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/dtcs033.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c index cdf27cf0112a..7654c8c08eda 100644 --- a/drivers/media/usb/gspca/dtcs033.c +++ b/drivers/media/usb/gspca/dtcs033.c @@ -76,12 +76,10 @@ static int reg_reqs(struct gspca_dev *gspca_dev, } else if (preq->bRequestType & USB_DIR_IN) { gspca_dbg(gspca_dev, D_STREAM, - "USB IN (%d) returned[%d] %02X %02X %02X %s\n", + "USB IN (%d) returned[%d] %3ph %s", i, preq->wLength, - gspca_dev->usb_buf[0], - gspca_dev->usb_buf[1], - gspca_dev->usb_buf[2], + gspca_dev->usb_buf, preq->wLength > 3 ? "...\n" : "\n"); } -- cgit From 9f564184e6cc21a86c26bab920afac1bab7653ff Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 8 Jan 2018 13:14:04 -0500 Subject: media: i2c: adv748x: fix HDMI field heights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADV748x handles interlaced media using V4L2_FIELD_ALTERNATE field types. The correct specification for the height on the mbus is the image height, in this instance, the field height. The AFE component already correctly adjusts the height on the mbus, but the HDMI component got left behind. Adjust the mbus height to correctly describe the image height of the fields when processing interlaced video for HDMI pipelines. Fixes: 3e89586a64df ("media: i2c: adv748x: add adv748x driver") Reviewed-by: Niklas Söderlund Signed-off-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-hdmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index 4da4253553fc..10d229a4f088 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -105,6 +105,9 @@ static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi, fmt->width = hdmi->timings.bt.width; fmt->height = hdmi->timings.bt.height; + + if (fmt->field == V4L2_FIELD_ALTERNATE) + fmt->height /= 2; } static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings) -- cgit From 00d9da502565e97fcca3805eec98db6df3594ec0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Feb 2018 08:28:22 -0500 Subject: media: ov7740: remove an unused var Fix this warning regression: drivers/media/i2c/ov7740.c: warning: variable 'ret' set but not used [-Wunused-but-set-variable]: => 276:6 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index e1a44a18d9a8..01f578785e79 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -279,7 +279,7 @@ static int ov7740_get_register(struct v4l2_subdev *sd, reg->val = val; reg->size = 1; - return 0; + return ret; } static int ov7740_set_register(struct v4l2_subdev *sd, -- cgit From 225fe212a2d58c7113aa2781a3594ae8d9827ea9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Feb 2018 08:31:28 -0500 Subject: media: tvp541x: fix some kernel-doc parameters Solve the following warnings: + drivers/media/i2c/tvp514x.c: warning: Excess function parameter 'a' description in 'tvp514x_g_frame_interval': => 759 + drivers/media/i2c/tvp514x.c: warning: Excess function parameter 'a' description in 'tvp514x_s_frame_interval': => 784 + drivers/media/i2c/tvp514x.c: warning: Function parameter or member 'ival' not described in 'tvp514x_g_frame_interval': => 759 + drivers/media/i2c/tvp514x.c: warning: Function parameter or member 'ival' not described in 'tvp514x_s_frame_interval': => 784 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp514x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 310f9fce520d..6a9890531d01 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -749,7 +749,7 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) /** * tvp514x_g_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to a v4l2_subdev_frame_interval structure + * @ival: pointer to a v4l2_subdev_frame_interval structure * * Returns the decoder's video CAPTURE parameters. */ @@ -773,7 +773,7 @@ tvp514x_g_frame_interval(struct v4l2_subdev *sd, /** * tvp514x_s_frame_interval() - V4L2 decoder interface handler * @sd: pointer to standard V4L2 sub-device structure - * @a: pointer to a v4l2_subdev_frame_interval structure + * @ival: pointer to a v4l2_subdev_frame_interval structure * * Configures the decoder to use the input parameters, if possible. If * not possible, returns the appropriate error code. -- cgit From 32e5a70dc8f4e9813c61e5465d72d2e9830ba0ff Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 22 Feb 2018 05:37:19 -0500 Subject: media: platform: Add Renesas CEU driver Add driver for Renesas Capture Engine Unit (CEU). The CEU interface supports capturing 'data' (YUV422) and 'images' (NV[12|21|16|61]). This driver aims to replace the soc_camera-based sh_mobile_ceu one. Tested with ov7670 camera sensor, providing YUYV_2X8 data on Renesas RZ platform GR-Peach. Tested with ov7725 camera sensor on SH4 platform Migo-R. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: added two 'fall-through' comments] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 9 + drivers/media/platform/Makefile | 1 + drivers/media/platform/renesas-ceu.c | 1677 ++++++++++++++++++++++++++++++++++ 3 files changed, 1687 insertions(+) create mode 100644 drivers/media/platform/renesas-ceu.c (limited to 'drivers/media') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 614fbef08ddc..f9cc0582c8a9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -144,6 +144,15 @@ config VIDEO_STM32_DCMI To compile this driver as a module, choose M here: the module will be called stm32-dcmi. +config VIDEO_RENESAS_CEU + tristate "Renesas Capture Engine Unit (CEU) driver" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + ---help--- + This is a v4l2 driver for the Renesas CEU Interface + source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/am437x/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 7f3080437be6..85e112122f32 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o +obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c new file mode 100644 index 000000000000..bd64cad542df --- /dev/null +++ b/drivers/media/platform/renesas-ceu.c @@ -0,0 +1,1677 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 Driver for Renesas Capture Engine Unit (CEU) interface + * Copyright (C) 2017-2018 Jacopo Mondi + * + * Based on soc-camera driver "soc_camera/sh_mobile_ceu_camera.c" + * Copyright (C) 2008 Magnus Damm + * + * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", + * Copyright (C) 2006, Sascha Hauer, Pengutronix + * Copyright (C) 2008, Guennadi Liakhovetski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "renesas-ceu" + +/* CEU registers offsets and masks. */ +#define CEU_CAPSR 0x00 /* Capture start register */ +#define CEU_CAPCR 0x04 /* Capture control register */ +#define CEU_CAMCR 0x08 /* Capture interface control register */ +#define CEU_CAMOR 0x10 /* Capture interface offset register */ +#define CEU_CAPWR 0x14 /* Capture interface width register */ +#define CEU_CAIFR 0x18 /* Capture interface input format register */ +#define CEU_CRCNTR 0x28 /* CEU register control register */ +#define CEU_CRCMPR 0x2c /* CEU register forcible control register */ +#define CEU_CFLCR 0x30 /* Capture filter control register */ +#define CEU_CFSZR 0x34 /* Capture filter size clip register */ +#define CEU_CDWDR 0x38 /* Capture destination width register */ +#define CEU_CDAYR 0x3c /* Capture data address Y register */ +#define CEU_CDACR 0x40 /* Capture data address C register */ +#define CEU_CFWCR 0x5c /* Firewall operation control register */ +#define CEU_CDOCR 0x64 /* Capture data output control register */ +#define CEU_CEIER 0x70 /* Capture event interrupt enable register */ +#define CEU_CETCR 0x74 /* Capture event flag clear register */ +#define CEU_CSTSR 0x7c /* Capture status register */ +#define CEU_CSRTR 0x80 /* Capture software reset register */ + +/* Data synchronous fetch mode. */ +#define CEU_CAMCR_JPEG BIT(4) + +/* Input components ordering: CEU_CAMCR.DTARY field. */ +#define CEU_CAMCR_DTARY_8_UYVY (0x00 << 8) +#define CEU_CAMCR_DTARY_8_VYUY (0x01 << 8) +#define CEU_CAMCR_DTARY_8_YUYV (0x02 << 8) +#define CEU_CAMCR_DTARY_8_YVYU (0x03 << 8) +/* TODO: input components ordering for 16 bits input. */ + +/* Bus transfer MTU. */ +#define CEU_CAPCR_BUS_WIDTH256 (0x3 << 20) + +/* Bus width configuration. */ +#define CEU_CAMCR_DTIF_16BITS BIT(12) + +/* No downsampling to planar YUV420 in image fetch mode. */ +#define CEU_CDOCR_NO_DOWSAMPLE BIT(4) + +/* Swap all input data in 8-bit, 16-bits and 32-bits units (Figure 46.45). */ +#define CEU_CDOCR_SWAP_ENDIANNESS (7) + +/* Capture reset and enable bits. */ +#define CEU_CAPSR_CPKIL BIT(16) +#define CEU_CAPSR_CE BIT(0) + +/* CEU operating flag bit. */ +#define CEU_CAPCR_CTNCP BIT(16) +#define CEU_CSTRST_CPTON BIT(1) + +/* Platform specific IRQ source flags. */ +#define CEU_CETCR_ALL_IRQS_RZ 0x397f313 +#define CEU_CETCR_ALL_IRQS_SH4 0x3d7f313 + +/* Prohibited register access interrupt bit. */ +#define CEU_CETCR_IGRW BIT(4) +/* One-frame capture end interrupt. */ +#define CEU_CEIER_CPE BIT(0) +/* VBP error. */ +#define CEU_CEIER_VBP BIT(20) +#define CEU_CEIER_MASK (CEU_CEIER_CPE | CEU_CEIER_VBP) + +#define CEU_MAX_WIDTH 2560 +#define CEU_MAX_HEIGHT 1920 +#define CEU_MAX_BPL 8188 +#define CEU_W_MAX(w) ((w) < CEU_MAX_WIDTH ? (w) : CEU_MAX_WIDTH) +#define CEU_H_MAX(h) ((h) < CEU_MAX_HEIGHT ? (h) : CEU_MAX_HEIGHT) + +/* + * ceu_bus_fmt - describe a 8-bits yuyv format the sensor can produce + * + * @mbus_code: bus format code + * @fmt_order: CEU_CAMCR.DTARY ordering of input components (Y, Cb, Cr) + * @fmt_order_swap: swapped CEU_CAMCR.DTARY ordering of input components + * (Y, Cr, Cb) + * @swapped: does Cr appear before Cb? + * @bps: number of bits sent over bus for each sample + * @bpp: number of bits per pixels unit + */ +struct ceu_mbus_fmt { + u32 mbus_code; + u32 fmt_order; + u32 fmt_order_swap; + bool swapped; + u8 bps; + u8 bpp; +}; + +/* + * ceu_buffer - Link vb2 buffer to the list of available buffers. + */ +struct ceu_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; +}; + +static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct ceu_buffer, vb); +} + +/* + * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice. + */ +struct ceu_subdev { + struct v4l2_subdev *v4l2_sd; + struct v4l2_async_subdev asd; + + /* per-subdevice mbus configuration options */ + unsigned int mbus_flags; + struct ceu_mbus_fmt mbus_fmt; +}; + +static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_subdev *asd) +{ + return container_of(asd, struct ceu_subdev, asd); +} + +/* + * ceu_device - CEU device instance + */ +struct ceu_device { + struct device *dev; + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* subdevices descriptors */ + struct ceu_subdev *subdevs; + /* the subdevice currently in use */ + struct ceu_subdev *sd; + unsigned int sd_index; + unsigned int num_sd; + + /* platform specific mask with all IRQ sources flagged */ + u32 irq_mask; + + /* currently configured field and pixel format */ + enum v4l2_field field; + struct v4l2_pix_format_mplane v4l2_pix; + + /* async subdev notification helpers */ + struct v4l2_async_notifier notifier; + /* pointers to "struct ceu_subdevice -> asd" */ + struct v4l2_async_subdev **asds; + + /* vb2 queue, capture buffer list and active buffer pointer */ + struct vb2_queue vb2_vq; + struct list_head capture; + struct vb2_v4l2_buffer *active; + unsigned int sequence; + + /* mlock - lock access to interface reset and vb2 queue */ + struct mutex mlock; + + /* lock - lock access to capture buffer queue and active buffer */ + spinlock_t lock; + + /* base - CEU memory base address */ + void __iomem *base; +}; + +static inline struct ceu_device *v4l2_to_ceu(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct ceu_device, v4l2_dev); +} + +/* --- CEU memory output formats --- */ + +/* + * ceu_fmt - describe a memory output format supported by CEU interface. + * + * @fourcc: memory layout fourcc format code + * @bpp: number of bits for each pixel stored in memory + */ +struct ceu_fmt { + u32 fourcc; + u32 bpp; +}; + +/* + * ceu_format_list - List of supported memory output formats + * + * If sensor provides any YUYV bus format, all the following planar memory + * formats are available thanks to CEU re-ordering and sub-sampling + * capabilities. + */ +static const struct ceu_fmt ceu_fmt_list[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .bpp = 16, + }, +}; + +static const struct ceu_fmt *get_ceu_fmt_from_fourcc(unsigned int fourcc) +{ + const struct ceu_fmt *fmt = &ceu_fmt_list[0]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ceu_fmt_list); i++, fmt++) + if (fmt->fourcc == fourcc) + return fmt; + + return NULL; +} + +static bool ceu_fmt_mplane(struct v4l2_pix_format_mplane *pix) +{ + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + return false; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + return true; + default: + return false; + } +} + +/* --- CEU HW operations --- */ + +static void ceu_write(struct ceu_device *priv, unsigned int reg_offs, u32 data) +{ + iowrite32(data, priv->base + reg_offs); +} + +static u32 ceu_read(struct ceu_device *priv, unsigned int reg_offs) +{ + return ioread32(priv->base + reg_offs); +} + +/* + * ceu_soft_reset() - Software reset the CEU interface. + * @ceu_device: CEU device. + * + * Returns 0 for success, -EIO for error. + */ +static int ceu_soft_reset(struct ceu_device *ceudev) +{ + unsigned int i; + + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CPKIL); + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CSTSR) & CEU_CSTRST_CPTON)) + break; + udelay(1); + } + + if (i == 100) { + dev_err(ceudev->dev, "soft reset time out\n"); + return -EIO; + } + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CAPSR) & CEU_CAPSR_CPKIL)) + return 0; + udelay(1); + } + + /* If we get here, CEU has not reset properly. */ + return -EIO; +} + +/* --- CEU Capture Operations --- */ + +/* + * ceu_hw_config() - Configure CEU interface registers. + */ +static int ceu_hw_config(struct ceu_device *ceudev) +{ + u32 camcr, cdocr, cfzsr, cdwdr, capwr; + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + unsigned int mbus_flags = ceu_sd->mbus_flags; + + /* Start configuring CEU registers */ + ceu_write(ceudev, CEU_CAIFR, 0); + ceu_write(ceudev, CEU_CFWCR, 0); + ceu_write(ceudev, CEU_CRCNTR, 0); + ceu_write(ceudev, CEU_CRCMPR, 0); + + /* Set the frame capture period for both image capture and data sync. */ + capwr = (pix->height << 16) | pix->width * mbus_fmt->bpp / 8; + + /* + * Swap input data endianness by default. + * In data fetch mode bytes are received in chunks of 8 bytes. + * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) + * The data is however by default written to memory in reverse order: + * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) + * + * Use CEU_CDOCR[2:0] to swap data ordering. + */ + cdocr = CEU_CDOCR_SWAP_ENDIANNESS; + + /* + * Configure CAMCR and CDOCR: + * match input components ordering with memory output format and + * handle downsampling to YUV420. + * + * If the memory output planar format is 'swapped' (Cr before Cb) and + * input format is not, use the swapped version of CAMCR.DTARY. + * + * If the memory output planar format is not 'swapped' (Cb before Cr) + * and input format is, use the swapped version of CAMCR.DTARY. + * + * CEU by default downsample to planar YUV420 (CDCOR[4] = 0). + * If output is planar YUV422 set CDOCR[4] = 1 + * + * No downsample for data fetch sync mode. + */ + switch (pix->pixelformat) { + /* Data fetch sync mode */ + case V4L2_PIX_FMT_YUYV: + /* TODO: handle YUYV permutations through DTARY bits. */ + camcr = CEU_CAMCR_JPEG; + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->plane_fmt[0].bytesperline; + break; + + /* Non-swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV16: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV12: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order_swap; + else + camcr = mbus_fmt->fmt_order; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + /* Swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV61: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV21: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order; + else + camcr = mbus_fmt->fmt_order_swap; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + default: + return -EINVAL; + } + + camcr |= mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; + camcr |= mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; + + /* TODO: handle 16 bit bus width with DTIF bit in CAMCR */ + ceu_write(ceudev, CEU_CAMCR, camcr); + ceu_write(ceudev, CEU_CDOCR, cdocr); + ceu_write(ceudev, CEU_CAPCR, CEU_CAPCR_BUS_WIDTH256); + + /* + * TODO: make CAMOR offsets configurable. + * CAMOR wants to know the number of blanks between a VS/HS signal + * and valid data. This value should actually come from the sensor... + */ + ceu_write(ceudev, CEU_CAMOR, 0); + + /* TODO: 16 bit bus width require re-calculation of cdwdr and cfzsr */ + ceu_write(ceudev, CEU_CAPWR, capwr); + ceu_write(ceudev, CEU_CFSZR, cfzsr); + ceu_write(ceudev, CEU_CDWDR, cdwdr); + + return 0; +} + +/* + * ceu_capture() - Trigger start of a capture sequence. + * + * Program the CEU DMA registers with addresses where to transfer image data. + */ +static int ceu_capture(struct ceu_device *ceudev) +{ + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + dma_addr_t phys_addr_top; + + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, 0); + ceu_write(ceudev, CEU_CDAYR, phys_addr_top); + + /* Ignore CbCr plane for non multi-planar image formats. */ + if (ceu_fmt_mplane(pix)) { + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, + 1); + ceu_write(ceudev, CEU_CDACR, phys_addr_top); + } + + /* + * Trigger new capture start: once for each frame, as we work in + * one-frame capture mode. + */ + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CE); + + return 0; +} + +static irqreturn_t ceu_irq(int irq, void *data) +{ + struct ceu_device *ceudev = data; + struct vb2_v4l2_buffer *vbuf; + struct ceu_buffer *buf; + u32 status; + + /* Clean interrupt status. */ + status = ceu_read(ceudev, CEU_CETCR); + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + + /* Unexpected interrupt. */ + if (!(status & CEU_CEIER_MASK)) + return IRQ_NONE; + + spin_lock(&ceudev->lock); + + /* Stale interrupt from a released buffer, ignore it. */ + vbuf = ceudev->active; + if (!vbuf) { + spin_unlock(&ceudev->lock); + return IRQ_HANDLED; + } + + /* + * When a VBP interrupt occurs, no capture end interrupt will occur + * and the image of that frame is not captured correctly. + */ + if (status & CEU_CEIER_VBP) { + dev_err(ceudev->dev, "VBP interrupt: abort capture\n"); + goto error_irq_out; + } + + /* Prepare to return the 'previous' buffer. */ + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vbuf->sequence = ceudev->sequence++; + vbuf->field = ceudev->field; + + /* Prepare a new 'active' buffer and trigger a new capture. */ + if (!list_empty(&ceudev->capture)) { + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + list_del(&buf->queue); + ceudev->active = &buf->vb; + + ceu_capture(ceudev); + } + + /* Return the 'previous' buffer. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; + +error_irq_out: + /* Return the 'previous' buffer and all queued ones. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR); + + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; +} + +/* --- CEU Videobuf2 operations --- */ + +static void ceu_update_plane_sizes(struct v4l2_plane_pix_format *plane, + unsigned int bpl, unsigned int szimage) +{ + memset(plane, 0, sizeof(*plane)); + + plane->sizeimage = szimage; + if (plane->bytesperline < bpl || plane->bytesperline > CEU_MAX_BPL) + plane->bytesperline = bpl; +} + +/* + * ceu_calc_plane_sizes() - Fill per-plane 'struct v4l2_plane_pix_format' + * information according to the currently configured + * pixel format. + * @ceu_device: CEU device. + * @ceu_fmt: Active image format. + * @pix: Pixel format information (store line width and image sizes) + */ +static void ceu_calc_plane_sizes(struct ceu_device *ceudev, + const struct ceu_fmt *ceu_fmt, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpl, szimage; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + pix->num_planes = 1; + bpl = pix->width * ceu_fmt->bpp / 8; + szimage = pix->height * bpl; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + break; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage / 2); + break; + + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + default: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage); + break; + } +} + +/* + * ceu_vb2_setup() - is called to check whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format, if required. + */ +static int ceu_vb2_setup(struct vb2_queue *vq, unsigned int *count, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + /* num_planes is set: just check plane sizes. */ + if (*num_planes) { + for (i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + /* num_planes not set: called from REQBUFS, just set plane sizes. */ + *num_planes = pix->num_planes; + for (i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + + return 0; +} + +static void ceu_vb2_queue(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ceu_buffer *buf = vb2_to_ceu(vbuf); + unsigned long irqflags; + + spin_lock_irqsave(&ceudev->lock, irqflags); + list_add_tail(&buf->queue, &ceudev->capture); + spin_unlock_irqrestore(&ceudev->lock, irqflags); +} + +static int ceu_vb2_prepare(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + for (i = 0; i < pix->num_planes; i++) { + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { + dev_err(ceudev->dev, + "Plane size too small (%lu < %u)\n", + vb2_plane_size(vb, i), + pix->plane_fmt[i].sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); + } + + return 0; +} + +static int ceu_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + int ret; + + /* Program the CEU interface according to the CEU image format. */ + ret = ceu_hw_config(ceudev); + if (ret) + goto error_return_bufs; + + ret = v4l2_subdev_call(v4l2_sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + dev_dbg(ceudev->dev, + "Subdevice failed to start streaming: %d\n", ret); + goto error_return_bufs; + } + + spin_lock_irqsave(&ceudev->lock, irqflags); + ceudev->sequence = 0; + + /* Grab the first available buffer and trigger the first capture. */ + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + if (!buf) { + spin_unlock_irqrestore(&ceudev->lock, irqflags); + dev_dbg(ceudev->dev, + "No buffer available for capture.\n"); + goto error_stop_sensor; + } + + list_del(&buf->queue); + ceudev->active = &buf->vb; + + /* Clean and program interrupts for first capture. */ + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + ceu_capture(ceudev); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return 0; + +error_stop_sensor: + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + +error_return_bufs: + spin_lock_irqsave(&ceudev->lock, irqflags); + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_QUEUED); + ceudev->active = NULL; + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return ret; +} + +static void ceu_stop_streaming(struct vb2_queue *vq) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + + /* Clean and disable interrupt sources. */ + ceu_write(ceudev, CEU_CETCR, + ceu_read(ceudev, CEU_CETCR) & ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + + spin_lock_irqsave(&ceudev->lock, irqflags); + if (ceudev->active) { + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_ERROR); + ceudev->active = NULL; + } + + /* Release all queued buffers. */ + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&ceudev->capture); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + ceu_soft_reset(ceudev); +} + +static const struct vb2_ops ceu_vb2_ops = { + .queue_setup = ceu_vb2_setup, + .buf_queue = ceu_vb2_queue, + .buf_prepare = ceu_vb2_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = ceu_start_streaming, + .stop_streaming = ceu_stop_streaming, +}; + +/* --- CEU image formats handling --- */ + +/* + * ceu_try_fmt() - test format on CEU and sensor + * @ceudev: The CEU device. + * @v4l2_fmt: format to test. + * + * Returns 0 for success, < 0 for errors. + */ +static int ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + struct v4l2_subdev_pad_config pad_cfg; + const struct ceu_fmt *ceu_fmt; + int ret; + + struct v4l2_subdev_format sd_format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + break; + + default: + pix->pixelformat = V4L2_PIX_FMT_NV16; + break; + } + + ceu_fmt = get_ceu_fmt_from_fourcc(pix->pixelformat); + + /* CFSZR requires height and width to be 4-pixel aligned. */ + v4l_bound_align_image(&pix->width, 2, CEU_MAX_WIDTH, 4, + &pix->height, 4, CEU_MAX_HEIGHT, 4, 0); + + /* + * Set format on sensor sub device: bus format used to produce memory + * format is selected at initialization time. + */ + v4l2_fill_mbus_format_mplane(&sd_format.format, pix); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format); + if (ret) + return ret; + + /* Apply size returned by sensor as the CEU can't scale. */ + v4l2_fill_pix_format_mplane(pix, &sd_format.format); + + /* Calculate per-plane sizes based on image format. */ + ceu_calc_plane_sizes(ceudev, ceu_fmt, pix); + + return 0; +} + +/* + * ceu_set_fmt() - Apply the supplied format to both sensor and CEU + */ +static int ceu_set_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + ret = ceu_try_fmt(ceudev, v4l2_fmt); + if (ret) + return ret; + + v4l2_fill_mbus_format_mplane(&format.format, &v4l2_fmt->fmt.pix_mp); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, NULL, &format); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt->fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_set_default_fmt() - Apply default NV16 memory output format with VGA + * sizes. + */ +static int ceu_set_default_fmt(struct ceu_device *ceudev) +{ + int ret; + + struct v4l2_format v4l2_fmt = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .field = V4L2_FIELD_NONE, + .pixelformat = V4L2_PIX_FMT_NV16, + .num_planes = 2, + .plane_fmt = { + [0] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + [1] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + }, + }, + }; + + ret = ceu_try_fmt(ceudev, &v4l2_fmt); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt.fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_init_mbus_fmt() - Query sensor for supported formats and initialize + * CEU media bus format used to produce memory formats. + * + * Find out if sensor can produce a permutation of 8-bits YUYV bus format. + * From a single 8-bits YUYV bus format the CEU can produce several memory + * output formats: + * - NV[12|21|16|61] through image fetch mode; + * - YUYV422 if sensor provides YUYV422 + * + * TODO: Other YUYV422 permutations through data fetch sync mode and DTARY + * TODO: Binary data (eg. JPEG) and raw formats through data fetch sync mode + */ +static int ceu_init_mbus_fmt(struct ceu_device *ceudev) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + bool yuyv_bus_fmt = false; + + struct v4l2_subdev_mbus_code_enum sd_mbus_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = 0, + }; + + /* Find out if sensor can produce any permutation of 8-bits YUYV422. */ + while (!yuyv_bus_fmt && + !v4l2_subdev_call(v4l2_sd, pad, enum_mbus_code, + NULL, &sd_mbus_fmt)) { + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + yuyv_bus_fmt = true; + break; + default: + /* + * Only support 8-bits YUYV bus formats at the moment; + * + * TODO: add support for binary formats (data sync + * fetch mode). + */ + break; + } + + sd_mbus_fmt.index++; + } + + if (!yuyv_bus_fmt) + return -ENXIO; + + /* + * Save the first encountered YUYV format as "mbus_fmt" and use it + * to output all planar YUV422 and YUV420 (NV*) formats to memory as + * well as for data synch fetch mode (YUYV - YVYU etc. ). + */ + mbus_fmt->mbus_code = sd_mbus_fmt.code; + mbus_fmt->bps = 8; + + /* Annotate the selected bus format components ordering. */ + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_YVYU8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_UYVY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_VYUY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + } + + return 0; +} + +/* --- Runtime PM Handlers --- */ + +/* + * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. + */ +static int ceu_runtime_resume(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 1); + + ceu_soft_reset(ceudev); + + return 0; +} + +/* + * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. + * Turn sensor power off. + */ +static int ceu_runtime_suspend(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 0); + + ceu_write(ceudev, CEU_CEIER, 0); + ceu_soft_reset(ceudev); + + return 0; +} + +/* --- File Operations --- */ + +static int ceu_open(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + int ret; + + ret = v4l2_fh_open(file); + if (ret) + return ret; + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power on on first open */ + pm_runtime_get_sync(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static int ceu_release(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + + vb2_fop_release(file); + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power down on last close */ + pm_runtime_put(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static const struct v4l2_file_operations ceu_fops = { + .owner = THIS_MODULE, + .open = ceu_open, + .release = ceu_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +/* --- Video Device IOCTLs --- */ + +static int ceu_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct ceu_device *ceudev = video_drvdata(file); + + strlcpy(cap->card, "Renesas CEU", sizeof(cap->card)); + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:renesas-ceu-%s", dev_name(ceudev->dev)); + + return 0; +} + +static int ceu_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ceu_fmt *fmt; + + if (f->index >= ARRAY_SIZE(ceu_fmt_list)) + return -EINVAL; + + fmt = &ceu_fmt_list[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int ceu_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return ceu_try_fmt(ceudev, f); +} + +static int ceu_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + return ceu_set_fmt(ceudev, f); +} + +static int ceu_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + f->fmt.pix_mp = ceudev->v4l2_pix; + + return 0; +} + +static int ceu_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceusd; + + if (inp->index >= ceudev->num_sd) + return -EINVAL; + + ceusd = &ceudev->subdevs[inp->index]; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = 0; + snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", + inp->index, ceusd->v4l2_sd->name); + + return 0; +} + +static int ceu_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct ceu_device *ceudev = video_drvdata(file); + + *i = ceudev->sd_index; + + return 0; +} + +static int ceu_s_input(struct file *file, void *priv, unsigned int i) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd_old; + int ret; + + if (i >= ceudev->num_sd) + return -EINVAL; + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + if (i == ceudev->sd_index) + return 0; + + ceu_sd_old = ceudev->sd; + ceudev->sd = &ceudev->subdevs[i]; + + /* + * Make sure we can generate output image formats and apply + * default one. + */ + ret = ceu_init_mbus_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + ret = ceu_set_default_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + /* Now that we're sure we can use the sensor, power off the old one. */ + v4l2_subdev_call(ceu_sd_old->v4l2_sd, core, s_power, 0); + v4l2_subdev_call(ceudev->sd->v4l2_sd, core, s_power, 1); + + ceudev->sd_index = i; + + return 0; +} + +static int ceu_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_size_enum fse = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fsize->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = CEU_W_MAX(fse.max_width); + fsize->discrete.height = CEU_H_MAX(fse.max_height); + + return 0; +} + +static int ceu_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_interval_enum fie = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fival->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_interval, NULL, + &fie); + if (ret) + return ret; + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static const struct v4l2_ioctl_ops ceu_ioctl_ops = { + .vidioc_querycap = ceu_querycap, + + .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, + + .vidioc_enum_input = ceu_enum_input, + .vidioc_g_input = ceu_g_input, + .vidioc_s_input = ceu_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_parm = ceu_g_parm, + .vidioc_s_parm = ceu_s_parm, + .vidioc_enum_framesizes = ceu_enum_framesizes, + .vidioc_enum_frameintervals = ceu_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * ceu_vdev_release() - release CEU video device memory when last reference + * to this driver is closed + */ +static void ceu_vdev_release(struct video_device *vdev) +{ + struct ceu_device *ceudev = video_get_drvdata(vdev); + + kfree(ceudev); +} + +static int ceu_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *v4l2_sd, + struct v4l2_async_subdev *asd) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct ceu_subdev *ceu_sd = to_ceu_subdev(asd); + + ceu_sd->v4l2_sd = v4l2_sd; + ceudev->num_sd++; + + return 0; +} + +static int ceu_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct video_device *vdev = &ceudev->vdev; + struct vb2_queue *q = &ceudev->vb2_vq; + struct v4l2_subdev *v4l2_sd; + int ret; + + /* Initialize vb2 queue. */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = ceudev; + q->ops = &ceu_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct ceu_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &ceudev->mlock; + q->dev = ceudev->v4l2_dev.dev; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + /* + * Make sure at least one sensor is primary and use it to initialize + * ceu formats. + */ + if (!ceudev->sd) { + ceudev->sd = &ceudev->subdevs[0]; + ceudev->sd_index = 0; + } + + v4l2_sd = ceudev->sd->v4l2_sd; + + ret = ceu_init_mbus_fmt(ceudev); + if (ret) + return ret; + + ret = ceu_set_default_fmt(ceudev); + if (ret) + return ret; + + /* Register the video device. */ + strncpy(vdev->name, DRIVER_NAME, strlen(DRIVER_NAME)); + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &ceudev->mlock; + vdev->queue = &ceudev->vb2_vq; + vdev->ctrl_handler = v4l2_sd->ctrl_handler; + vdev->fops = &ceu_fops; + vdev->ioctl_ops = &ceu_ioctl_ops; + vdev->release = ceu_vdev_release; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + video_set_drvdata(vdev, ceudev); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + v4l2_err(vdev->v4l2_dev, + "video_register_device failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct v4l2_async_notifier_operations ceu_notify_ops = { + .bound = ceu_notify_bound, + .complete = ceu_notify_complete, +}; + +/* + * ceu_init_async_subdevs() - Initialize CEU subdevices and async_subdevs in + * ceu device. Both DT and platform data parsing use + * this routine. + * + * Returns 0 for success, -ENOMEM for failure. + */ +static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd) +{ + /* Reserve memory for 'n_sd' ceu_subdev descriptors. */ + ceudev->subdevs = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->subdevs), GFP_KERNEL); + if (!ceudev->subdevs) + return -ENOMEM; + + /* + * Reserve memory for 'n_sd' pointers to async_subdevices. + * ceudev->asds members will point to &ceu_subdev.asd + */ + ceudev->asds = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->asds), GFP_KERNEL); + if (!ceudev->asds) + return -ENOMEM; + + ceudev->sd = NULL; + ceudev->sd_index = 0; + ceudev->num_sd = 0; + + return 0; +} + +/* + * ceu_parse_platform_data() - Initialize async_subdevices using platform + * device provided data. + */ +static int ceu_parse_platform_data(struct ceu_device *ceudev, + const struct ceu_platform_data *pdata) +{ + const struct ceu_async_subdev *async_sd; + struct ceu_subdev *ceu_sd; + unsigned int i; + int ret; + + if (pdata->num_subdevs == 0) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, pdata->num_subdevs); + if (ret) + return ret; + + for (i = 0; i < pdata->num_subdevs; i++) { + /* Setup the ceu subdevice and the async subdevice. */ + async_sd = &pdata->subdevs[i]; + ceu_sd = &ceudev->subdevs[i]; + + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = async_sd->flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_I2C; + ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id; + ceu_sd->asd.match.i2c.address = async_sd->i2c_address; + + ceudev->asds[i] = &ceu_sd->asd; + } + + return pdata->num_subdevs; +} + +/* + * ceu_parse_dt() - Initialize async_subdevs parsing device tree graph. + */ +static int ceu_parse_dt(struct ceu_device *ceudev) +{ + struct device_node *of = ceudev->dev->of_node; + struct v4l2_fwnode_endpoint fw_ep; + struct ceu_subdev *ceu_sd; + struct device_node *ep; + unsigned int i; + int num_ep; + int ret; + + num_ep = of_graph_get_endpoint_count(of); + if (!num_ep) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, num_ep); + if (ret) + return ret; + + for (i = 0; i < num_ep; i++) { + ep = of_graph_get_endpoint_by_regs(of, 0, i); + if (!ep) { + dev_err(ceudev->dev, + "No subdevice connected on endpoint %u.\n", i); + ret = -ENODEV; + goto error_put_node; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep); + if (ret) { + dev_err(ceudev->dev, + "Unable to parse endpoint #%u.\n", i); + goto error_put_node; + } + + if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) { + dev_err(ceudev->dev, + "Only parallel input supported.\n"); + ret = -EINVAL; + goto error_put_node; + } + + /* Setup the ceu subdevice and the async subdevice. */ + ceu_sd = &ceudev->subdevs[i]; + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + ceu_sd->asd.match.fwnode = + fwnode_graph_get_remote_port_parent( + of_fwnode_handle(ep)); + + ceudev->asds[i] = &ceu_sd->asd; + of_node_put(ep); + } + + return num_ep; + +error_put_node: + of_node_put(ep); + return ret; +} + +/* + * struct ceu_data - Platform specific CEU data + * @irq_mask: CETCR mask with all interrupt sources enabled. The mask differs + * between SH4 and RZ platforms. + */ +struct ceu_data { + u32 irq_mask; +}; + +static const struct ceu_data ceu_data_rz = { + .irq_mask = CEU_CETCR_ALL_IRQS_RZ, +}; + +static const struct ceu_data ceu_data_sh4 = { + .irq_mask = CEU_CETCR_ALL_IRQS_SH4, +}; + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ceu_of_match[] = { + { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz }, + { } +}; +MODULE_DEVICE_TABLE(of, ceu_of_match); +#endif + +static int ceu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct ceu_data *ceu_data; + struct ceu_device *ceudev; + struct resource *res; + unsigned int irq; + int num_subdevs; + int ret; + + ceudev = kzalloc(sizeof(*ceudev), GFP_KERNEL); + if (!ceudev) + return -ENOMEM; + + platform_set_drvdata(pdev, ceudev); + ceudev->dev = dev; + + INIT_LIST_HEAD(&ceudev->capture); + spin_lock_init(&ceudev->lock); + mutex_init(&ceudev->mlock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ceudev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ceudev->base)) { + ret = PTR_ERR(ceudev->base); + goto error_free_ceudev; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "Failed to get irq: %d\n", ret); + goto error_free_ceudev; + } + irq = ret; + + ret = devm_request_irq(dev, irq, ceu_irq, + 0, dev_name(dev), ceudev); + if (ret) { + dev_err(&pdev->dev, "Unable to request CEU interrupt.\n"); + goto error_free_ceudev; + } + + pm_runtime_enable(dev); + + ret = v4l2_device_register(dev, &ceudev->v4l2_dev); + if (ret) + goto error_pm_disable; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + ceu_data = of_match_device(ceu_of_match, dev)->data; + num_subdevs = ceu_parse_dt(ceudev); + } else if (dev->platform_data) { + /* Assume SH4 if booting with platform data. */ + ceu_data = &ceu_data_sh4; + num_subdevs = ceu_parse_platform_data(ceudev, + dev->platform_data); + } else { + num_subdevs = -EINVAL; + } + + if (num_subdevs < 0) { + ret = num_subdevs; + goto error_v4l2_unregister; + } + ceudev->irq_mask = ceu_data->irq_mask; + + ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; + ceudev->notifier.subdevs = ceudev->asds; + ceudev->notifier.num_subdevs = num_subdevs; + ceudev->notifier.ops = &ceu_notify_ops; + ret = v4l2_async_notifier_register(&ceudev->v4l2_dev, + &ceudev->notifier); + if (ret) + goto error_v4l2_unregister; + + dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev)); + + return 0; + +error_v4l2_unregister: + v4l2_device_unregister(&ceudev->v4l2_dev); +error_pm_disable: + pm_runtime_disable(dev); +error_free_ceudev: + kfree(ceudev); + + return ret; +} + +static int ceu_remove(struct platform_device *pdev) +{ + struct ceu_device *ceudev = platform_get_drvdata(pdev); + + pm_runtime_disable(ceudev->dev); + + v4l2_async_notifier_unregister(&ceudev->notifier); + + v4l2_device_unregister(&ceudev->v4l2_dev); + + video_unregister_device(&ceudev->vdev); + + return 0; +} + +static const struct dev_pm_ops ceu_pm_ops = { + SET_RUNTIME_PM_OPS(ceu_runtime_suspend, + ceu_runtime_resume, + NULL) +}; + +static struct platform_driver ceu_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &ceu_pm_ops, + .of_match_table = of_match_ptr(ceu_of_match), + }, + .probe = ceu_probe, + .remove = ceu_remove, +}; + +module_platform_driver(ceu_driver); + +MODULE_DESCRIPTION("Renesas CEU camera driver"); +MODULE_AUTHOR("Jacopo Mondi "); +MODULE_LICENSE("GPL v2"); -- cgit From 1112babde21483d86ed3fbad1320b0ddf9ab2ece Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 21 Feb 2018 12:47:59 -0500 Subject: media: i2c: Copy ov772x soc_camera sensor driver Copy the soc_camera based driver in v4l2 sensor driver directory. This commit just copies the original file without modifying it. No modification to KConfig and Makefile as soc_camera framework dependencies need to be removed first in next commit. Signed-off-by: Jacopo Mondi Acked-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 1124 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1124 insertions(+) create mode 100644 drivers/media/i2c/ov772x.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c new file mode 100644 index 000000000000..806383500313 --- /dev/null +++ b/drivers/media/i2c/ov772x.c @@ -0,0 +1,1124 @@ +/* + * ov772x Camera Driver + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov7670 and soc_camera_platform driver, + * + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * register offset + */ +#define GAIN 0x00 /* AGC - Gain control gain setting */ +#define BLUE 0x01 /* AWB - Blue channel gain setting */ +#define RED 0x02 /* AWB - Red channel gain setting */ +#define GREEN 0x03 /* AWB - Green channel gain setting */ +#define COM1 0x04 /* Common control 1 */ +#define BAVG 0x05 /* U/B Average Level */ +#define GAVG 0x06 /* Y/Gb Average Level */ +#define RAVG 0x07 /* V/R Average Level */ +#define AECH 0x08 /* Exposure Value - AEC MSBs */ +#define COM2 0x09 /* Common control 2 */ +#define PID 0x0A /* Product ID Number MSB */ +#define VER 0x0B /* Product ID Number LSB */ +#define COM3 0x0C /* Common control 3 */ +#define COM4 0x0D /* Common control 4 */ +#define COM5 0x0E /* Common control 5 */ +#define COM6 0x0F /* Common control 6 */ +#define AEC 0x10 /* Exposure Value */ +#define CLKRC 0x11 /* Internal clock */ +#define COM7 0x12 /* Common control 7 */ +#define COM8 0x13 /* Common control 8 */ +#define COM9 0x14 /* Common control 9 */ +#define COM10 0x15 /* Common control 10 */ +#define REG16 0x16 /* Register 16 */ +#define HSTART 0x17 /* Horizontal sensor size */ +#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ +#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ +#define VSIZE 0x1A /* Vertical sensor size */ +#define PSHFT 0x1B /* Data format - pixel delay select */ +#define MIDH 0x1C /* Manufacturer ID byte - high */ +#define MIDL 0x1D /* Manufacturer ID byte - low */ +#define LAEC 0x1F /* Fine AEC value */ +#define COM11 0x20 /* Common control 11 */ +#define BDBASE 0x22 /* Banding filter Minimum AEC value */ +#define DBSTEP 0x23 /* Banding filter Maximum Setp */ +#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ +#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ +#define VPT 0x26 /* AGC/AEC Fast mode operating region */ +#define REG28 0x28 /* Register 28 */ +#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ +#define EXHCH 0x2A /* Dummy pixel insert MSB */ +#define EXHCL 0x2B /* Dummy pixel insert LSB */ +#define VOUTSIZE 0x2C /* Vertical data output size MSBs */ +#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ +#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */ +#define YAVE 0x2F /* Y/G Channel Average value */ +#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */ +#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */ +#define HREF 0x32 /* Image start and size control */ +#define DM_LNL 0x33 /* Dummy line low 8 bits */ +#define DM_LNH 0x34 /* Dummy line high 8 bits */ +#define ADOFF_B 0x35 /* AD offset compensation value for B channel */ +#define ADOFF_R 0x36 /* AD offset compensation value for R channel */ +#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */ +#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */ +#define OFF_B 0x39 /* Analog process B channel offset value */ +#define OFF_R 0x3A /* Analog process R channel offset value */ +#define OFF_GB 0x3B /* Analog process Gb channel offset value */ +#define OFF_GR 0x3C /* Analog process Gr channel offset value */ +#define COM12 0x3D /* Common control 12 */ +#define COM13 0x3E /* Common control 13 */ +#define COM14 0x3F /* Common control 14 */ +#define COM15 0x40 /* Common control 15*/ +#define COM16 0x41 /* Common control 16 */ +#define TGT_B 0x42 /* BLC blue channel target value */ +#define TGT_R 0x43 /* BLC red channel target value */ +#define TGT_GB 0x44 /* BLC Gb channel target value */ +#define TGT_GR 0x45 /* BLC Gr channel target value */ +/* for ov7720 */ +#define LCC0 0x46 /* Lens correction control 0 */ +#define LCC1 0x47 /* Lens correction option 1 - X coordinate */ +#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ +#define LCC3 0x49 /* Lens correction option 3 */ +#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ +#define LCC5 0x4B /* Lens correction option 5 */ +#define LCC6 0x4C /* Lens correction option 6 */ +/* for ov7725 */ +#define LC_CTR 0x46 /* Lens correction control */ +#define LC_XC 0x47 /* X coordinate of lens correction center relative */ +#define LC_YC 0x48 /* Y coordinate of lens correction center relative */ +#define LC_COEF 0x49 /* Lens correction coefficient */ +#define LC_RADI 0x4A /* Lens correction radius */ +#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */ +#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */ + +#define FIXGAIN 0x4D /* Analog fix gain amplifer */ +#define AREF0 0x4E /* Sensor reference control */ +#define AREF1 0x4F /* Sensor reference current control */ +#define AREF2 0x50 /* Analog reference control */ +#define AREF3 0x51 /* ADC reference control */ +#define AREF4 0x52 /* ADC reference control */ +#define AREF5 0x53 /* ADC reference control */ +#define AREF6 0x54 /* Analog reference control */ +#define AREF7 0x55 /* Analog reference control */ +#define UFIX 0x60 /* U channel fixed value output */ +#define VFIX 0x61 /* V channel fixed value output */ +#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ +#define AWB_CTRL0 0x63 /* AWB control byte 0 */ +#define DSP_CTRL1 0x64 /* DSP control byte 1 */ +#define DSP_CTRL2 0x65 /* DSP control byte 2 */ +#define DSP_CTRL3 0x66 /* DSP control byte 3 */ +#define DSP_CTRL4 0x67 /* DSP control byte 4 */ +#define AWB_BIAS 0x68 /* AWB BLC level clip */ +#define AWB_CTRL1 0x69 /* AWB control 1 */ +#define AWB_CTRL2 0x6A /* AWB control 2 */ +#define AWB_CTRL3 0x6B /* AWB control 3 */ +#define AWB_CTRL4 0x6C /* AWB control 4 */ +#define AWB_CTRL5 0x6D /* AWB control 5 */ +#define AWB_CTRL6 0x6E /* AWB control 6 */ +#define AWB_CTRL7 0x6F /* AWB control 7 */ +#define AWB_CTRL8 0x70 /* AWB control 8 */ +#define AWB_CTRL9 0x71 /* AWB control 9 */ +#define AWB_CTRL10 0x72 /* AWB control 10 */ +#define AWB_CTRL11 0x73 /* AWB control 11 */ +#define AWB_CTRL12 0x74 /* AWB control 12 */ +#define AWB_CTRL13 0x75 /* AWB control 13 */ +#define AWB_CTRL14 0x76 /* AWB control 14 */ +#define AWB_CTRL15 0x77 /* AWB control 15 */ +#define AWB_CTRL16 0x78 /* AWB control 16 */ +#define AWB_CTRL17 0x79 /* AWB control 17 */ +#define AWB_CTRL18 0x7A /* AWB control 18 */ +#define AWB_CTRL19 0x7B /* AWB control 19 */ +#define AWB_CTRL20 0x7C /* AWB control 20 */ +#define AWB_CTRL21 0x7D /* AWB control 21 */ +#define GAM1 0x7E /* Gamma Curve 1st segment input end point */ +#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ +#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ +#define GAM4 0x81 /* Gamma Curve 4th segment input end point */ +#define GAM5 0x82 /* Gamma Curve 5th segment input end point */ +#define GAM6 0x83 /* Gamma Curve 6th segment input end point */ +#define GAM7 0x84 /* Gamma Curve 7th segment input end point */ +#define GAM8 0x85 /* Gamma Curve 8th segment input end point */ +#define GAM9 0x86 /* Gamma Curve 9th segment input end point */ +#define GAM10 0x87 /* Gamma Curve 10th segment input end point */ +#define GAM11 0x88 /* Gamma Curve 11th segment input end point */ +#define GAM12 0x89 /* Gamma Curve 12th segment input end point */ +#define GAM13 0x8A /* Gamma Curve 13th segment input end point */ +#define GAM14 0x8B /* Gamma Curve 14th segment input end point */ +#define GAM15 0x8C /* Gamma Curve 15th segment input end point */ +#define SLOP 0x8D /* Gamma curve highest segment slope */ +#define DNSTH 0x8E /* De-noise threshold */ +#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */ +#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */ +#define DNSOFF 0x91 /* Auto De-noise threshold control */ +#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */ +#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */ +#define MTX1 0x94 /* Matrix coefficient 1 */ +#define MTX2 0x95 /* Matrix coefficient 2 */ +#define MTX3 0x96 /* Matrix coefficient 3 */ +#define MTX4 0x97 /* Matrix coefficient 4 */ +#define MTX5 0x98 /* Matrix coefficient 5 */ +#define MTX6 0x99 /* Matrix coefficient 6 */ +#define MTX_CTRL 0x9A /* Matrix control */ +#define BRIGHT 0x9B /* Brightness control */ +#define CNTRST 0x9C /* Contrast contrast */ +#define CNTRST_CTRL 0x9D /* Contrast contrast center */ +#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */ +#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */ +#define SCAL0 0xA0 /* Scaling control 0 */ +#define SCAL1 0xA1 /* Scaling control 1 */ +#define SCAL2 0xA2 /* Scaling control 2 */ +#define FIFODLYM 0xA3 /* FIFO manual mode delay control */ +#define FIFODLYA 0xA4 /* FIFO auto mode delay control */ +#define SDE 0xA6 /* Special digital effect control */ +#define USAT 0xA7 /* U component saturation control */ +#define VSAT 0xA8 /* V component saturation control */ +/* for ov7720 */ +#define HUE0 0xA9 /* Hue control 0 */ +#define HUE1 0xAA /* Hue control 1 */ +/* for ov7725 */ +#define HUECOS 0xA9 /* Cosine value */ +#define HUESIN 0xAA /* Sine value */ + +#define SIGN 0xAB /* Sign bit for Hue and contrast */ +#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ + +/* + * register detail + */ + +/* COM2 */ +#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ + /* Output drive capability */ +#define OCAP_1x 0x00 /* 1x */ +#define OCAP_2x 0x01 /* 2x */ +#define OCAP_3x 0x02 /* 3x */ +#define OCAP_4x 0x03 /* 4x */ + +/* COM3 */ +#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) +#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) + +#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ +#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ +#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ +#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ +#define SWAP_ML 0x08 /* Swap output MSB/LSB */ + /* Tri-state option for output clock */ +#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ + /* Tri-state option for output data */ +#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ +#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */ + +/* COM4 */ + /* PLL frequency control */ +#define PLL_BYPASS 0x00 /* 00: Bypass PLL */ +#define PLL_4x 0x40 /* 01: PLL 4x */ +#define PLL_6x 0x80 /* 10: PLL 6x */ +#define PLL_8x 0xc0 /* 11: PLL 8x */ + /* AEC evaluate window */ +#define AEC_FULL 0x00 /* 00: Full window */ +#define AEC_1p2 0x10 /* 01: 1/2 window */ +#define AEC_1p4 0x20 /* 10: 1/4 window */ +#define AEC_2p3 0x30 /* 11: Low 2/3 window */ + +/* COM5 */ +#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ +#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */ + /* Auto frame rate max rate control */ +#define AFR_NO_RATE 0x00 /* No reduction of frame rate */ +#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */ +#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */ +#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */ + /* Auto frame rate active point control */ +#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */ +#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */ +#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ +#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ + /* AEC max step control */ +#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ + /* 1 : No limit to AEC increase step */ + +/* COM7 */ + /* SCCB Register Reset */ +#define SCCB_RESET 0x80 /* 0 : No change */ + /* 1 : Resets all registers to default */ + /* Resolution selection */ +#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */ +#define SLCT_VGA 0x00 /* 0 : VGA */ +#define SLCT_QVGA 0x40 /* 1 : QVGA */ +#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ +#define SENSOR_RAW 0x10 /* Sensor RAW */ + /* RGB output format control */ +#define FMT_MASK 0x0c /* Mask of color format */ +#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ +#define FMT_RGB565 0x04 /* 01 : RGB 565 */ +#define FMT_RGB555 0x08 /* 10 : RGB 555 */ +#define FMT_RGB444 0x0c /* 11 : RGB 444 */ + /* Output format control */ +#define OFMT_MASK 0x03 /* Mask of output format */ +#define OFMT_YUV 0x00 /* 00 : YUV */ +#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ +#define OFMT_RGB 0x02 /* 10 : RGB */ +#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */ + +/* COM8 */ +#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */ + /* AEC Setp size limit */ +#define UNLMT_STEP 0x40 /* 0 : Step size is limited */ + /* 1 : Unlimited step size */ +#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */ +#define AEC_BND 0x10 /* Enable AEC below banding value */ +#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */ +#define AGC_ON 0x04 /* AGC Enable */ +#define AWB_ON 0x02 /* AWB Enable */ +#define AEC_ON 0x01 /* AEC Enable */ + +/* COM9 */ +#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */ + /* Automatic gain ceiling - maximum AGC value */ +#define GAIN_2x 0x00 /* 000 : 2x */ +#define GAIN_4x 0x10 /* 001 : 4x */ +#define GAIN_8x 0x20 /* 010 : 8x */ +#define GAIN_16x 0x30 /* 011 : 16x */ +#define GAIN_32x 0x40 /* 100 : 32x */ +#define GAIN_64x 0x50 /* 101 : 64x */ +#define GAIN_128x 0x60 /* 110 : 128x */ +#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ +#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ + +/* COM11 */ +#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */ +#define SGLF_TRIG 0x01 /* Single frame transfer trigger */ + +/* HREF */ +#define HREF_VSTART_SHIFT 6 /* VSTART LSB */ +#define HREF_HSTART_SHIFT 4 /* HSTART 2 LSBs */ +#define HREF_VSIZE_SHIFT 2 /* VSIZE LSB */ +#define HREF_HSIZE_SHIFT 0 /* HSIZE 2 LSBs */ + +/* EXHCH */ +#define EXHCH_VSIZE_SHIFT 2 /* VOUTSIZE LSB */ +#define EXHCH_HSIZE_SHIFT 0 /* HOUTSIZE 2 LSBs */ + +/* DSP_CTRL1 */ +#define FIFO_ON 0x80 /* FIFO enable/disable selection */ +#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */ +#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */ +#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */ +#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */ +#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */ +#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */ +#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */ + +/* DSP_CTRL3 */ +#define UV_MASK 0x80 /* UV output sequence option */ +#define UV_ON 0x80 /* ON */ +#define UV_OFF 0x00 /* OFF */ +#define CBAR_MASK 0x20 /* DSP Color bar mask */ +#define CBAR_ON 0x20 /* ON */ +#define CBAR_OFF 0x00 /* OFF */ + +/* DSP_CTRL4 */ +#define DSP_OFMT_YUV 0x00 +#define DSP_OFMT_RGB 0x00 +#define DSP_OFMT_RAW8 0x02 +#define DSP_OFMT_RAW10 0x03 + +/* DSPAUTO (DSP Auto Function ON/OFF Control) */ +#define AWB_ACTRL 0x80 /* AWB auto threshold control */ +#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */ +#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */ +#define UV_ACTRL 0x10 /* UV adjust auto slope control */ +#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ +#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ + +#define OV772X_MAX_WIDTH VGA_WIDTH +#define OV772X_MAX_HEIGHT VGA_HEIGHT + +/* + * ID + */ +#define OV7720 0x7720 +#define OV7725 0x7721 +#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) + +/* + * struct + */ + +struct ov772x_color_format { + u32 code; + enum v4l2_colorspace colorspace; + u8 dsp3; + u8 dsp4; + u8 com3; + u8 com7; +}; + +struct ov772x_win_size { + char *name; + unsigned char com7_bit; + struct v4l2_rect rect; +}; + +struct ov772x_priv { + struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct v4l2_clk *clk; + struct ov772x_camera_info *info; + const struct ov772x_color_format *cfmt; + const struct ov772x_win_size *win; + unsigned short flag_vflip:1; + unsigned short flag_hflip:1; + /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ + unsigned short band_filter; +}; + +/* + * supported color format list + */ +static const struct ov772x_color_format ov772x_cfmts[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = UV_ON, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = OFMT_YUV, + }, + { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_RGB, + .com7 = FMT_RGB555 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = FMT_RGB555 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = SWAP_RGB, + .com7 = FMT_RGB565 | OFMT_RGB, + }, + { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_YUV, + .com3 = 0x0, + .com7 = FMT_RGB565 | OFMT_RGB, + }, + { + /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output, + * regardless of the COM7 value. We can thus only support 10-bit + * Bayer until someone figures it out. + */ + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .dsp4 = DSP_OFMT_RAW10, + .com3 = 0x0, + .com7 = SENSOR_RAW | OFMT_BRAW, + }, +}; + + +/* + * window size list + */ + +static const struct ov772x_win_size ov772x_win_sizes[] = { + { + .name = "VGA", + .com7_bit = SLCT_VGA, + .rect = { + .left = 140, + .top = 14, + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + }, + }, { + .name = "QVGA", + .com7_bit = SLCT_QVGA, + .rect = { + .left = 252, + .top = 6, + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, + }, + }, +}; + +/* + * general function + */ + +static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov772x_priv, subdev); +} + +static inline int ov772x_read(struct i2c_client *client, u8 addr) +{ + return i2c_smbus_read_byte_data(client, addr); +} + +static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value) +{ + return i2c_smbus_write_byte_data(client, addr, value); +} + +static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask, + u8 set) +{ + s32 val = ov772x_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return ov772x_write(client, command, val); +} + +static int ov772x_reset(struct i2c_client *client) +{ + int ret; + + ret = ov772x_write(client, COM7, SCCB_RESET); + if (ret < 0) + return ret; + + msleep(1); + + return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); +} + +/* + * soc_camera_ops function + */ + +static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov772x_priv *priv = to_ov772x(sd); + + if (!enable) { + ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); + return 0; + } + + ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); + + dev_dbg(&client->dev, "format %d, win %s\n", + priv->cfmt->code, priv->win->name); + + return 0; +} + +static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov772x_priv *priv = container_of(ctrl->handler, + struct ov772x_priv, hdl); + struct v4l2_subdev *sd = &priv->subdev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + u8 val; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + val = ctrl->val ? VFLIP_IMG : 0x00; + priv->flag_vflip = ctrl->val; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val ^= VFLIP_IMG; + return ov772x_mask_set(client, COM3, VFLIP_IMG, val); + case V4L2_CID_HFLIP: + val = ctrl->val ? HFLIP_IMG : 0x00; + priv->flag_hflip = ctrl->val; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val ^= HFLIP_IMG; + return ov772x_mask_set(client, COM3, HFLIP_IMG, val); + case V4L2_CID_BAND_STOP_FILTER: + if (!ctrl->val) { + /* Switch the filter off, it is on now */ + ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); + if (!ret) + ret = ov772x_mask_set(client, COM8, + BNDF_ON_OFF, 0); + } else { + /* Switch the filter on, set AEC low limit */ + val = 256 - ctrl->val; + ret = ov772x_mask_set(client, COM8, + BNDF_ON_OFF, BNDF_ON_OFF); + if (!ret) + ret = ov772x_mask_set(client, BDBASE, + 0xff, val); + } + if (!ret) + priv->band_filter = ctrl->val; + return ret; + } + + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov772x_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 1; + if (reg->reg > 0xff) + return -EINVAL; + + ret = ov772x_read(client, reg->reg); + if (ret < 0) + return ret; + + reg->val = (__u64)ret; + + return 0; +} + +static int ov772x_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return ov772x_write(client, reg->reg, reg->val); +} +#endif + +static int ov772x_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct ov772x_priv *priv = to_ov772x(sd); + + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); +} + +static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) +{ + const struct ov772x_win_size *win = &ov772x_win_sizes[0]; + u32 best_diff = UINT_MAX; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) { + u32 diff = abs(width - ov772x_win_sizes[i].rect.width) + + abs(height - ov772x_win_sizes[i].rect.height); + if (diff < best_diff) { + best_diff = diff; + win = &ov772x_win_sizes[i]; + } + } + + return win; +} + +static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf, + const struct ov772x_color_format **cfmt, + const struct ov772x_win_size **win) +{ + unsigned int i; + + /* Select a format. */ + *cfmt = &ov772x_cfmts[0]; + + for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { + if (mf->code == ov772x_cfmts[i].code) { + *cfmt = &ov772x_cfmts[i]; + break; + } + } + + /* Select a window size. */ + *win = ov772x_select_win(mf->width, mf->height); +} + +static int ov772x_set_params(struct ov772x_priv *priv, + const struct ov772x_color_format *cfmt, + const struct ov772x_win_size *win) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + int ret; + u8 val; + + /* + * reset hardware + */ + ov772x_reset(client); + + /* + * Edge Ctrl + */ + if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { + + /* + * Manual Edge Control Mode + * + * Edge auto strength bit is set by default. + * Remove it when manual mode. + */ + + ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, + priv->info->edgectrl.threshold); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, + priv->info->edgectrl.strength); + if (ret < 0) + goto ov772x_set_fmt_error; + + } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) { + /* + * Auto Edge Control Mode + * + * set upper and lower limit + */ + ret = ov772x_mask_set(client, + EDGE_UPPER, OV772X_EDGE_UPPER_MASK, + priv->info->edgectrl.upper); + if (ret < 0) + goto ov772x_set_fmt_error; + + ret = ov772x_mask_set(client, + EDGE_LOWER, OV772X_EDGE_LOWER_MASK, + priv->info->edgectrl.lower); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* Format and window size */ + ret = ov772x_write(client, HSTART, win->rect.left >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HSIZE, win->rect.width >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VSTART, win->rect.top >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VSIZE, win->rect.height >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, HREF, + ((win->rect.top & 1) << HREF_VSTART_SHIFT) | + ((win->rect.left & 3) << HREF_HSTART_SHIFT) | + ((win->rect.height & 1) << HREF_VSIZE_SHIFT) | + ((win->rect.width & 3) << HREF_HSIZE_SHIFT)); + if (ret < 0) + goto ov772x_set_fmt_error; + ret = ov772x_write(client, EXHCH, + ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) | + ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT)); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set DSP_CTRL3 + */ + val = cfmt->dsp3; + if (val) { + ret = ov772x_mask_set(client, + DSP_CTRL3, UV_MASK, val); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* DSP_CTRL4: AEC reference point and DSP output format. */ + if (cfmt->dsp4) { + ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* + * set COM3 + */ + val = cfmt->com3; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val |= VFLIP_IMG; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val |= HFLIP_IMG; + if (priv->flag_vflip) + val ^= VFLIP_IMG; + if (priv->flag_hflip) + val ^= HFLIP_IMG; + + ret = ov772x_mask_set(client, + COM3, SWAP_MASK | IMG_MASK, val); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* COM7: Sensor resolution and output format control. */ + ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set COM8 + */ + if (priv->band_filter) { + ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); + if (!ret) + ret = ov772x_mask_set(client, BDBASE, + 0xff, 256 - priv->band_filter); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + return ret; + +ov772x_set_fmt_error: + + ov772x_reset(client); + + return ret; +} + +static int ov772x_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.width = OV772X_MAX_WIDTH; + sel->r.height = OV772X_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r.width = VGA_WIDTH; + sel->r.height = VGA_HEIGHT; + return 0; + default: + return -EINVAL; + } +} + +static int ov772x_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct ov772x_priv *priv = to_ov772x(sd); + + if (format->pad) + return -EINVAL; + + mf->width = priv->win->rect.width; + mf->height = priv->win->rect.height; + mf->code = priv->cfmt->code; + mf->colorspace = priv->cfmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov772x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_mbus_framefmt *mf = &format->format; + const struct ov772x_color_format *cfmt; + const struct ov772x_win_size *win; + int ret; + + if (format->pad) + return -EINVAL; + + ov772x_select_params(mf, &cfmt, &win); + + mf->code = cfmt->code; + mf->width = win->rect.width; + mf->height = win->rect.height; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = cfmt->colorspace; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + + ret = ov772x_set_params(priv, cfmt, win); + if (ret < 0) + return ret; + + priv->win = win; + priv->cfmt = cfmt; + return 0; +} + +static int ov772x_video_probe(struct ov772x_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + u8 pid, ver; + const char *devname; + int ret; + + ret = ov772x_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * check and show product ID and manufacturer ID + */ + pid = ov772x_read(client, PID); + ver = ov772x_read(client, VER); + + switch (VERSION(pid, ver)) { + case OV7720: + devname = "ov7720"; + break; + case OV7725: + devname = "ov7725"; + break; + default: + dev_err(&client->dev, + "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, + "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, + pid, + ver, + ov772x_read(client, MIDH), + ov772x_read(client, MIDL)); + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov772x_s_power(&priv->subdev, 0); + return ret; +} + +static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { + .s_ctrl = ov772x_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov772x_g_register, + .s_register = ov772x_s_register, +#endif + .s_power = ov772x_s_power, +}; + +static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) + return -EINVAL; + + code->code = ov772x_cfmts[code->index].code; + return 0; +} + +static int ov772x_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { + .s_stream = ov772x_s_stream, + .g_mbus_config = ov772x_g_mbus_config, +}; + +static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { + .enum_mbus_code = ov772x_enum_mbus_code, + .get_selection = ov772x_get_selection, + .get_fmt = ov772x_get_fmt, + .set_fmt = ov772x_set_fmt, +}; + +static const struct v4l2_subdev_ops ov772x_subdev_ops = { + .core = &ov772x_subdev_core_ops, + .video = &ov772x_subdev_video_ops, + .pad = &ov772x_subdev_pad_ops, +}; + +/* + * i2c_driver function + */ + +static int ov772x_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov772x_priv *priv; + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + + if (!ssdd || !ssdd->drv_priv) { + dev_err(&client->dev, "OV772X: missing platform data!\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_PROTOCOL_MANGLING)) { + dev_err(&adapter->dev, + "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n"); + return -EIO; + } + client->flags |= I2C_CLIENT_SCCB; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = ssdd->drv_priv; + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 3); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) + return priv->hdl.error; + + priv->clk = v4l2_clk_get(&client->dev, "mclk"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto eclkget; + } + + ret = ov772x_video_probe(priv); + if (ret < 0) { + v4l2_clk_put(priv->clk); +eclkget: + v4l2_ctrl_handler_free(&priv->hdl); + } else { + priv->cfmt = &ov772x_cfmts[0]; + priv->win = &ov772x_win_sizes[0]; + } + + return ret; +} + +static int ov772x_remove(struct i2c_client *client) +{ + struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client)); + + v4l2_clk_put(priv->clk); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); + return 0; +} + +static const struct i2c_device_id ov772x_id[] = { + { "ov772x", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov772x_id); + +static struct i2c_driver ov772x_i2c_driver = { + .driver = { + .name = "ov772x", + }, + .probe = ov772x_probe, + .remove = ov772x_remove, + .id_table = ov772x_id, +}; + +module_i2c_driver(ov772x_i2c_driver); + +MODULE_DESCRIPTION("SoC Camera driver for ov772x"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); -- cgit From 762c28121d7cf183db6ef70988d3b47bb60e4869 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 21 Feb 2018 12:48:00 -0500 Subject: media: i2c: ov772x: Remove soc_camera dependencies Remove soc_camera framework dependencies from ov772x sensor driver. - Handle clock and gpios - Register async subdevice - Remove soc_camera specific g/s_mbus_config operations - Change image format colorspace from JPEG to SRGB as the two use the same colorspace information but JPEG makes assumptions on color components quantization that do not apply to the sensor - Remove sizes crop from get_selection as driver can't scale - Add kernel doc to driver interface header file - Adjust build system This commit does not remove the original soc_camera based driver as long as other platforms depends on soc_camera-based CEU driver. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 +++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov772x.c | 172 ++++++++++++++++++++++++++++++--------------- 3 files changed, 129 insertions(+), 55 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index ef2e1dea253b..038b63d74c3c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -677,6 +677,17 @@ config VIDEO_OV5695 To compile this driver as a module, choose M here: the module will be called ov5695. +config VIDEO_OV772X + tristate "OmniVision OV772x sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV772x camera. + + To compile this driver as a module, choose M here: the + module will be called ov772x. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index e4f420d730e8..2d712c81cc28 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 806383500313..23106d7742e5 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1,6 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ov772x Camera Driver * + * Copyright (C) 2017 Jacopo Mondi + * * Copyright (C) 2008 Renesas Solutions Corp. * Kuninori Morimoto * @@ -9,27 +12,25 @@ * Copyright 2006-7 Jonathan Corbet * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ +#include +#include +#include +#include #include #include #include -#include #include -#include #include #include #include -#include -#include + #include -#include +#include #include +#include /* * register offset @@ -393,8 +394,10 @@ struct ov772x_win_size { struct ov772x_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; - struct v4l2_clk *clk; + struct clk *clk; struct ov772x_camera_info *info; + struct gpio_desc *pwdn_gpio; + struct gpio_desc *rstb_gpio; const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; unsigned short flag_vflip:1; @@ -409,7 +412,7 @@ struct ov772x_priv { static const struct ov772x_color_format ov772x_cfmts[] = { { .code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, + .colorspace = V4L2_COLORSPACE_SRGB, .dsp3 = 0x0, .dsp4 = DSP_OFMT_YUV, .com3 = SWAP_YUV, @@ -417,7 +420,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = { }, { .code = MEDIA_BUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, + .colorspace = V4L2_COLORSPACE_SRGB, .dsp3 = UV_ON, .dsp4 = DSP_OFMT_YUV, .com3 = SWAP_YUV, @@ -425,7 +428,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = { }, { .code = MEDIA_BUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, + .colorspace = V4L2_COLORSPACE_SRGB, .dsp3 = 0x0, .dsp4 = DSP_OFMT_YUV, .com3 = 0x0, @@ -550,7 +553,7 @@ static int ov772x_reset(struct i2c_client *client) } /* - * soc_camera_ops function + * subdev ops */ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) @@ -650,13 +653,65 @@ static int ov772x_s_register(struct v4l2_subdev *sd, } #endif +static int ov772x_power_on(struct ov772x_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + int ret; + + if (priv->clk) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + if (priv->pwdn_gpio) { + gpiod_set_value(priv->pwdn_gpio, 1); + usleep_range(500, 1000); + } + + /* + * FIXME: The reset signal is connected to a shared GPIO on some + * platforms (namely the SuperH Migo-R). Until a framework becomes + * available to handle this cleanly, request the GPIO temporarily + * to avoid conflicts. + */ + priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb", + GPIOD_OUT_LOW); + if (IS_ERR(priv->rstb_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + return PTR_ERR(priv->rstb_gpio); + } + + if (priv->rstb_gpio) { + gpiod_set_value(priv->rstb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(priv->rstb_gpio, 0); + usleep_range(500, 1000); + + gpiod_put(priv->rstb_gpio); + } + + return 0; +} + +static int ov772x_power_off(struct ov772x_priv *priv) +{ + clk_disable_unprepare(priv->clk); + + if (priv->pwdn_gpio) { + gpiod_set_value(priv->pwdn_gpio, 0); + usleep_range(500, 1000); + } + + return 0; +} + static int ov772x_s_power(struct v4l2_subdev *sd, int on) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov772x_priv *priv = to_ov772x(sd); - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + return on ? ov772x_power_on(priv) : + ov772x_power_off(priv); } static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) @@ -855,6 +910,8 @@ static int ov772x_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { + struct ov772x_priv *priv = to_ov772x(sd); + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; @@ -863,12 +920,9 @@ static int ov772x_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.width = OV772X_MAX_WIDTH; - sel->r.height = OV772X_MAX_HEIGHT; - return 0; case V4L2_SEL_TGT_CROP: - sel->r.width = VGA_WIDTH; - sel->r.height = VGA_HEIGHT; + sel->r.width = priv->win->rect.width; + sel->r.height = priv->win->rect.height; return 0; default: return -EINVAL; @@ -914,6 +968,9 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd, mf->height = win->rect.height; mf->field = V4L2_FIELD_NONE; mf->colorspace = cfmt->colorspace; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { cfg->try_fmt = *mf; @@ -997,24 +1054,8 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int ov772x_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, - .g_mbus_config = ov772x_g_mbus_config, }; static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { @@ -1038,12 +1079,11 @@ static int ov772x_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov772x_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "OV772X: missing platform data!\n"); + if (!client->dev.platform_data) { + dev_err(&client->dev, "Missing ov772x platform data\n"); return -EINVAL; } @@ -1059,7 +1099,7 @@ static int ov772x_probe(struct i2c_client *client, if (!priv) return -ENOMEM; - priv->info = ssdd->drv_priv; + priv->info = client->dev.platform_data; v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 3); @@ -1073,22 +1113,42 @@ static int ov772x_probe(struct i2c_client *client, if (priv->hdl.error) return priv->hdl.error; - priv->clk = v4l2_clk_get(&client->dev, "mclk"); + priv->clk = clk_get(&client->dev, "xclk"); if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get xclk clock\n"); ret = PTR_ERR(priv->clk); - goto eclkget; + goto error_ctrl_free; } - ret = ov772x_video_probe(priv); - if (ret < 0) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } else { - priv->cfmt = &ov772x_cfmts[0]; - priv->win = &ov772x_win_sizes[0]; + priv->pwdn_gpio = gpiod_get_optional(&client->dev, "pwdn", + GPIOD_OUT_LOW); + if (IS_ERR(priv->pwdn_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"pwdn\""); + ret = PTR_ERR(priv->pwdn_gpio); + goto error_clk_put; } + ret = ov772x_video_probe(priv); + if (ret < 0) + goto error_gpio_put; + + priv->cfmt = &ov772x_cfmts[0]; + priv->win = &ov772x_win_sizes[0]; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto error_gpio_put; + + return 0; + +error_gpio_put: + if (priv->pwdn_gpio) + gpiod_put(priv->pwdn_gpio); +error_clk_put: + clk_put(priv->clk); +error_ctrl_free: + v4l2_ctrl_handler_free(&priv->hdl); + return ret; } @@ -1096,7 +1156,9 @@ static int ov772x_remove(struct i2c_client *client) { struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client)); - v4l2_clk_put(priv->clk); + clk_put(priv->clk); + if (priv->pwdn_gpio) + gpiod_put(priv->pwdn_gpio); v4l2_device_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; @@ -1119,6 +1181,6 @@ static struct i2c_driver ov772x_i2c_driver = { module_i2c_driver(ov772x_i2c_driver); -MODULE_DESCRIPTION("SoC Camera driver for ov772x"); +MODULE_DESCRIPTION("V4L2 driver for OV772x image sensor"); MODULE_AUTHOR("Kuninori Morimoto"); MODULE_LICENSE("GPL v2"); -- cgit From 350894918ee932f70034e485cb91e6fdd00152bb Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 21 Feb 2018 12:48:01 -0500 Subject: media: i2c: ov772x: Support frame interval handling Add support to ov772x driver for frame intervals handling and enumeration. Tested with 10MHz and 24MHz input clock at VGA and QVGA resolutions for 10, 15 and 30 frame per second rates. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 213 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 196 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 23106d7742e5..3edf0cb6fd0e 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -250,6 +250,7 @@ #define AEC_1p2 0x10 /* 01: 1/2 window */ #define AEC_1p4 0x20 /* 10: 1/4 window */ #define AEC_2p3 0x30 /* 11: Low 2/3 window */ +#define COM4_RESERVED 0x01 /* Reserved bit */ /* COM5 */ #define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ @@ -267,6 +268,10 @@ /* AEC max step control */ #define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ /* 1 : No limit to AEC increase step */ +/* CLKRC */ + /* Input clock divider register */ +#define CLKRC_RESERVED 0x80 /* Reserved bit */ +#define CLKRC_DIV(n) ((n) - 1) /* COM7 */ /* SCCB Register Reset */ @@ -372,6 +377,19 @@ #define OV7725 0x7721 #define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) +/* + * PLL multipliers + */ +static struct { + unsigned int mult; + u8 com4; +} ov772x_pll[] = { + { 1, PLL_BYPASS, }, + { 4, PLL_4x, }, + { 6, PLL_6x, }, + { 8, PLL_8x, }, +}; + /* * struct */ @@ -388,6 +406,7 @@ struct ov772x_color_format { struct ov772x_win_size { char *name; unsigned char com7_bit; + unsigned int sizeimage; struct v4l2_rect rect; }; @@ -404,6 +423,7 @@ struct ov772x_priv { unsigned short flag_hflip:1; /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ unsigned short band_filter; + unsigned int fps; }; /* @@ -487,26 +507,33 @@ static const struct ov772x_color_format ov772x_cfmts[] = { static const struct ov772x_win_size ov772x_win_sizes[] = { { - .name = "VGA", - .com7_bit = SLCT_VGA, + .name = "VGA", + .com7_bit = SLCT_VGA, + .sizeimage = 510 * 748, .rect = { - .left = 140, - .top = 14, - .width = VGA_WIDTH, - .height = VGA_HEIGHT, + .left = 140, + .top = 14, + .width = VGA_WIDTH, + .height = VGA_HEIGHT, }, }, { - .name = "QVGA", - .com7_bit = SLCT_QVGA, + .name = "QVGA", + .com7_bit = SLCT_QVGA, + .sizeimage = 278 * 576, .rect = { - .left = 252, - .top = 6, - .width = QVGA_WIDTH, - .height = QVGA_HEIGHT, + .left = 252, + .top = 6, + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, }, }, }; +/* + * frame rate settings lists + */ +static unsigned int ov772x_frame_intervals[] = { 5, 10, 15, 20, 30, 60 }; + /* * general function */ @@ -574,6 +601,128 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static int ov772x_set_frame_rate(struct ov772x_priv *priv, + struct v4l2_fract *tpf, + const struct ov772x_color_format *cfmt, + const struct ov772x_win_size *win) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + unsigned long fin = clk_get_rate(priv->clk); + unsigned int fps = tpf->numerator ? + tpf->denominator / tpf->numerator : + tpf->denominator; + unsigned int best_diff; + unsigned int fsize; + unsigned int pclk; + unsigned int diff; + unsigned int idx; + unsigned int i; + u8 clkrc = 0; + u8 com4 = 0; + int ret; + + /* Approximate to the closest supported frame interval. */ + best_diff = ~0L; + for (i = 0, idx = 0; i < ARRAY_SIZE(ov772x_frame_intervals); i++) { + diff = abs(fps - ov772x_frame_intervals[i]); + if (diff < best_diff) { + idx = i; + best_diff = diff; + } + } + fps = ov772x_frame_intervals[idx]; + + /* Use image size (with blankings) to calculate desired pixel clock. */ + switch (cfmt->com7 & OFMT_MASK) { + case OFMT_BRAW: + fsize = win->sizeimage; + break; + case OFMT_RGB: + case OFMT_YUV: + default: + fsize = win->sizeimage * 2; + break; + } + + pclk = fps * fsize; + + /* + * Pixel clock generation circuit is pretty simple: + * + * Fin -> [ / CLKRC_div] -> [ * PLL_mult] -> pclk + * + * Try to approximate the desired pixel clock testing all available + * PLL multipliers (1x, 4x, 6x, 8x) and calculate corresponding + * divisor with: + * + * div = PLL_mult * Fin / pclk + * + * and re-calculate the pixel clock using it: + * + * pclk = Fin * PLL_mult / CLKRC_div + * + * Choose the PLL_mult and CLKRC_div pair that gives a pixel clock + * closer to the desired one. + * + * The desired pixel clock is calculated using a known frame size + * (blanking included) and FPS. + */ + best_diff = ~0L; + for (i = 0; i < ARRAY_SIZE(ov772x_pll); i++) { + unsigned int pll_mult = ov772x_pll[i].mult; + unsigned int pll_out = pll_mult * fin; + unsigned int t_pclk; + unsigned int div; + + if (pll_out < pclk) + continue; + + div = DIV_ROUND_CLOSEST(pll_out, pclk); + t_pclk = DIV_ROUND_CLOSEST(fin * pll_mult, div); + diff = abs(pclk - t_pclk); + if (diff < best_diff) { + best_diff = diff; + clkrc = CLKRC_DIV(div); + com4 = ov772x_pll[i].com4; + } + } + + ret = ov772x_write(client, COM4, com4 | COM4_RESERVED); + if (ret < 0) + return ret; + + ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED); + if (ret < 0) + return ret; + + tpf->numerator = 1; + tpf->denominator = fps; + priv->fps = tpf->denominator; + + return 0; +} + +static int ov772x_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_fract *tpf = &ival->interval; + + tpf->numerator = 1; + tpf->denominator = priv->fps; + + return 0; +} + +static int ov772x_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *ival) +{ + struct ov772x_priv *priv = to_ov772x(sd); + struct v4l2_fract *tpf = &ival->interval; + + return ov772x_set_frame_rate(priv, tpf, priv->cfmt, priv->win); +} + static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov772x_priv *priv = container_of(ctrl->handler, @@ -757,6 +906,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, const struct ov772x_win_size *win) { struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + struct v4l2_fract tpf; int ret; u8 val; @@ -885,6 +1035,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, if (ret < 0) goto ov772x_set_fmt_error; + /* COM4, CLKRC: Set pixel clock and framerate. */ + tpf.numerator = 1; + tpf.denominator = priv->fps; + ret = ov772x_set_frame_rate(priv, &tpf, cfmt, win); + if (ret < 0) + goto ov772x_set_fmt_error; + /* * set COM8 */ @@ -1043,6 +1200,24 @@ static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { .s_power = ov772x_s_power, }; +static int ov772x_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + if (fie->pad || fie->index >= ARRAY_SIZE(ov772x_frame_intervals)) + return -EINVAL; + + if (fie->width != VGA_WIDTH && fie->width != QVGA_WIDTH) + return -EINVAL; + if (fie->height != VGA_HEIGHT && fie->height != QVGA_HEIGHT) + return -EINVAL; + + fie->interval.numerator = 1; + fie->interval.denominator = ov772x_frame_intervals[fie->index]; + + return 0; +} + static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) @@ -1055,14 +1230,17 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, } static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { - .s_stream = ov772x_s_stream, + .s_stream = ov772x_s_stream, + .s_frame_interval = ov772x_s_frame_interval, + .g_frame_interval = ov772x_g_frame_interval, }; static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { - .enum_mbus_code = ov772x_enum_mbus_code, - .get_selection = ov772x_get_selection, - .get_fmt = ov772x_get_fmt, - .set_fmt = ov772x_set_fmt, + .enum_frame_interval = ov772x_enum_frame_interval, + .enum_mbus_code = ov772x_enum_mbus_code, + .get_selection = ov772x_get_selection, + .get_fmt = ov772x_get_fmt, + .set_fmt = ov772x_set_fmt, }; static const struct v4l2_subdev_ops ov772x_subdev_ops = { @@ -1134,6 +1312,7 @@ static int ov772x_probe(struct i2c_client *client, priv->cfmt = &ov772x_cfmts[0]; priv->win = &ov772x_win_sizes[0]; + priv->fps = 15; ret = v4l2_async_register_subdev(&priv->subdev); if (ret) -- cgit From e0d76c3842ee4ac417792393e7140858ae5d3b93 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 21 Feb 2018 12:48:02 -0500 Subject: media: i2c: Copy tw9910 soc_camera sensor driver Copy the soc_camera based driver in v4l2 sensor driver directory. This commit just copies the original file without modifying it. No modification to KConfig and Makefile as soc_camera framework dependencies need to be removed first in next commit. Signed-off-by: Jacopo Mondi Acked-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 999 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 999 insertions(+) create mode 100644 drivers/media/i2c/tw9910.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c new file mode 100644 index 000000000000..bdb5e0a431e9 --- /dev/null +++ b/drivers/media/i2c/tw9910.c @@ -0,0 +1,999 @@ +/* + * tw9910 Video Driver + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov772x driver, + * + * Copyright (C) 2008 Kuninori Morimoto + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define GET_ID(val) ((val & 0xF8) >> 3) +#define GET_REV(val) (val & 0x07) + +/* + * register offset + */ +#define ID 0x00 /* Product ID Code Register */ +#define STATUS1 0x01 /* Chip Status Register I */ +#define INFORM 0x02 /* Input Format */ +#define OPFORM 0x03 /* Output Format Control Register */ +#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */ +#define OUTCTR1 0x05 /* Output Control I */ +#define ACNTL1 0x06 /* Analog Control Register 1 */ +#define CROP_HI 0x07 /* Cropping Register, High */ +#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */ +#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */ +#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */ +#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */ +#define CNTRL1 0x0C /* Control Register I */ +#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */ +#define SCALE_HI 0x0E /* Scaling Register, High */ +#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */ +#define BRIGHT 0x10 /* BRIGHTNESS Control Register */ +#define CONTRAST 0x11 /* CONTRAST Control Register */ +#define SHARPNESS 0x12 /* SHARPNESS Control Register I */ +#define SAT_U 0x13 /* Chroma (U) Gain Register */ +#define SAT_V 0x14 /* Chroma (V) Gain Register */ +#define HUE 0x15 /* Hue Control Register */ +#define CORING1 0x17 +#define CORING2 0x18 /* Coring and IF compensation */ +#define VBICNTL 0x19 /* VBI Control Register */ +#define ACNTL2 0x1A /* Analog Control 2 */ +#define OUTCTR2 0x1B /* Output Control 2 */ +#define SDT 0x1C /* Standard Selection */ +#define SDTR 0x1D /* Standard Recognition */ +#define TEST 0x1F /* Test Control Register */ +#define CLMPG 0x20 /* Clamping Gain */ +#define IAGC 0x21 /* Individual AGC Gain */ +#define AGCGAIN 0x22 /* AGC Gain */ +#define PEAKWT 0x23 /* White Peak Threshold */ +#define CLMPL 0x24 /* Clamp level */ +#define SYNCT 0x25 /* Sync Amplitude */ +#define MISSCNT 0x26 /* Sync Miss Count Register */ +#define PCLAMP 0x27 /* Clamp Position Register */ +#define VCNTL1 0x28 /* Vertical Control I */ +#define VCNTL2 0x29 /* Vertical Control II */ +#define CKILL 0x2A /* Color Killer Level Control */ +#define COMB 0x2B /* Comb Filter Control */ +#define LDLY 0x2C /* Luma Delay and H Filter Control */ +#define MISC1 0x2D /* Miscellaneous Control I */ +#define LOOP 0x2E /* LOOP Control Register */ +#define MISC2 0x2F /* Miscellaneous Control II */ +#define MVSN 0x30 /* Macrovision Detection */ +#define STATUS2 0x31 /* Chip STATUS II */ +#define HFREF 0x32 /* H monitor */ +#define CLMD 0x33 /* CLAMP MODE */ +#define IDCNTL 0x34 /* ID Detection Control */ +#define CLCNTL1 0x35 /* Clamp Control I */ +#define ANAPLLCTL 0x4C +#define VBIMIN 0x4D +#define HSLOWCTL 0x4E +#define WSS3 0x4F +#define FILLDATA 0x50 +#define SDID 0x51 +#define DID 0x52 +#define WSS1 0x53 +#define WSS2 0x54 +#define VVBI 0x55 +#define LCTL6 0x56 +#define LCTL7 0x57 +#define LCTL8 0x58 +#define LCTL9 0x59 +#define LCTL10 0x5A +#define LCTL11 0x5B +#define LCTL12 0x5C +#define LCTL13 0x5D +#define LCTL14 0x5E +#define LCTL15 0x5F +#define LCTL16 0x60 +#define LCTL17 0x61 +#define LCTL18 0x62 +#define LCTL19 0x63 +#define LCTL20 0x64 +#define LCTL21 0x65 +#define LCTL22 0x66 +#define LCTL23 0x67 +#define LCTL24 0x68 +#define LCTL25 0x69 +#define LCTL26 0x6A +#define HSBEGIN 0x6B +#define HSEND 0x6C +#define OVSDLY 0x6D +#define OVSEND 0x6E +#define VBIDELAY 0x6F + +/* + * register detail + */ + +/* INFORM */ +#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */ +#define FC27_FF 0x00 /* 0 : Square pixel mode. */ + /* Must use 24.54MHz for 60Hz field rate */ + /* source or 29.5MHz for 50Hz field rate */ +#define IFSEL_S 0x10 /* 01 : S-video decoding */ +#define IFSEL_C 0x00 /* 00 : Composite video decoding */ + /* Y input video selection */ +#define YSEL_M0 0x00 /* 00 : Mux0 selected */ +#define YSEL_M1 0x04 /* 01 : Mux1 selected */ +#define YSEL_M2 0x08 /* 10 : Mux2 selected */ +#define YSEL_M3 0x10 /* 11 : Mux3 selected */ + +/* OPFORM */ +#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */ + /* 1 : ITU-R-656 compatible data sequence format */ +#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */ + /* 1 : 16-bit YCrCb 4:2:2 output format.*/ +#define LLCMODE 0x20 /* 1 : LLC output mode. */ + /* 0 : free-run output mode */ +#define AINC 0x10 /* Serial interface auto-indexing control */ + /* 0 : auto-increment */ + /* 1 : non-auto */ +#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ + /* 0 : Vertical out ctrl by HACTIVE and DVALID */ +#define OEN_TRI_SEL_MASK 0x07 +#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ +#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ +#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ + +/* OUTCTR1 */ +#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ +#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */ + /* VS pin output control */ +#define VSSL_VSYNC 0x00 /* 0 : VSYNC */ +#define VSSL_VACT 0x10 /* 1 : VACT */ +#define VSSL_FIELD 0x20 /* 2 : FIELD */ +#define VSSL_VVALID 0x30 /* 3 : VVALID */ +#define VSSL_ZERO 0x70 /* 7 : 0 */ +#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */ +#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/ + /* HS pin output control */ +#define HSSL_HACT 0x00 /* 0 : HACT */ +#define HSSL_HSYNC 0x01 /* 1 : HSYNC */ +#define HSSL_DVALID 0x02 /* 2 : DVALID */ +#define HSSL_HLOCK 0x03 /* 3 : HLOCK */ +#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */ +#define HSSL_ZERO 0x07 /* 7 : 0 */ + +/* ACNTL1 */ +#define SRESET 0x80 /* resets the device to its default state + * but all register content remain unchanged. + * This bit is self-resetting. + */ +#define ACNTL1_PDN_MASK 0x0e +#define CLK_PDN 0x08 /* system clock power down */ +#define Y_PDN 0x04 /* Luma ADC power down */ +#define C_PDN 0x02 /* Chroma ADC power down */ + +/* ACNTL2 */ +#define ACNTL2_PDN_MASK 0x40 +#define PLL_PDN 0x40 /* PLL power down */ + +/* VBICNTL */ + +/* RTSEL : control the real time signal output from the MPOUT pin */ +#define RTSEL_MASK 0x07 +#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ +#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ +#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */ +#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */ +#define RTSEL_MONO 0x04 /* 0100 = MONO */ +#define RTSEL_DET50 0x05 /* 0101 = DET50 */ +#define RTSEL_FIELD 0x06 /* 0110 = FIELD */ +#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ + +/* HSYNC start and end are constant for now */ +#define HSYNC_START 0x0260 +#define HSYNC_END 0x0300 + +/* + * structure + */ + +struct regval_list { + unsigned char reg_num; + unsigned char value; +}; + +struct tw9910_scale_ctrl { + char *name; + unsigned short width; + unsigned short height; + u16 hscale; + u16 vscale; +}; + +struct tw9910_priv { + struct v4l2_subdev subdev; + struct v4l2_clk *clk; + struct tw9910_video_info *info; + const struct tw9910_scale_ctrl *scale; + v4l2_std_id norm; + u32 revision; +}; + +static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { + { + .name = "NTSC SQ", + .width = 640, + .height = 480, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "NTSC CCIR601", + .width = 720, + .height = 480, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "NTSC SQ (CIF)", + .width = 320, + .height = 240, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "NTSC CCIR601 (CIF)", + .width = 360, + .height = 240, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "NTSC SQ (QCIF)", + .width = 160, + .height = 120, + .hscale = 0x0400, + .vscale = 0x0400, + }, + { + .name = "NTSC CCIR601 (QCIF)", + .width = 180, + .height = 120, + .hscale = 0x0400, + .vscale = 0x0400, + }, +}; + +static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { + { + .name = "PAL SQ", + .width = 768, + .height = 576, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "PAL CCIR601", + .width = 720, + .height = 576, + .hscale = 0x0100, + .vscale = 0x0100, + }, + { + .name = "PAL SQ (CIF)", + .width = 384, + .height = 288, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "PAL CCIR601 (CIF)", + .width = 360, + .height = 288, + .hscale = 0x0200, + .vscale = 0x0200, + }, + { + .name = "PAL SQ (QCIF)", + .width = 192, + .height = 144, + .hscale = 0x0400, + .vscale = 0x0400, + }, + { + .name = "PAL CCIR601 (QCIF)", + .width = 180, + .height = 144, + .hscale = 0x0400, + .vscale = 0x0400, + }, +}; + +/* + * general function + */ +static struct tw9910_priv *to_tw9910(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct tw9910_priv, + subdev); +} + +static int tw9910_mask_set(struct i2c_client *client, u8 command, + u8 mask, u8 set) +{ + s32 val = i2c_smbus_read_byte_data(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return i2c_smbus_write_byte_data(client, command, val); +} + +static int tw9910_set_scale(struct i2c_client *client, + const struct tw9910_scale_ctrl *scale) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, SCALE_HI, + (scale->vscale & 0x0F00) >> 4 | + (scale->hscale & 0x0F00) >> 8); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, HSCALE_LO, + scale->hscale & 0x00FF); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, VSCALE_LO, + scale->vscale & 0x00FF); + + return ret; +} + +static int tw9910_set_hsync(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + int ret; + + /* bit 10 - 3 */ + ret = i2c_smbus_write_byte_data(client, HSBEGIN, + (HSYNC_START & 0x07F8) >> 3); + if (ret < 0) + return ret; + + /* bit 10 - 3 */ + ret = i2c_smbus_write_byte_data(client, HSEND, + (HSYNC_END & 0x07F8) >> 3); + if (ret < 0) + return ret; + + /* So far only revisions 0 and 1 have been seen */ + /* bit 2 - 0 */ + if (1 == priv->revision) + ret = tw9910_mask_set(client, HSLOWCTL, 0x77, + (HSYNC_START & 0x0007) << 4 | + (HSYNC_END & 0x0007)); + + return ret; +} + +static void tw9910_reset(struct i2c_client *client) +{ + tw9910_mask_set(client, ACNTL1, SRESET, SRESET); + msleep(1); +} + +static int tw9910_power(struct i2c_client *client, int enable) +{ + int ret; + u8 acntl1; + u8 acntl2; + + if (enable) { + acntl1 = 0; + acntl2 = 0; + } else { + acntl1 = CLK_PDN | Y_PDN | C_PDN; + acntl2 = PLL_PDN; + } + + ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); + if (ret < 0) + return ret; + + return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); +} + +static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, + u32 width, u32 height) +{ + const struct tw9910_scale_ctrl *scale; + const struct tw9910_scale_ctrl *ret = NULL; + __u32 diff = 0xffffffff, tmp; + int size, i; + + if (norm & V4L2_STD_NTSC) { + scale = tw9910_ntsc_scales; + size = ARRAY_SIZE(tw9910_ntsc_scales); + } else if (norm & V4L2_STD_PAL) { + scale = tw9910_pal_scales; + size = ARRAY_SIZE(tw9910_pal_scales); + } else { + return NULL; + } + + for (i = 0; i < size; i++) { + tmp = abs(width - scale[i].width) + + abs(height - scale[i].height); + if (tmp < diff) { + diff = tmp; + ret = scale + i; + } + } + + return ret; +} + +/* + * subdevice operations + */ +static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + u8 val; + int ret; + + if (!enable) { + switch (priv->revision) { + case 0: + val = OEN_TRI_SEL_ALL_OFF_r0; + break; + case 1: + val = OEN_TRI_SEL_ALL_OFF_r1; + break; + default: + dev_err(&client->dev, "un-supported revision\n"); + return -EINVAL; + } + } else { + val = OEN_TRI_SEL_ALL_ON; + + if (!priv->scale) { + dev_err(&client->dev, "norm select error\n"); + return -EPERM; + } + + dev_dbg(&client->dev, "%s %dx%d\n", + priv->scale->name, + priv->scale->width, + priv->scale->height); + } + + ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); + if (ret < 0) + return ret; + + return tw9910_power(client, enable); +} + +static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + *norm = priv->norm; + + return 0; +} + +static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + const unsigned hact = 720; + const unsigned hdelay = 15; + unsigned vact; + unsigned vdelay; + int ret; + + if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) + return -EINVAL; + + priv->norm = norm; + if (norm & V4L2_STD_525_60) { + vact = 240; + vdelay = 18; + ret = tw9910_mask_set(client, VVBI, 0x10, 0x10); + } else { + vact = 288; + vdelay = 24; + ret = tw9910_mask_set(client, VVBI, 0x10, 0x00); + } + if (!ret) + ret = i2c_smbus_write_byte_data(client, CROP_HI, + ((vdelay >> 2) & 0xc0) | + ((vact >> 4) & 0x30) | + ((hdelay >> 6) & 0x0c) | + ((hact >> 8) & 0x03)); + if (!ret) + ret = i2c_smbus_write_byte_data(client, VDELAY_LO, + vdelay & 0xff); + if (!ret) + ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, + vact & 0xff); + + return ret; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int tw9910_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (reg->reg > 0xff) + return -EINVAL; + + reg->size = 1; + ret = i2c_smbus_read_byte_data(client, reg->reg); + if (ret < 0) + return ret; + + /* + * ret = int + * reg->val = __u64 + */ + reg->val = (__u64)ret; + + return 0; +} + +static int tw9910_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(client, reg->reg, reg->val); +} +#endif + +static int tw9910_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct tw9910_priv *priv = to_tw9910(client); + + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); +} + +static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + int ret = -EINVAL; + u8 val; + + /* + * select suitable norm + */ + priv->scale = tw9910_select_norm(priv->norm, *width, *height); + if (!priv->scale) + goto tw9910_set_fmt_error; + + /* + * reset hardware + */ + tw9910_reset(client); + + /* + * set bus width + */ + val = 0x00; + if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) + val = LEN; + + ret = tw9910_mask_set(client, OPFORM, LEN, val); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* + * select MPOUT behavior + */ + switch (priv->info->mpout) { + case TW9910_MPO_VLOSS: + val = RTSEL_VLOSS; break; + case TW9910_MPO_HLOCK: + val = RTSEL_HLOCK; break; + case TW9910_MPO_SLOCK: + val = RTSEL_SLOCK; break; + case TW9910_MPO_VLOCK: + val = RTSEL_VLOCK; break; + case TW9910_MPO_MONO: + val = RTSEL_MONO; break; + case TW9910_MPO_DET50: + val = RTSEL_DET50; break; + case TW9910_MPO_FIELD: + val = RTSEL_FIELD; break; + case TW9910_MPO_RTCO: + val = RTSEL_RTCO; break; + default: + val = 0; + } + + ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* + * set scale + */ + ret = tw9910_set_scale(client, priv->scale); + if (ret < 0) + goto tw9910_set_fmt_error; + + /* + * set hsync + */ + ret = tw9910_set_hsync(client); + if (ret < 0) + goto tw9910_set_fmt_error; + + *width = priv->scale->width; + *height = priv->scale->height; + + return ret; + +tw9910_set_fmt_error: + + tw9910_reset(client); + priv->scale = NULL; + + return ret; +} + +static int tw9910_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */ + if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + if (priv->norm & V4L2_STD_NTSC) { + sel->r.width = 640; + sel->r.height = 480; + } else { + sel->r.width = 768; + sel->r.height = 576; + } + return 0; +} + +static int tw9910_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + if (format->pad) + return -EINVAL; + + if (!priv->scale) { + priv->scale = tw9910_select_norm(priv->norm, 640, 480); + if (!priv->scale) + return -EINVAL; + } + + mf->width = priv->scale->width; + mf->height = priv->scale->height; + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->field = V4L2_FIELD_INTERLACED_BT; + + return 0; +} + +static int tw9910_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u32 width = mf->width, height = mf->height; + int ret; + + WARN_ON(mf->field != V4L2_FIELD_ANY && + mf->field != V4L2_FIELD_INTERLACED_BT); + + /* + * check color format + */ + if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8) + return -EINVAL; + + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = tw9910_set_frame(sd, &width, &height); + if (!ret) { + mf->width = width; + mf->height = height; + } + return ret; +} + +static int tw9910_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + const struct tw9910_scale_ctrl *scale; + + if (format->pad) + return -EINVAL; + + if (V4L2_FIELD_ANY == mf->field) { + mf->field = V4L2_FIELD_INTERLACED_BT; + } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { + dev_err(&client->dev, "Field type %d invalid.\n", mf->field); + return -EINVAL; + } + + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + /* + * select suitable norm + */ + scale = tw9910_select_norm(priv->norm, mf->width, mf->height); + if (!scale) + return -EINVAL; + + mf->width = scale->width; + mf->height = scale->height; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return tw9910_s_fmt(sd, mf); + cfg->try_fmt = *mf; + return 0; +} + +static int tw9910_video_probe(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + s32 id; + int ret; + + /* + * tw9910 only use 8 or 16 bit bus width + */ + if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && + SOCAM_DATAWIDTH_8 != priv->info->buswidth) { + dev_err(&client->dev, "bus width error\n"); + return -ENODEV; + } + + ret = tw9910_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * check and show Product ID + * So far only revisions 0 and 1 have been seen + */ + id = i2c_smbus_read_byte_data(client, ID); + priv->revision = GET_REV(id); + id = GET_ID(id); + + if (0x0B != id || + 0x01 < priv->revision) { + dev_err(&client->dev, + "Product ID error %x:%x\n", + id, priv->revision); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, + "tw9910 Product ID %0x:%0x\n", id, priv->revision); + + priv->norm = V4L2_STD_NTSC; + priv->scale = &tw9910_ntsc_scales[0]; + +done: + tw9910_s_power(&priv->subdev, 0); + return ret; +} + +static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tw9910_g_register, + .s_register = tw9910_s_register, +#endif + .s_power = tw9910_s_power, +}; + +static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_UYVY8_2X8; + return 0; +} + +static int tw9910_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); + + return 0; +} + +static int tw9910_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + u8 val = VSSL_VVALID | HSSL_DVALID; + unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); + + /* + * set OUTCTR1 + * + * We use VVALID and DVALID signals to control VSYNC and HSYNC + * outputs, in this mode their polarity is inverted. + */ + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + val |= HSP_HI; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + val |= VSP_HI; + + return i2c_smbus_write_byte_data(client, OUTCTR1, val); +} + +static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + *norm = V4L2_STD_NTSC | V4L2_STD_PAL; + return 0; +} + +static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { + .s_std = tw9910_s_std, + .g_std = tw9910_g_std, + .s_stream = tw9910_s_stream, + .g_mbus_config = tw9910_g_mbus_config, + .s_mbus_config = tw9910_s_mbus_config, + .g_tvnorms = tw9910_g_tvnorms, +}; + +static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { + .enum_mbus_code = tw9910_enum_mbus_code, + .get_selection = tw9910_get_selection, + .get_fmt = tw9910_get_fmt, + .set_fmt = tw9910_set_fmt, +}; + +static const struct v4l2_subdev_ops tw9910_subdev_ops = { + .core = &tw9910_subdev_core_ops, + .video = &tw9910_subdev_video_ops, + .pad = &tw9910_subdev_pad_ops, +}; + +/* + * i2c_driver function + */ + +static int tw9910_probe(struct i2c_client *client, + const struct i2c_device_id *did) + +{ + struct tw9910_priv *priv; + struct tw9910_video_info *info; + struct i2c_adapter *adapter = + to_i2c_adapter(client->dev.parent); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + int ret; + + if (!ssdd || !ssdd->drv_priv) { + dev_err(&client->dev, "TW9910: missing platform data!\n"); + return -EINVAL; + } + + info = ssdd->drv_priv; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); + return -EIO; + } + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = info; + + v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); + + priv->clk = v4l2_clk_get(&client->dev, "mclk"); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + ret = tw9910_video_probe(client); + if (ret < 0) + v4l2_clk_put(priv->clk); + + return ret; +} + +static int tw9910_remove(struct i2c_client *client) +{ + struct tw9910_priv *priv = to_tw9910(client); + v4l2_clk_put(priv->clk); + return 0; +} + +static const struct i2c_device_id tw9910_id[] = { + { "tw9910", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tw9910_id); + +static struct i2c_driver tw9910_i2c_driver = { + .driver = { + .name = "tw9910", + }, + .probe = tw9910_probe, + .remove = tw9910_remove, + .id_table = tw9910_id, +}; + +module_i2c_driver(tw9910_i2c_driver); + +MODULE_DESCRIPTION("SoC Camera driver for tw9910"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); -- cgit From 7b20f325a566df27737c795176a9ae519ecc486d Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 21 Feb 2018 12:48:03 -0500 Subject: media: i2c: tw9910: Remove soc_camera dependencies Remove soc_camera framework dependencies from tw9910 sensor driver. - Handle clock and gpios - Register async subdevice - Remove soc_camera specific g/s_mbus_config operations - Add kernel doc to driver interface header file - Adjust build system This commit does not remove the original soc_camera based driver as long as other platforms depends on soc_camera-based CEU driver. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 9 +++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tw9910.c | 162 ++++++++++++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 61 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 038b63d74c3c..6f20c7fb4a71 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -432,6 +432,15 @@ config VIDEO_TW9906 To compile this driver as a module, choose M here: the module will be called tw9906. +config VIDEO_TW9910 + tristate "Techwell TW9910 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. + + To compile this driver as a module, choose M here: the + module will be called tw9910. + config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 2d712c81cc28..cc30178e3347 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o obj-$(CONFIG_VIDEO_TW2804) += tw2804.o obj-$(CONFIG_VIDEO_TW9903) += tw9903.o obj-$(CONFIG_VIDEO_TW9906) += tw9906.o +obj-$(CONFIG_VIDEO_TW9910) += tw9910.o obj-$(CONFIG_VIDEO_CS3308) += cs3308.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index bdb5e0a431e9..96792df45fb0 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -1,6 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * tw9910 Video Driver * + * Copyright (C) 2017 Jacopo Mondi + * * Copyright (C) 2008 Renesas Solutions Corp. * Kuninori Morimoto * @@ -10,12 +13,10 @@ * Copyright 2006-7 Jonathan Corbet * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ +#include +#include #include #include #include @@ -25,9 +26,7 @@ #include #include -#include #include -#include #include #define GET_ID(val) ((val & 0xF8) >> 3) @@ -228,8 +227,10 @@ struct tw9910_scale_ctrl { struct tw9910_priv { struct v4l2_subdev subdev; - struct v4l2_clk *clk; + struct clk *clk; struct tw9910_video_info *info; + struct gpio_desc *pdn_gpio; + struct gpio_desc *rstb_gpio; const struct tw9910_scale_ctrl *scale; v4l2_std_id norm; u32 revision; @@ -582,13 +583,66 @@ static int tw9910_s_register(struct v4l2_subdev *sd, } #endif +static int tw9910_power_on(struct tw9910_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); + int ret; + + if (priv->clk) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + if (priv->pdn_gpio) { + gpiod_set_value(priv->pdn_gpio, 0); + usleep_range(500, 1000); + } + + /* + * FIXME: The reset signal is connected to a shared GPIO on some + * platforms (namely the SuperH Migo-R). Until a framework becomes + * available to handle this cleanly, request the GPIO temporarily + * to avoid conflicts. + */ + priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb", + GPIOD_OUT_LOW); + if (IS_ERR(priv->rstb_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + return PTR_ERR(priv->rstb_gpio); + } + + if (priv->rstb_gpio) { + gpiod_set_value(priv->rstb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(priv->rstb_gpio, 0); + usleep_range(500, 1000); + + gpiod_put(priv->rstb_gpio); + } + + return 0; +} + +static int tw9910_power_off(struct tw9910_priv *priv) +{ + clk_disable_unprepare(priv->clk); + + if (priv->pdn_gpio) { + gpiod_set_value(priv->pdn_gpio, 1); + usleep_range(500, 1000); + } + + return 0; +} + static int tw9910_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct tw9910_priv *priv = to_tw9910(client); - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + return on ? tw9910_power_on(priv) : + tw9910_power_off(priv); } static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) @@ -614,7 +668,7 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) * set bus width */ val = 0x00; - if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) + if (priv->info->buswidth == 16) val = LEN; ret = tw9910_mask_set(client, OPFORM, LEN, val); @@ -799,8 +853,7 @@ static int tw9910_video_probe(struct i2c_client *client) /* * tw9910 only use 8 or 16 bit bus width */ - if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && - SOCAM_DATAWIDTH_8 != priv->info->buswidth) { + if (priv->info->buswidth != 16 && priv->info->buswidth != 8) { dev_err(&client->dev, "bus width error\n"); return -ENODEV; } @@ -856,45 +909,6 @@ static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int tw9910_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int tw9910_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - u8 val = VSSL_VVALID | HSSL_DVALID; - unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); - - /* - * set OUTCTR1 - * - * We use VVALID and DVALID signals to control VSYNC and HSYNC - * outputs, in this mode their polarity is inverted. - */ - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - val |= HSP_HI; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - val |= VSP_HI; - - return i2c_smbus_write_byte_data(client, OUTCTR1, val); -} - static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) { *norm = V4L2_STD_NTSC | V4L2_STD_PAL; @@ -905,8 +919,6 @@ static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_std = tw9910_s_std, .g_std = tw9910_g_std, .s_stream = tw9910_s_stream, - .g_mbus_config = tw9910_g_mbus_config, - .s_mbus_config = tw9910_s_mbus_config, .g_tvnorms = tw9910_g_tvnorms, }; @@ -935,15 +947,14 @@ static int tw9910_probe(struct i2c_client *client, struct tw9910_video_info *info; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; - if (!ssdd || !ssdd->drv_priv) { + if (!client->dev.platform_data) { dev_err(&client->dev, "TW9910: missing platform data!\n"); return -EINVAL; } - info = ssdd->drv_priv; + info = client->dev.platform_data; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, @@ -959,13 +970,37 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) + priv->clk = clk_get(&client->dev, "xti"); + if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = NULL; + } else if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get xti clock\n"); return PTR_ERR(priv->clk); + } + + priv->pdn_gpio = gpiod_get_optional(&client->dev, "pdn", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->pdn_gpio)) { + dev_info(&client->dev, "Unable to get GPIO \"pdn\""); + ret = PTR_ERR(priv->pdn_gpio); + goto error_clk_put; + } ret = tw9910_video_probe(client); if (ret < 0) - v4l2_clk_put(priv->clk); + goto error_gpio_put; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto error_gpio_put; + + return ret; + +error_gpio_put: + if (priv->pdn_gpio) + gpiod_put(priv->pdn_gpio); +error_clk_put: + clk_put(priv->clk); return ret; } @@ -973,7 +1008,12 @@ static int tw9910_probe(struct i2c_client *client, static int tw9910_remove(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); - v4l2_clk_put(priv->clk); + + if (priv->pdn_gpio) + gpiod_put(priv->pdn_gpio); + clk_put(priv->clk); + v4l2_device_unregister_subdev(&priv->subdev); + return 0; } @@ -994,6 +1034,6 @@ static struct i2c_driver tw9910_i2c_driver = { module_i2c_driver(tw9910_i2c_driver); -MODULE_DESCRIPTION("SoC Camera driver for tw9910"); +MODULE_DESCRIPTION("V4L2 driver for TW9910 video decoder"); MODULE_AUTHOR("Kuninori Morimoto"); MODULE_LICENSE("GPL v2"); -- cgit From 054d8830ac07d865c2973971af29b7caad593914 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Feb 2018 09:23:32 -0500 Subject: media: ov772x: fix whitespace issues As we're adding this as a new driver, make checkpatch happier by solving some whitespace issues, using --fix-inplace. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 3edf0cb6fd0e..16665af0c712 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -375,7 +375,7 @@ */ #define OV7720 0x7720 #define OV7725 0x7721 -#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) +#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) /* * PLL multipliers @@ -500,7 +500,6 @@ static const struct ov772x_color_format ov772x_cfmts[] = { }, }; - /* * window size list */ @@ -557,6 +556,7 @@ static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask, u8 set) { s32 val = ov772x_read(client, command); + if (val < 0) return val; @@ -919,7 +919,6 @@ static int ov772x_set_params(struct ov772x_priv *priv, * Edge Ctrl */ if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { - /* * Manual Edge Control Mode * @@ -1064,7 +1063,7 @@ ov772x_set_fmt_error: } static int ov772x_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct ov772x_priv *priv = to_ov772x(sd); @@ -1087,7 +1086,7 @@ static int ov772x_get_selection(struct v4l2_subdev *sd, } static int ov772x_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; @@ -1106,7 +1105,7 @@ static int ov772x_get_fmt(struct v4l2_subdev *sd, } static int ov772x_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct ov772x_priv *priv = to_ov772x(sd); @@ -1219,7 +1218,7 @@ static int ov772x_enum_frame_interval(struct v4l2_subdev *sd, } static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) @@ -1282,11 +1281,11 @@ static int ov772x_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 3); v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); + V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); + V4L2_CID_HFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); priv->subdev.ctrl_handler = &priv->hdl; if (priv->hdl.error) return priv->hdl.error; -- cgit From 876e32e5dd6e08320288862440e3e8a9542b5d9b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Feb 2018 09:25:26 -0500 Subject: media: tw9910: solve coding style issues As we're adding this as a new driver, make checkpatch happier by solving several style issues, using --fix-inplace at strict mode. Some issues required manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 96792df45fb0..cc5d383fc6b8 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -339,6 +339,7 @@ static int tw9910_mask_set(struct i2c_client *client, u8 command, u8 mask, u8 set) { s32 val = i2c_smbus_read_byte_data(client, command); + if (val < 0) return val; @@ -389,7 +390,7 @@ static int tw9910_set_hsync(struct i2c_client *client) /* So far only revisions 0 and 1 have been seen */ /* bit 2 - 0 */ - if (1 == priv->revision) + if (priv->revision == 1) ret = tw9910_mask_set(client, HSLOWCTL, 0x77, (HSYNC_START & 0x0007) << 4 | (HSYNC_END & 0x0007)); @@ -511,10 +512,10 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); - const unsigned hact = 720; - const unsigned hdelay = 15; - unsigned vact; - unsigned vdelay; + const unsigned int hact = 720; + const unsigned int hdelay = 15; + unsigned int vact; + unsigned int vdelay; int ret; if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) @@ -532,16 +533,16 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) } if (!ret) ret = i2c_smbus_write_byte_data(client, CROP_HI, - ((vdelay >> 2) & 0xc0) | + ((vdelay >> 2) & 0xc0) | ((vact >> 4) & 0x30) | ((hdelay >> 6) & 0x0c) | ((hact >> 8) & 0x03)); if (!ret) ret = i2c_smbus_write_byte_data(client, VDELAY_LO, - vdelay & 0xff); + vdelay & 0xff); if (!ret) ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, - vact & 0xff); + vact & 0xff); return ret; } @@ -731,7 +732,7 @@ tw9910_set_fmt_error: } static int tw9910_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -756,7 +757,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd, } static int tw9910_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; @@ -807,7 +808,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, } static int tw9910_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; @@ -818,9 +819,9 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; - if (V4L2_FIELD_ANY == mf->field) { + if (mf->field == V4L2_FIELD_ANY) { mf->field = V4L2_FIELD_INTERLACED_BT; - } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { + } else if (mf->field != V4L2_FIELD_INTERLACED_BT) { dev_err(&client->dev, "Field type %d invalid.\n", mf->field); return -EINVAL; } @@ -870,8 +871,7 @@ static int tw9910_video_probe(struct i2c_client *client) priv->revision = GET_REV(id); id = GET_ID(id); - if (0x0B != id || - 0x01 < priv->revision) { + if (id != 0x0b || priv->revision > 0x01) { dev_err(&client->dev, "Product ID error %x:%x\n", id, priv->revision); @@ -899,7 +899,7 @@ static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { }; static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad || code->index) -- cgit From 3da7ee94f3fe9a58c9a7ddd6f5c892524068780c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 2 Feb 2018 08:00:32 -0500 Subject: media: vimc: fix control event handling The sensor subdev didn't handle control events. Add support for this. Found with v4l2-compliance. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-common.c | 4 +++- drivers/media/platform/vimc/vimc-sensor.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 9d63c84a9876..617415c224fe 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -434,7 +434,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, v4l2_set_subdevdata(sd, ved); /* Expose this subdev to user space */ - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; /* Initialize the media entity */ ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 457e211514c6..54184cd9e0ff 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -284,11 +285,18 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static struct v4l2_subdev_core_ops vimc_sen_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { .s_stream = vimc_sen_s_stream, }; static const struct v4l2_subdev_ops vimc_sen_ops = { + .core = &vimc_sen_core_ops, .pad = &vimc_sen_pad_ops, .video = &vimc_sen_video_ops, }; -- cgit From 1ceda32bf3f2f5542af805a70c6b59123e3c76c9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Feb 2018 12:06:30 -0500 Subject: media: vimc: use correct subdev functions Instead of calling everything a MEDIA_ENT_F_ATV_DECODER, pick the correct functions for these blocks. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-debayer.c | 2 +- drivers/media/platform/vimc/vimc-scaler.c | 2 +- drivers/media/platform/vimc/vimc-sensor.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 4d663e89d33f..6e10b63ba9ec 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -533,7 +533,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_deb_ops); diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index e1602e0bc230..e583ec7a91da 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -395,7 +395,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_sca_ops); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 54184cd9e0ff..605e2a2d5dd5 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -386,7 +386,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 1, + MEDIA_ENT_F_CAM_SENSOR, 1, (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, &vimc_sen_ops); if (ret) -- cgit From 3103c7b4ad08d813ec5c8187f7a9ddea55acf027 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 2 Feb 2018 08:05:23 -0500 Subject: media: v4l2-subdev: without controls return -ENOTTY If the subdev did not define any controls, then return -ENOTTY if userspace attempts to call these ioctls. The control framework functions will return -EINVAL, not -ENOTTY if vfh->ctrl_handler is NULL. Several of these framework functions are also called directly from drivers, so I don't want to change the error code there. Found with vimc and v4l2-compliance. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 74fe8083cf26..ec0bd6411aa7 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -187,27 +187,51 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_QUERYCTRL: + /* + * TODO: this really should be folded into v4l2_queryctrl (this + * currently returns -EINVAL for NULL control handlers). + * However, v4l2_queryctrl() is still called directly by + * drivers as well and until that has been addressed I believe + * it is safer to do the check here. The same is true for the + * other control ioctls below. + */ + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_queryctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERY_EXT_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERYMENU: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_querymenu(vfh->ctrl_handler, arg); case VIDIOC_G_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_g_ctrl(vfh->ctrl_handler, arg); case VIDIOC_S_CTRL: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: + if (!vfh->ctrl_handler) + return -ENOTTY; return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_DQEVENT: -- cgit From f437a7cb87b2814bba4f334fe97d0f02e7ed6079 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 3 Feb 2018 08:24:44 -0500 Subject: media: v4l2-subdev: implement VIDIOC_DBG_G_CHIP_INFO ioctl The VIDIOC_DBG_G/S_REGISTER ioctls imply that VIDIOC_DBG_G_CHIP_INFO is also present, since without that you cannot use v4l2-dbg. Just like the implementation in v4l2-ioctl.c this can be implemented in the core and no drivers need to be modified. It also makes it possible for v4l2-compliance to properly test the VIDIOC_DBG_G/S_REGISTER ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index ec0bd6411aa7..f9eed938d348 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -263,6 +263,19 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return -EPERM; return v4l2_subdev_call(sd, core, s_register, p); } + case VIDIOC_DBG_G_CHIP_INFO: + { + struct v4l2_dbg_chip_info *p = arg; + + if (p->match.type != V4L2_CHIP_MATCH_SUBDEV || p->match.addr) + return -EINVAL; + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; + } #endif case VIDIOC_LOG_STATUS: { -- cgit From fcab757396b29b72e76c66d0216c923094ff69fc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 3 Feb 2018 13:46:05 -0500 Subject: media: media-device.c: zero reserved fields MEDIA_IOC_SETUP_LINK didn't zero the reserved field of the media_link_desc struct. Do so in media_device_setup_link(). MEDIA_IOC_ENUM_LINKS didn't zero the reserved field of the media_links_enum struct. Do so in media_device_enum_links(). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index f44244415124..5d55743f970c 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -190,6 +190,7 @@ static long media_device_enum_links(struct media_device *mdev, ulink_desc++; } } + memset(links->reserved, 0, sizeof(links->reserved)); return 0; } @@ -218,6 +219,8 @@ static long media_device_setup_link(struct media_device *mdev, if (link == NULL) return -EINVAL; + memset(linkd->reserved, 0, sizeof(linkd->reserved)); + /* Setup the link on both entities. */ return __media_entity_setup_link(link, linkd->flags); } -- cgit From baa9e9101512499ecb8b524e586ca2b6fd6c73d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 3 Feb 2018 13:06:01 -0500 Subject: media: zero reservedX fields in media_v2_topology The MEDIA_IOC_G_TOPOLOGY implementation did not zero the reservedX fields. Fix this. Found with v4l2-compliance. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 5d55743f970c..35e81f7c0d2f 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -266,6 +266,7 @@ static long media_device_get_topology(struct media_device *mdev, uentity++; } topo->num_entities = i; + topo->reserved1 = 0; /* Get interfaces and number of interfaces */ i = 0; @@ -301,6 +302,7 @@ static long media_device_get_topology(struct media_device *mdev, uintf++; } topo->num_interfaces = i; + topo->reserved2 = 0; /* Get pads and number of pads */ i = 0; @@ -327,6 +329,7 @@ static long media_device_get_topology(struct media_device *mdev, upad++; } topo->num_pads = i; + topo->reserved3 = 0; /* Get links and number of links */ i = 0; @@ -358,6 +361,7 @@ static long media_device_get_topology(struct media_device *mdev, ulink++; } topo->num_links = i; + topo->reserved4 = 0; return ret; } -- cgit From ed3056f015de90a53127d05c34d49fe3e04675a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 5 Feb 2018 06:19:00 -0500 Subject: media: media.h: reorganize header to make it easier to understand The media.h public header is very messy. It mixes legacy and 'new' defines and it is not easy to figure out what should and what shouldn't be used. It also contains confusing comment that are either out of date or completely uninteresting for anyone that needs to use this header. The patch groups all entity functions together, including the 'old' defines based on the old range base. The reader just wants to know about the available functions and doesn't care about what range is used. All legacy defines are moved to the end of the header, so it is easier to locate them and just ignore them. The legacy structs in the struct media_entity_desc are put under also a much more effective signal to the reader that they shouldn't be used compared to the old method of relying on '#if 1' followed by a comment. The unused MEDIA_INTF_T_ALSA_* defines are also moved to the end of the header in the legacy area. They are also dropped from intf_type() in media-entity.c. All defines are also aligned at the same tab making the header easier to read. Signed-off-by: Hans Verkuil [mchehab@s-opensource.com: removed lots of spaces before tabs; typo changes ->change ] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index f7c6d64e6031..3498551e618e 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -64,22 +64,6 @@ static inline const char *intf_type(struct media_interface *intf) return "v4l-swradio"; case MEDIA_INTF_T_V4L_TOUCH: return "v4l-touch"; - case MEDIA_INTF_T_ALSA_PCM_CAPTURE: - return "alsa-pcm-capture"; - case MEDIA_INTF_T_ALSA_PCM_PLAYBACK: - return "alsa-pcm-playback"; - case MEDIA_INTF_T_ALSA_CONTROL: - return "alsa-control"; - case MEDIA_INTF_T_ALSA_COMPRESS: - return "alsa-compress"; - case MEDIA_INTF_T_ALSA_RAWMIDI: - return "alsa-rawmidi"; - case MEDIA_INTF_T_ALSA_HWDEP: - return "alsa-hwdep"; - case MEDIA_INTF_T_ALSA_SEQUENCER: - return "alsa-sequencer"; - case MEDIA_INTF_T_ALSA_TIMER: - return "alsa-timer"; default: return "unknown-intf"; } -- cgit From 5e3e4cb5e24b92773b194aa90066170b12133bc6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 3 Dec 2017 05:06:57 -0500 Subject: media: v4l: vsp1: Fix display stalls when requesting too many inputs Make sure we don't accept more inputs than the hardware can handle. This is a temporary fix to avoid display stall, we need to instead allocate the BRU or BRS to display pipelines dynamically based on the number of planes they each use. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 7ce69f23f50a..ac85942162c1 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -530,6 +530,15 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; + /* + * Make sure we don't accept more inputs than the hardware can + * handle. This is a temporary fix to avoid display stall, we + * need to instead allocate the BRU or BRS to display pipelines + * dynamically based on the number of planes they each use. + */ + if (pipe->num_inputs >= pipe->bru->source_pad) + pipe->inputs[i] = NULL; + if (!pipe->inputs[i]) continue; -- cgit From 613928e85317b945c863bb893f5737d2f22f5425 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 9 Feb 2018 09:50:34 -0500 Subject: media: v4l: vsp1: Fix header display list status check in continuous mode To allow dual pipelines utilising two WPF entities when available, the VSP was updated to support header-mode display list in continuous pipelines. A small bug in the status check of the command register causes the second pipeline to be directly afflicted by the running of the first; appearing as a perceived performance issue with stuttering display. Fix the vsp1_dl_list_hw_update_pending() call to ensure that the read comparison corresponds to the correct pipeline. Fixes: eaf4bfad6ad8 ("v4l: vsp1: Add support for header display lists in continuous mode") Cc: "Stable v4.14+" Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_dl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 4257451f1bd8..0b86ed01e85d 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -509,7 +509,8 @@ static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm) return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); else - return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR)); + return !!(vsp1_read(vsp1, VI6_CMD(dlm->index)) + & VI6_CMD_UPDHDR); } static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl) -- cgit From 5b78f0361caec7e2b809af35facd767da1b9030d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 2 Dec 2017 14:39:51 -0500 Subject: media: v4l: vsp1: Print the correct blending unit name in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DRM pipelines can use either the BRU or the BRS for blending. Make sure the right name is used in debugging messages to avoid confusion. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Kieran Bingham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index ac85942162c1..b8fee1834253 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -27,6 +27,7 @@ #include "vsp1_pipe.h" #include "vsp1_rwpf.h" +#define BRU_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS" /* ----------------------------------------------------------------------------- * Interrupt Handling @@ -88,7 +89,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, struct vsp1_entity *next; struct vsp1_dl_list *dl; struct v4l2_subdev_format format; - const char *bru_name; unsigned long flags; unsigned int i; int ret; @@ -99,7 +99,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, drm_pipe = &vsp1->drm->pipe[pipe_index]; pipe = &drm_pipe->pipe; bru = to_bru(&pipe->bru->subdev); - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; if (!cfg) { /* @@ -165,7 +164,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); } format.pad = pipe->bru->source_pad; @@ -181,7 +180,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); format.pad = RWPF_PAD_SINK; ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL, @@ -473,9 +472,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, format.pad); + format.format.code, BRU_NAME(pipe->bru), format.pad); sel.pad = bru_input; sel.target = V4L2_SEL_TGT_COMPOSE; @@ -486,10 +485,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, - "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n", __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, - sel.pad); + BRU_NAME(pipe->bru), sel.pad); return 0; } @@ -514,12 +512,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_entity *entity; struct vsp1_entity *next; struct vsp1_dl_list *dl; - const char *bru_name; unsigned int i; int ret; - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; - /* Prepare the display list. */ dl = vsp1_dl_list_get(pipe->output->dlm); @@ -570,7 +565,7 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) rpf->entity.sink_pad = i; dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n", - __func__, rpf->entity.index, bru_name, i); + __func__, rpf->entity.index, BRU_NAME(pipe->bru), i); ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i); if (ret < 0) -- cgit From 06227008670afddd5eb66cc6a85c27fd5e72f41e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Feb 2018 15:09:58 -0500 Subject: media: v4l: vsp1: Fix mask creation for MULT_ALPHA_RATIO Due to a typo, the mask was destroyed by a comparison instead of a bit shift. No regression since the mask has not been used yet. Signed-off-by: Wolfram Sang Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 26c4ffad2f46..b1912c83a1da 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -225,7 +225,7 @@ #define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_BOTH (3 << 8) -#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff < 0) +#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0) #define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0 /* ----------------------------------------------------------------------------- -- cgit From 7f43ff953f4009655a8b19a6f2fd1f665f4d7c2e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 18 Jan 2018 09:05:51 -0500 Subject: media: v4l: vsp1: Fix video output on R8A77970 Commit d455b45f8393 ("v4l: vsp1: Add support for new VSP2-BS, VSP2-DL, and VSP2-D instances") added support for the VSP2-D found in the R-Car V3M (R8A77970) but the video output that VSP2-D sends to DU has a greenish garbage-like line repeated every 8 screen rows. It turns out that R-Car V3M has the LIF0 buffer attribute register that you need to set to a non- default value in order to get rid of the output artifacts. Based on the original (and large) patch by Daisuke Matsushita . Fixes: d455b45f8393 ("v4l: vsp1: Add support for new VSP2-BS, VSP2-DL and VSP2-D instances") [Removed braces, added VI6_IP_VERSION_MASK to improve readabiliy] Signed-off-by: Sergei Shtylyov Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_lif.c | 12 ++++++++++++ drivers/media/platform/vsp1/vsp1_regs.h | 6 ++++++ 2 files changed, 18 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e6fa16d7fda8..704920753998 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -155,6 +155,18 @@ static void lif_configure(struct vsp1_entity *entity, (obth << VI6_LIF_CTRL_OBTH_SHIFT) | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); + + /* + * On R-Car V3M the LIF0 buffer attribute register has to be set to a + * non-default value to guarantee proper operation (otherwise artifacts + * may appear on the output). The value required by the manual is not + * explained but is likely a buffer size or threshold. + */ + if ((entity->vsp1->version & VI6_IP_VERSION_MASK) == + (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M)) + vsp1_lif_write(lif, dl, VI6_LIF_LBA, + VI6_LIF_LBA_LBA0 | + (1536 << VI6_LIF_LBA_LBA1_SHIFT)); } static const struct vsp1_entity_operations lif_entity_ops = { diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index b1912c83a1da..dae0c1901297 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -693,6 +693,11 @@ #define VI6_LIF_CSBTH_LBTH_MASK (0x7ff << 0) #define VI6_LIF_CSBTH_LBTH_SHIFT 0 +#define VI6_LIF_LBA 0x3b0c +#define VI6_LIF_LBA_LBA0 (1 << 31) +#define VI6_LIF_LBA_LBA1_MASK (0xfff << 16) +#define VI6_LIF_LBA_LBA1_SHIFT 16 + /* ----------------------------------------------------------------------------- * Security Control Registers */ @@ -705,6 +710,7 @@ */ #define VI6_IP_VERSION 0x3f00 +#define VI6_IP_VERSION_MASK (0xffff << 0) #define VI6_IP_VERSION_MODEL_MASK (0xff << 8) #define VI6_IP_VERSION_MODEL_VSPS_H2 (0x09 << 8) #define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8) -- cgit From 2a18115d43b209cf8f6b9a4deb735c4786478625 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 7 Feb 2018 12:35:34 -0500 Subject: media: stm32-dcmi: remove redundant capture enable Remove redundant capture enable already done in dcmi_start_capture(). Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 3319d9cb1b12..0993b55b8bd3 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -255,9 +255,6 @@ static void dcmi_dma_callback(void *param) spin_unlock(&dcmi->irqlock); return; } - - /* Enable capture */ - reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE); } break; -- cgit From ffb1bdc225d125e41f548fa268ca1a687ec4cecc Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 7 Feb 2018 12:35:35 -0500 Subject: media: stm32-dcmi: remove redundant clear of interrupt flags It is already cleared in dcmi_irq_callback(). Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 0993b55b8bd3..7deab02e23f6 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -385,8 +385,6 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) dcmi->errors_count++; dmaengine_terminate_all(dcmi->dma_chan); - reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n"); if (dcmi_start_capture(dcmi)) { -- cgit From 2c737e9c29b1fb7e585470c8247b9ec8ba5285c4 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 7 Feb 2018 12:35:36 -0500 Subject: media: stm32-dcmi: improve error trace points Fix some missing "\n". Trace error returned by subdev streamon/streamoff. Remove extra "0x" unneeded with %pad formatter. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 7deab02e23f6..6baea432e382 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -234,7 +234,7 @@ static void dcmi_dma_callback(void *param) /* Restart a new DMA transfer with next buffer */ if (dcmi->state == RUNNING) { if (list_empty(&dcmi->buffers)) { - dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer", + dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n", __func__); dcmi->errors_count++; dcmi->active = NULL; @@ -249,7 +249,7 @@ static void dcmi_dma_callback(void *param) list_del_init(&dcmi->active->list); if (dcmi_start_capture(dcmi)) { - dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete", + dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", __func__); spin_unlock(&dcmi->irqlock); @@ -478,7 +478,7 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); - dev_dbg(dcmi->dev, "buffer[%d] phy=0x%pad size=%zu\n", + dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", vb->index, &buf->paddr, buf->size); } @@ -524,7 +524,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) ret = clk_enable(dcmi->mclk); if (ret) { - dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock", + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n", __func__); goto err_release_buffers; } @@ -600,7 +600,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) ret = dcmi_start_capture(dcmi); if (ret) { - dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture", + dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", __func__); spin_unlock_irq(&dcmi->irqlock); @@ -651,7 +651,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Disable stream on the sub device */ ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); if (ret && ret != -ENOIOCTLCMD) - dev_err(dcmi->dev, "stream off failed in subdev\n"); + dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", + __func__, ret); dcmi->state = STOPPING; @@ -667,7 +668,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE); if (!timeout) { - dev_err(dcmi->dev, "Timeout during stop streaming\n"); + dev_err(dcmi->dev, "%s: Timeout during stop streaming\n", + __func__); dcmi->state = STOPPED; } -- cgit From e0019f71011dff4228175d1e30c1ba7fd6da41de Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 7 Feb 2018 16:11:35 -0500 Subject: media: i2c: adv748x: Fix cleanup jump on chip identification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error handling for the adv748x_identify_chip() call erroneously jumps to the err_cleanup_clients label before the clients have been established. Correct this by jumping to the next (and correct) label in the cleanup code: err_cleanup_dt. Fixes: 3e89586a64df ("media: i2c: adv748x: add adv748x driver") Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index fd92c9e4b519..accaa70134fb 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -715,7 +715,7 @@ static int adv748x_probe(struct i2c_client *client, ret = adv748x_identify_chip(state); if (ret) { adv_err(state, "Failed to identify chip"); - goto err_cleanup_clients; + goto err_cleanup_dt; } /* Configure remaining pages as I2C clients with regmap access */ -- cgit From aebd90aa3244e3539001919dcfbf00027d5ab63c Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 8 Feb 2018 06:00:45 -0500 Subject: media: stm32-dcmi: add g/s_parm framerate support Add g/s_parm framerate support by calling subdev g/s_frame_interval ops. This allows user to control sensor framerate by calling ioctl G/S_PARM. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 6baea432e382..cc104a0805e2 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1164,6 +1164,22 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, return 0; } +static int dcmi_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + +static int dcmi_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + static int dcmi_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { @@ -1266,6 +1282,9 @@ static const struct v4l2_ioctl_ops dcmi_ioctl_ops = { .vidioc_g_input = dcmi_g_input, .vidioc_s_input = dcmi_s_input, + .vidioc_g_parm = dcmi_g_parm, + .vidioc_s_parm = dcmi_s_parm, + .vidioc_enum_framesizes = dcmi_enum_framesizes, .vidioc_enum_frameintervals = dcmi_enum_frameintervals, -- cgit From 15001033f4149162359de0ca2d74b39933358fc3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 23 Feb 2018 08:13:26 -0500 Subject: media: i2c: TDA1997x: add CONFIG_SND dependency Without CONFIG_SND, we get a link error: ERROR: "snd_soc_register_codec" [drivers/media/i2c/tda1997x.ko] undefined! ERROR: "snd_soc_unregister_codec" [drivers/media/i2c/tda1997x.ko] undefined! ERROR: "snd_pcm_hw_constraint_minmax" [drivers/media/i2c/tda1997x.ko] undefined! This adds the same Kconfig dependency that we have in other media drivers, using 'select SND_PCM' to ensure that we have can call snd_pcm_hw_constraint_minmax, while depending on CONFIG_SND_SOC for registering the codec. Fixes: 9ac0038db9a7 ("media: i2c: Add TDA1997x HDMI receiver driver") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6f20c7fb4a71..d7bba0e3f30e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -59,6 +59,8 @@ config VIDEO_TDA9840 config VIDEO_TDA1997X tristate "NXP TDA1997x HDMI receiver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on SND_SOC + select SND_PCM ---help--- V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. -- cgit From 94d4a1a671ec4887e8052badb34fb06312ce3158 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 26 Feb 2018 09:18:03 -0500 Subject: media: ov5695: mark PM functions as __maybe_unused Without CONFIG_PM, we get a harmless build warning: drivers/media/i2c/ov5695.c:1033:12: error: 'ov5695_runtime_suspend' defined but not used [-Werror=unused-function] static int ov5695_runtime_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~ drivers/media/i2c/ov5695.c:1024:12: error: 'ov5695_runtime_resume' defined but not used [-Werror=unused-function] static int ov5695_runtime_resume(struct device *dev) This marks the affected functions as __maybe_unused. Fixes: 8a77009be4be ("media: ov5695: add support for OV5695 sensor") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5695.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 2db7d2e535b9..a4985a4715f5 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1021,7 +1021,7 @@ static void __ov5695_power_off(struct ov5695 *ov5695) regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies); } -static int ov5695_runtime_resume(struct device *dev) +static int __maybe_unused ov5695_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1030,7 +1030,7 @@ static int ov5695_runtime_resume(struct device *dev) return __ov5695_power_on(ov5695); } -static int ov5695_runtime_suspend(struct device *dev) +static int __maybe_unused ov5695_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); -- cgit From 15ea2df9143729a2b722d4ca2b52cfa14a819d8e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 26 Feb 2018 09:18:04 -0500 Subject: media: ov2685: mark PM functions as __maybe_unused Without CONFIG_PM, we get a harmless build warning: drivers/media/i2c/ov2685.c:516:12: error: 'ov2685_runtime_suspend' defined but not used [-Werror=unused-function] static int ov2685_runtime_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~ drivers/media/i2c/ov2685.c:507:12: error: 'ov2685_runtime_resume' defined but not used [-Werror=unused-function] static int ov2685_runtime_resume(struct device *dev) This marks the affected functions as __maybe_unused. Fixes: e3861d9118c8 ("media: ov2685: add support for OV2685 sensor") Signed-off-by: Arnd Bergmann [hans.verkuil@cisco.com: fixed typo in Subject: was ov5695] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2685.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 904ac305d499..9ac702e3ae95 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -504,7 +504,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) } #endif -static int ov2685_runtime_resume(struct device *dev) +static int __maybe_unused ov2685_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -513,7 +513,7 @@ static int ov2685_runtime_resume(struct device *dev) return __ov2685_power_on(ov2685); } -static int ov2685_runtime_suspend(struct device *dev) +static int __maybe_unused ov2685_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); -- cgit From 5817b3d15e67f8a7280e06e0dfb2c7ede5897cd3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 13 Feb 2018 06:11:35 -0500 Subject: media: rc: no need to announce major number Since commit a60d64b15c20 ("media: lirc: lirc interface should not be a raw decoder"), the message in the documentation is incorrect as the module name is rc_core, not lirc_dev. Since the message is not useful, just make the message debug and remove it from the documentation. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index da3b5c095a59..24e9fbb80e81 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -804,8 +804,8 @@ int __init lirc_dev_init(void) return retval; } - pr_info("IR Remote Control driver registered, major %d\n", - MAJOR(lirc_base_dev)); + pr_debug("IR Remote Control driver registered, major %d\n", + MAJOR(lirc_base_dev)); return 0; } -- cgit From e3e389f931a14ddf43089c7db92fc5d74edf93a4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 14 Feb 2018 10:26:17 -0500 Subject: media: rc: fix race condition in ir_raw_event_store_edge() handling There is a possible race condition between the IR timeout being generated from the timer, and new IR arriving. This could result in the timeout being added to the kfifo after new IR arrives. On top of that, there is concurrent write access to the kfifo from ir_raw_event_store_edge() and the timer. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-core-priv.h | 5 +++-- drivers/media/rc/rc-ir-raw.c | 24 +++++++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index d09a06e1c17f..5e80b4273e2d 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -50,8 +50,9 @@ struct ir_raw_event_ctrl { DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); ktime_t last_event; /* when last event occurred */ struct rc_dev *dev; /* pointer to the parent rc_dev */ - /* edge driver */ - struct timer_list edge_handle; + /* handle delayed ir_raw_event_store_edge processing */ + spinlock_t edge_spinlock; + struct timer_list edge_handle; /* raw decoder state follows */ struct ir_raw_event prev_ev; diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 2790a0d268fd..984bb82851f9 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -101,6 +101,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); ev.pulse = !pulse; + spin_lock(&dev->raw->edge_spinlock); rc = ir_raw_event_store(dev, &ev); dev->raw->last_event = now; @@ -112,6 +113,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) mod_timer(&dev->raw->edge_handle, jiffies + msecs_to_jiffies(15)); } + spin_unlock(&dev->raw->edge_spinlock); return rc; } @@ -462,12 +464,26 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, } EXPORT_SYMBOL(ir_raw_encode_scancode); -static void edge_handle(struct timer_list *t) +/** + * ir_raw_edge_handle() - Handle ir_raw_event_store_edge() processing + * + * @t: timer_list + * + * This callback is armed by ir_raw_event_store_edge(). It does two things: + * first of all, rather than calling ir_raw_event_handle() for each + * edge and waking up the rc thread, 15 ms after the first edge + * ir_raw_event_handle() is called. Secondly, generate a timeout event + * no more IR is received after the rc_dev timeout. + */ +static void ir_raw_edge_handle(struct timer_list *t) { struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle); struct rc_dev *dev = raw->dev; - ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event); + unsigned long flags; + ktime_t interval; + spin_lock_irqsave(&dev->raw->edge_spinlock, flags); + interval = ktime_sub(ktime_get(), dev->raw->last_event); if (ktime_to_ns(interval) >= dev->timeout) { DEFINE_IR_RAW_EVENT(ev); @@ -480,6 +496,7 @@ static void edge_handle(struct timer_list *t) jiffies + nsecs_to_jiffies(dev->timeout - ktime_to_ns(interval))); } + spin_unlock_irqrestore(&dev->raw->edge_spinlock, flags); ir_raw_event_handle(dev); } @@ -528,7 +545,8 @@ int ir_raw_event_prepare(struct rc_dev *dev) dev->raw->dev = dev; dev->change_protocol = change_protocol; - timer_setup(&dev->raw->edge_handle, edge_handle, 0); + spin_lock_init(&dev->raw->edge_spinlock); + timer_setup(&dev->raw->edge_handle, ir_raw_edge_handle, 0); INIT_KFIFO(dev->raw->kfifo); return 0; -- cgit From 62474660fb2d92bb3f419769912517cccac2cf96 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Wed, 20 Dec 2017 11:29:48 -0500 Subject: media: dvb-frontend/mxl5xx: add support for physical layer scrambling The MaxLinear MxL5xx has support for physical layer scrambling, which was recently added to the DVB core via the new scrambling_sequence_index property. Add required bits to the mxl5xx driver. Picked up from dddvb master, commit 5c032058b9ba ("add support for PLS") by Ralph Metzler , adapted to the different naming of the pls property (pls vs. scrambling_sequence_index). Cc: Ralph Metzler Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mxl5xx.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c index e899821018a0..483ee7d6198e 100644 --- a/drivers/media/dvb-frontends/mxl5xx.c +++ b/drivers/media/dvb-frontends/mxl5xx.c @@ -380,6 +380,38 @@ static int get_algo(struct dvb_frontend *fe) return DVBFE_ALGO_HW; } +static u32 gold2root(u32 gold) +{ + u32 x, g, tmp = gold; + + if (tmp >= 0x3ffff) + tmp = 0; + for (g = 0, x = 1; g < tmp; g++) + x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1); + return x; +} + +static int cfg_scrambler(struct mxl *state, u32 gold) +{ + u32 root; + u8 buf[26] = { + MXL_HYDRA_PLID_CMD_WRITE, 24, + 0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0, + state->demod, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + }; + + root = gold2root(gold); + + buf[25] = (root >> 24) & 0xff; + buf[24] = (root >> 16) & 0xff; + buf[23] = (root >> 8) & 0xff; + buf[22] = root & 0xff; + + return send_command(state, sizeof(buf), buf); +} + static int cfg_demod_abort_tune(struct mxl *state) { struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd; @@ -437,7 +469,7 @@ static int set_parameters(struct dvb_frontend *fe) demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO; demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO; - /* cfg_scrambler(state); */ + cfg_scrambler(state, p->scrambling_sequence_index); break; default: return -EINVAL; -- cgit From 7aa92c4229fefff0cab6930cf977f4a0e3e606d8 Mon Sep 17 00:00:00 2001 From: Dan Gopstein Date: Mon, 25 Dec 2017 16:16:14 -0500 Subject: media: ABS macro parameter parenthesization Replace usages of the locally defined ABS() macro with calls to the canonical abs() from kernel.h and remove the old definitions of ABS() This change was originally motivated by two local definitions of the ABS (absolute value) macro that fail to parenthesize their parameter properly. This can lead to a bad expansion for low-precedence expression arguments. For example: ABS(1-2) currently expands to ((1-2) < 0 ? (-1-2) : (1-2)) which evaluates to -3. But the correct expansion would be ((1-2) < 0 ? -(1-2) : (1-2)) which evaluates to 1. Signed-off-by: Dan Gopstein Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib0090.c | 4 ++-- drivers/media/dvb-frontends/dib7000p.c | 2 +- drivers/media/dvb-frontends/dib8000.c | 2 +- drivers/media/dvb-frontends/dibx000_common.h | 2 -- drivers/media/dvb-frontends/mb86a16.c | 8 +++----- drivers/media/dvb-frontends/stv0367_priv.h | 1 - drivers/media/dvb-frontends/stv0900_priv.h | 1 - drivers/media/dvb-frontends/stv0900_sw.c | 6 +++--- 8 files changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 64f49c8eb1fb..ee7af34979ed 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -1285,7 +1285,7 @@ int dib0090_gain_control(struct dvb_frontend *fe) #endif if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ - if (ABS(adc_error) < 50 || state->agc_step++ > 5) { + if (abs(adc_error) < 50 || state->agc_step++ > 5) { #ifdef CONFIG_STANDARD_DAB if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { @@ -1754,7 +1754,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front *tune_state = CT_TUNER_STEP_1; } else { /* the minimum was what we have seen in the step before */ - if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { + if (abs(state->adc_diff) > abs(state->min_adc_diff)) { dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff); state->step--; } diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 90ace707a80d..902af482448e 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -809,7 +809,7 @@ static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) { u32 internal = dib7000p_get_internal_freq(state); s32 unit_khz_dds_val; - u32 abs_offset_khz = ABS(offset_khz); + u32 abs_offset_khz = abs(offset_khz); u32 dds = state->cfg.bw->ifreq & 0x1ffffff; u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); if (internal == 0) { diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index e64014f338fb..6f35173d2968 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2677,7 +2677,7 @@ static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) { s16 unit_khz_dds_val; - u32 abs_offset_khz = ABS(offset_khz); + u32 abs_offset_khz = abs(offset_khz); u32 dds = state->cfg.pll->ifreq & 0x1ffffff; u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); u8 ratio; diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h index 8784af962eba..12b58f5c677d 100644 --- a/drivers/media/dvb-frontends/dibx000_common.h +++ b/drivers/media/dvb-frontends/dibx000_common.h @@ -223,8 +223,6 @@ struct dvb_frontend_parametersContext { #define FE_CALLBACK_TIME_NEVER 0xffffffff -#define ABS(x) ((x < 0) ? (-x) : (x)) - #define DATA_BUS_ACCESS_MODE_8BIT 0x01 #define DATA_BUS_ACCESS_MODE_16BIT 0x02 #define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10 diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 2969ba6ed9e1..377cd984b069 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -31,8 +31,6 @@ static unsigned int verbose = 5; module_param(verbose, int, 0644); -#define ABS(x) ((x) < 0 ? (-x) : (x)) - struct mb86a16_state { struct i2c_adapter *i2c_adap; const struct mb86a16_config *config; @@ -1202,12 +1200,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state) signal_dupl = 0; for (j = 0; j < prev_freq_num; j++) { - if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { + if ((abs(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { signal_dupl = 1; dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j); } } - if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { + if ((signal_dupl == 0) && (swp_freq > 0) && (abs(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate); prev_swp_freq[prev_freq_num] = swp_freq; prev_freq_num++; @@ -1381,7 +1379,7 @@ static int mb86a16_set_fe(struct mb86a16_state *state) dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq); swp_freq += delta_freq; dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq); - if (ABS(state->frequency * 1000 - swp_freq) > 3800) { + if (abs(state->frequency * 1000 - swp_freq) > 3800) { dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !"); } else { diff --git a/drivers/media/dvb-frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h index 8abc451dd524..460066a391b7 100644 --- a/drivers/media/dvb-frontends/stv0367_priv.h +++ b/drivers/media/dvb-frontends/stv0367_priv.h @@ -35,7 +35,6 @@ #endif /* MACRO definitions */ -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) #define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) #define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) #define INRANGE(X, Y, Z) \ diff --git a/drivers/media/dvb-frontends/stv0900_priv.h b/drivers/media/dvb-frontends/stv0900_priv.h index d1fc06ff27d3..09a46477eae4 100644 --- a/drivers/media/dvb-frontends/stv0900_priv.h +++ b/drivers/media/dvb-frontends/stv0900_priv.h @@ -24,7 +24,6 @@ #include -#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) #define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \ || (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index c97a39120ea5..d406c83e4744 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1255,14 +1255,14 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe) else intp->freq[d] = stv0900_get_tuner_freq(fe); - if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) range = STV0900_RANGEOK; - else if (ABS(offsetFreq) <= + else if (abs(offsetFreq) <= (stv0900_carrier_width(result->symbol_rate, result->rolloff) / 2000)) range = STV0900_RANGEOK; - } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) + } else if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500)) range = STV0900_RANGEOK; dprintk("%s: range %d\n", __func__, range); -- cgit From be7fd3c3a8c5e9acbc69f887ca961df5e68cf6f0 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:11 -0500 Subject: media: em28xx: Hauppauge DualHD second tuner functionality Implement use of secondary TS port on em28xx. Adds has_dual_ts field, allows secondary demod/tuner to be added to a single em28xx device. Hauppauge DualHD models are configured to use this feature. [mchehab@s-opensource.com: em28xx_duplicate_dev() should be static] Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 126 +++++++++++++++++++++++++++++++- drivers/media/usb/em28xx/em28xx-core.c | 42 +++++++++-- drivers/media/usb/em28xx/em28xx-dvb.c | 33 +++++++-- drivers/media/usb/em28xx/em28xx.h | 12 +++ 4 files changed, 196 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 34e16f6ab4ac..7f5d0b28cb8c 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2402,6 +2402,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = hauppauge_dualhd_dvb, .has_dvb = 1, + .has_dual_ts = 1, .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, @@ -2417,6 +2418,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = hauppauge_dualhd_dvb, .has_dvb = 1, + .has_dual_ts = 1, .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, @@ -3239,7 +3241,8 @@ static void em28xx_release_resources(struct em28xx *dev) em28xx_i2c_unregister(dev, 1); em28xx_i2c_unregister(dev, 0); - usb_put_dev(udev); + if (dev->ts == PRIMARY_TS) + usb_put_dev(udev); /* Mark device as unused */ clear_bit(dev->devno, em28xx_devused); @@ -3432,6 +3435,35 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, return 0; } +int em28xx_duplicate_dev(struct em28xx *dev) +{ + int nr; + struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); + + if (sec_dev == NULL) { + dev->dev_next = NULL; + return -ENOMEM; + } + memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev))); + /* Check to see next free device and mark as used */ + do { + nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); + if (nr >= EM28XX_MAXBOARDS) { + /* No free device slots */ + dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + kfree(sec_dev); + dev->dev_next = NULL; + return -ENOMEM; + } + } while (test_and_set_bit(nr, em28xx_devused)); + sec_dev->devno = nr; + snprintf(sec_dev->name, 28, "em28xx #%d", nr); + sec_dev->dev_next = NULL; + dev->dev_next = sec_dev; + return 0; +} + /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) @@ -3551,6 +3583,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } break; + case 0x85: + if (usb_endpoint_xfer_isoc(e)) { + if (size > dev->dvb_max_pkt_size_isoc_ts2) { + dev->dvb_ep_isoc_ts2 = e->bEndpointAddress; + dev->dvb_max_pkt_size_isoc_ts2 = size; + dev->dvb_alt_isoc = i; + } + } else { + dev->dvb_ep_bulk_ts2 = e->bEndpointAddress; + } + break; } } /* NOTE: @@ -3565,6 +3608,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, * 0x83 isoc* => audio * 0x84 isoc => digital * 0x84 bulk => analog or digital** + * 0x85 isoc => digital TS2 + * 0x85 bulk => digital TS2 * (*: audio should always be isoc) * (**: analog, if ep 0x82 is isoc, otherwise digital) * @@ -3632,6 +3677,10 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->has_video = has_video; dev->ifnum = ifnum; + dev->ts = PRIMARY_TS; + snprintf(dev->name, 28, "em28xx"); + dev->dev_next = NULL; + if (has_vendor_audio) { dev_err(&interface->dev, "Audio interface %i found (Vendor Class)\n", ifnum); @@ -3711,6 +3760,65 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->dvb_xfer_bulk ? "bulk" : "isoc"); } + if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) { + dev->dev_next->ts = SECONDARY_TS; + dev->dev_next->alt = -1; + dev->dev_next->is_audio_only = has_vendor_audio && + !(has_video || has_dvb); + dev->dev_next->has_video = false; + dev->dev_next->ifnum = ifnum; + dev->dev_next->model = id->driver_info; + + mutex_init(&dev->dev_next->lock); + retval = em28xx_init_dev(dev->dev_next, udev, interface, + dev->dev_next->devno); + if (retval) + goto err_free; + + dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */ + dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */ + + if (usb_xfer_mode < 0) { + if (dev->dev_next->board.is_webcam) + try_bulk = 1; + else + try_bulk = 0; + } else { + try_bulk = usb_xfer_mode > 0; + } + + /* Select USB transfer types to use */ + if (has_dvb) { + if (!dev->dvb_ep_isoc_ts2 || + (try_bulk && dev->dvb_ep_bulk_ts2)) + dev->dev_next->dvb_xfer_bulk = 1; + dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n", + dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc"); + } + + dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2; + dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2; + dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2; + dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc; + + /* Configuare hardware to support TS2*/ + if (dev->dvb_xfer_bulk) { + /* The ep4 and ep5 are configuared for BULK */ + em28xx_write_reg(dev, 0x0b, 0x96); + mdelay(100); + em28xx_write_reg(dev, 0x0b, 0x80); + mdelay(100); + } else { + /* The ep4 and ep5 are configuared for ISO */ + em28xx_write_reg(dev, 0x0b, 0x96); + mdelay(100); + em28xx_write_reg(dev, 0x0b, 0x82); + mdelay(100); + } + + kref_init(&dev->dev_next->ref); + } + kref_init(&dev->ref); request_modules(dev); @@ -3753,15 +3861,29 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (!dev) return; + if (dev->dev_next != NULL) { + dev->dev_next->disconnected = 1; + dev_info(&dev->intf->dev, "Disconnecting %s\n", + dev->dev_next->name); + flush_request_modules(dev->dev_next); + } + dev->disconnected = 1; - dev_err(&dev->intf->dev, "Disconnecting\n"); + dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name); flush_request_modules(dev); em28xx_close_extension(dev); + if (dev->dev_next != NULL) + em28xx_release_resources(dev->dev_next); em28xx_release_resources(dev); + + if (dev->dev_next != NULL) { + kref_put(&dev->dev_next->ref, em28xx_free_device); + dev->dev_next = NULL; + } kref_put(&dev->ref, em28xx_free_device); } diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 1d0d8cc06103..ef38e567c4bb 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -638,10 +638,18 @@ int em28xx_capture_start(struct em28xx *dev, int start) dev->chip_id == CHIP_ID_EM28174 || dev->chip_id == CHIP_ID_EM28178) { /* The Transport Stream Enable Register moved in em2874 */ - rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - start ? - EM2874_TS1_CAPTURE_ENABLE : 0x00, - EM2874_TS1_CAPTURE_ENABLE); + if (dev->ts == PRIMARY_TS) + rc = em28xx_write_reg_bits(dev, + EM2874_R5F_TS_ENABLE, + start ? + EM2874_TS1_CAPTURE_ENABLE : 0x00, + EM2874_TS1_CAPTURE_ENABLE); + else + rc = em28xx_write_reg_bits(dev, + EM2874_R5F_TS_ENABLE, + start ? + EM2874_TS2_CAPTURE_ENABLE : 0x00, + EM2874_TS2_CAPTURE_ENABLE); } else { /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ @@ -1077,7 +1085,11 @@ int em28xx_register_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->init(dev); + if (ops->init) { + ops->init(dev); + if (dev->dev_next != NULL) + ops->init(dev->dev_next); + } } mutex_unlock(&em28xx_devlist_mutex); pr_info("em28xx: Registered (%s) extension\n", ops->name); @@ -1091,7 +1103,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { - ops->fini(dev); + if (ops->fini) { + if (dev->dev_next != NULL) + ops->fini(dev->dev_next); + ops->fini(dev); + } } list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); @@ -1106,8 +1122,11 @@ void em28xx_init_extension(struct em28xx *dev) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&dev->devlist, &em28xx_devlist); list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->init) + if (ops->init) { ops->init(dev); + if (dev->dev_next != NULL) + ops->init(dev->dev_next); + } } mutex_unlock(&em28xx_devlist_mutex); } @@ -1118,8 +1137,11 @@ void em28xx_close_extension(struct em28xx *dev) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->fini) + if (ops->fini) { + if (dev->dev_next != NULL) + ops->fini(dev->dev_next); ops->fini(dev); + } } list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); @@ -1134,6 +1156,8 @@ int em28xx_suspend_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) ops->suspend(dev); + if (dev->dev_next != NULL) + ops->suspend(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); return 0; @@ -1148,6 +1172,8 @@ int em28xx_resume_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) ops->resume(dev); + if (dev->dev_next != NULL) + ops->resume(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 8a81c94a8a27..9bc957690b45 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -199,7 +199,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) int rc; struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv; struct em28xx *dev = i2c_bus->dev; - struct usb_device *udev = interface_to_usbdev(dev->intf); int dvb_max_packet_size, packet_multiplier, dvb_alt; if (dev->dvb_xfer_bulk) { @@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) dvb_alt = dev->dvb_alt_isoc; } - usb_set_interface(udev, dev->ifnum, dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; @@ -1128,8 +1126,9 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) static int em28xx_dvb_init(struct em28xx *dev) { - int result = 0; + int result = 0, dvb_alt = 0; struct em28xx_dvb *dvb; + struct usb_device *udev; if (dev->is_audio_only) { /* Shouldn't initialize IR for this interface */ @@ -1914,7 +1913,10 @@ static int em28xx_dvb_init(struct em28xx *dev) si2168_config.ts_mode = SI2168_TS_SERIAL; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; + if (dev->ts == PRIMARY_TS) + info.addr = 0x64; + else + info.addr = 0x67; info.platform_data = &si2168_config; request_module(info.type); client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); @@ -1940,7 +1942,10 @@ static int em28xx_dvb_init(struct em28xx *dev) #endif memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; + if (dev->ts == PRIMARY_TS) + info.addr = 0x60; + else + info.addr = 0x63; info.platform_data = &si2157_config; request_module(info.type); client = i2c_new_device(adapter, &info); @@ -1976,7 +1981,10 @@ static int em28xx_dvb_init(struct em28xx *dev) lgdt3306a_config.fe = &dvb->fe[0]; lgdt3306a_config.i2c_adapter = &adapter; strlcpy(info.type, "lgdt3306a", sizeof(info.type)); - info.addr = 0x59; + if (dev->ts == PRIMARY_TS) + info.addr = 0x59; + else + info.addr = 0x0e; info.platform_data = &lgdt3306a_config; request_module(info.type); client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], @@ -2003,7 +2011,10 @@ static int em28xx_dvb_init(struct em28xx *dev) #endif memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", sizeof(info.type)); - info.addr = 0x60; + if (dev->ts == PRIMARY_TS) + info.addr = 0x60; + else + info.addr = 0x62; info.platform_data = &si2157_config; request_module(info.type); @@ -2046,6 +2057,14 @@ static int em28xx_dvb_init(struct em28xx *dev) if (result < 0) goto out_free; + if (dev->dvb_xfer_bulk) { + dvb_alt = 0; + } else { /* isoc */ + dvb_alt = dev->dvb_alt_isoc; + } + + udev = interface_to_usbdev(dev->intf); + usb_set_interface(udev, dev->ifnum, dvb_alt); dev_info(&dev->intf->dev, "DVB extension successfully initialized\n"); kref_get(&dev->ref); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 88084f24f033..c85292c9883b 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -217,6 +217,9 @@ /* max. number of button state polling addresses */ #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5 +#define PRIMARY_TS 0 +#define SECONDARY_TS 1 + enum em28xx_mode { EM28XX_SUSPEND, EM28XX_ANALOG_MODE, @@ -457,6 +460,7 @@ struct em28xx_board { unsigned int mts_firmware:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; + unsigned int has_dual_ts:1; unsigned int is_webcam:1; unsigned int valid:1; unsigned int has_ir_i2c:1; @@ -621,6 +625,7 @@ struct em28xx { unsigned int is_audio_only:1; enum em28xx_int_audio_type int_audio_type; enum em28xx_usb_audio_type usb_audio_type; + unsigned char name[32]; struct em28xx_board board; @@ -682,6 +687,8 @@ struct em28xx { u8 ifnum; /* number of the assigned usb interface */ u8 analog_ep_isoc; /* address of isoc endpoint for analog */ u8 analog_ep_bulk; /* address of bulk endpoint for analog */ + u8 dvb_ep_isoc_ts2; /* address of isoc endpoint for DVB TS2*/ + u8 dvb_ep_bulk_ts2; /* address of bulk endpoint for DVB TS2*/ u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */ int alt; /* alternate setting */ @@ -695,6 +702,8 @@ struct em28xx { int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */ unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the selected DVB ep at dvb_alt */ + unsigned int dvb_max_pkt_size_isoc_ts2; /* isoc max packet size of the + selected DVB ep at dvb_alt */ unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc transfers for DVB */ char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ @@ -726,6 +735,9 @@ struct em28xx { struct media_entity input_ent[MAX_EM28XX_INPUT]; struct media_pad input_pad[MAX_EM28XX_INPUT]; #endif + + struct em28xx *dev_next; + int ts; }; #define kref_to_dev(d) container_of(d, struct em28xx, ref) -- cgit From 0eeb232f5aadc2e258e3963aeacaf405ca842e78 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 6 Mar 2018 04:30:22 -0500 Subject: media: em28xx: constify a new function em28xx_duplicate_dev() is static. This were supposed to be merged on the last patch, but somehow, I forgot "-a" when I called git commit --amend. Fixes: be7fd3c3a8c5 ("media: em28xx: Hauppauge DualHD second tuner functionality") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 7f5d0b28cb8c..fb42f75a3406 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3435,7 +3435,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, return 0; } -int em28xx_duplicate_dev(struct em28xx *dev) +static int em28xx_duplicate_dev(struct em28xx *dev) { int nr; struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); -- cgit From 1b5f69f5b94489343d939700a50a0a841a16f97d Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 1 Feb 2018 17:04:37 -0500 Subject: media: em28xx: Bulk transfer implementation fix Set appropriate bulk/ISOC transfer multiplier on capture start. This sets ISOC transfer to USB endpoint configuration This sets bulk transfer to 48128 bytes (188 * 256) The bulk multiplier is maximum allowed according to Empia. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index ef38e567c4bb..903d0b34f557 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -638,6 +638,19 @@ int em28xx_capture_start(struct em28xx *dev, int start) dev->chip_id == CHIP_ID_EM28174 || dev->chip_id == CHIP_ID_EM28178) { /* The Transport Stream Enable Register moved in em2874 */ + if (dev->dvb_xfer_bulk) { + /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */ + em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + 0xFF); + } else { + /* ISOC Maximum Transfer Size = 188 * 5 */ + em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + dev->dvb_max_pkt_size_isoc / 188); + } if (dev->ts == PRIMARY_TS) rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, -- cgit From c7c7e8d7803406daa21e96d00c357de8b77b6764 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:13 -0500 Subject: media: em28xx: USB bulk packet size fix Hauppauge em28xx bulk devices exhibit continuity errors and corrupted packets, when run in VMWare virtual machines. Unknown if other manufacturers bulk models exhibit the same issue. KVM/Qemu is unaffected. According to documentation the maximum packet multiplier for em28xx in bulk transfer mode is 256 * 188 bytes. This changes the size of bulk transfers to maximum supported value and have a bonus beneficial alignment. Before: After: This sets up USB to expect just as many bytes as the em28xx is set to emit. Successful usage under load afterwards natively and in both VMWare and KVM/Qemu virtual machines. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index c85292c9883b..7be8ac9a9fa0 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -191,7 +191,7 @@ USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 -#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384 +#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 #define EM28XX_INTERLACED_DEFAULT 1 -- cgit From 48efbc370eb2a9857cf65aec675c122302207dbc Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:14 -0500 Subject: media: em28xx: Increase max em28xx boards to max dvb adapters Maximum 4 em28xx boards is too low, this can be maxed out by two devices. This allows all the dvb adapters in the system to be em28xx if so desired. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 7be8ac9a9fa0..3dbcc9d05a8a 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -166,7 +166,7 @@ #define EM28XX_STOP_AUDIO 0 /* maximum number of em28xx boards */ -#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ +#define EM28XX_MAXBOARDS DVB_MAX_ADAPTERS /* All adapters could be em28xx */ /* maximum number of frames that can be queued */ #define EM28XX_NUM_FRAMES 5 -- cgit From f2a326c928cca1f5e36a3dceaf66e8c6b34e9cb8 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:15 -0500 Subject: media: em28xx: Add Hauppauge SoloHD/DualHD bulk models Add additional pids to driver list Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index fb42f75a3406..8d7b7f806f38 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -507,8 +507,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = { }; /* - * 2040:0265 Hauppauge WinTV-dualHD DVB - * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM + * 2040:0265 Hauppauge WinTV-dualHD DVB Isoc + * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk + * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM Isoc + * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk * reg 0x80/0x84: * GPIO_0: Yellow LED tuner 1, 0=on, 1=off * GPIO_1: Green LED tuner 1, 0=on, 1=off @@ -2391,7 +2393,8 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, }, /* - * 2040:0265 Hauppauge WinTV-dualHD (DVB version). + * 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc. + * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk. * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { @@ -2407,7 +2410,8 @@ struct em28xx_board em28xx_boards[] = { .leds = hauppauge_dualhd_leds, }, /* - * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM). + * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc. + * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Bulk. * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157 */ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = { @@ -2549,8 +2553,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, { USB_DEVICE(0x2040, 0x0265), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x2040, 0x8265), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, { USB_DEVICE(0x2040, 0x026d), .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, + { USB_DEVICE(0x2040, 0x826d), + .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -2611,7 +2619,11 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x025f), .driver_info = EM28178_BOARD_PCTV_292E }, - { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */ + { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */ + .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */ .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x0413, 0x6f07), .driver_info = EM2861_BOARD_LEADTEK_VC100 }, -- cgit From cc4406d919d25f2d8667a0eebab179dadaaa1cb5 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:16 -0500 Subject: media: em28xx: Enable Hauppauge SoloHD rebranded 292e SE Add a missing device to the driver table. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 8d7b7f806f38..eb3dcfbac6aa 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2619,6 +2619,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x025f), .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */ + .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */ .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */ -- cgit From 5b3a8e906973540b61dbf402c6b6f8d64d4ae119 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:17 -0500 Subject: media: lgdt3306a: Set fe ops.release to NULL if probed If release is part of frontend ops then it is called in the course of dvb_frontend_detach. The process also decrements the module usage count. The problem is if the lgdt3306a driver is reached via i2c_new_device, then when it is eventually destroyed remove is called, which further decrements the module usage count to negative. After this occurs the driver is in a bad state and no longer works. Also fixed by NULLing out the release callback is a double kfree of state, which introduces arbitrary oopses/GPF. This problem is only currently reachable via the em28xx driver. On disconnect of Hauppauge SoloHD before: lsmod | grep lgdt3306a lgdt3306a 28672 -1 i2c_mux 16384 1 lgdt3306a On disconnect of Hauppauge SoloHD after: lsmod | grep lgdt3306a lgdt3306a 28672 0 i2c_mux 16384 1 lgdt3306a Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 6356815cf3e1..d2477edae197 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -2177,6 +2177,7 @@ static int lgdt3306a_probe(struct i2c_client *client, i2c_set_clientdata(client, fe->demodulator_priv); state = fe->demodulator_priv; + state->frontend.ops.release = NULL; /* create mux i2c adapter for tuner */ state->muxc = i2c_mux_alloc(client->adapter, &client->dev, -- cgit From 4c7c3f9b1a85d26ffd4a8a31dd661856c7482357 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 20:30:24 -0500 Subject: media: lgdt3306a: QAM streaming improvement Add some register updates required for stable viewing on Cablevision in NY. Does not adversely affect other providers. Changes since v1: - Change upper case hex to lower case. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index d2477edae197..377271decbab 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -598,6 +598,28 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) if (lg_chkerr(ret)) goto fail; + /* 5.1 V0.36 SRDCHKALWAYS : For better QAM detection */ + ret = lgdt3306a_read_reg(state, 0x000a, &val); + val &= 0xfd; + val |= 0x02; + ret = lgdt3306a_write_reg(state, 0x000a, val); + if (lg_chkerr(ret)) + goto fail; + + /* 5.2 V0.36 Control of "no signal" detector function */ + ret = lgdt3306a_read_reg(state, 0x2849, &val); + val &= 0xdf; + ret = lgdt3306a_write_reg(state, 0x2849, val); + if (lg_chkerr(ret)) + goto fail; + + /* 5.3 Fix for Blonder Tongue HDE-2H-QAM and AQM modulators */ + ret = lgdt3306a_read_reg(state, 0x302b, &val); + val &= 0x7f; /* SELFSYNCFINDEN_CQS=0; disable auto reset */ + ret = lgdt3306a_write_reg(state, 0x302b, val); + if (lg_chkerr(ret)) + goto fail; + /* 6. Reset */ ret = lgdt3306a_soft_reset(state); if (lg_chkerr(ret)) -- cgit From 4966c0c5c61c0c3a5fb0ebfed7495df02027205f Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 4 Jan 2018 19:04:19 -0500 Subject: media: lgdt3306a: Add QAM AUTO support As configured currently, modulation in the driver is set to auto detect, no matter what the user sets modulation to. This leads to both QAM64 and QAM256 having the same effect. QAM AUTO is explicitly added here for compatibility with scanning software who can use AUTO instead of doing essentially the same scan twice. Also included is a module option to enforce a specific QAM modulation if desired. The true modulation is read before calculating the snr. Changes are backwards compatible with current behaviour. Signed-off-by: Brad Love Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 42 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 377271decbab..fb9c7bc40a9c 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -30,6 +30,17 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); +/* + * Older drivers treated QAM64 and QAM256 the same; that is the HW always + * used "Auto" mode during detection. Setting "forced_manual"=1 allows + * the user to treat these modes as separate. For backwards compatibility, + * it's off by default. QAM_AUTO can now be specified to achive that + * effect even if "forced_manual"=1 + */ +static int forced_manual; +module_param(forced_manual, int, 0644); +MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified"); + #define DBG_INFO 1 #define DBG_REG 2 #define DBG_DUMP 4 /* FGR - comment out to remove dump code */ @@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) /* 3. : 64QAM/256QAM detection(manual, auto) */ ret = lgdt3306a_read_reg(state, 0x0009, &val); val &= 0xfc; - val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */ + /* Check for forced Manual modulation modes; otherwise always "auto" */ + if(forced_manual && (modulation != QAM_AUTO)){ + val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */ + } else { + val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */ + } ret = lgdt3306a_write_reg(state, 0x0009, val); if (lg_chkerr(ret)) goto fail; @@ -642,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state, ret = lgdt3306a_set_vsb(state); break; case QAM_64: - ret = lgdt3306a_set_qam(state, QAM_64); - break; case QAM_256: - ret = lgdt3306a_set_qam(state, QAM_256); + case QAM_AUTO: + ret = lgdt3306a_set_qam(state, p->modulation); break; default: return -EINVAL; @@ -672,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: break; default: return -EINVAL; @@ -726,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: /* Auto ok for QAM */ ret = lgdt3306a_set_inversion_auto(state, 1); break; @@ -749,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state, break; case QAM_64: case QAM_256: + case QAM_AUTO: if_freq_khz = state->cfg->qam_if_khz; break; default: @@ -1607,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe, switch (state->current_modulation) { case QAM_256: case QAM_64: + case QAM_AUTO: if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) { *status |= FE_HAS_VITERBI; *status |= FE_HAS_SYNC; @@ -1650,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, * Calculate some sort of "strength" from SNR */ struct lgdt3306a_state *state = fe->demodulator_priv; + u8 val; u16 snr; /* snr_x10 */ int ret; u32 ref_snr; /* snr*100 */ @@ -1662,11 +1682,15 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, ref_snr = 1600; /* 16dB */ break; case QAM_64: - ref_snr = 2200; /* 22dB */ - break; case QAM_256: - ref_snr = 2800; /* 28dB */ - break; + case QAM_AUTO: + /* need to know actual modulation to set proper SNR baseline */ + lgdt3306a_read_reg(state, 0x00a6, &val); + if(val & 0x04) + ref_snr = 2800; /* QAM-256 28dB */ + else + ref_snr = 2200; /* QAM-64 22dB */ + break; default: return -EINVAL; } @@ -2136,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + .caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB }, .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl, .init = lgdt3306a_init, -- cgit From 835d66173a38538c072a7c393d02360dcfac8582 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 09:57:12 -0500 Subject: media: lgdt3306a: Fix module count mismatch on usb unplug When used as an i2c device there is a module usage count mismatch on removal, preventing the driver from being used thereafter. dvb_attach increments the usage count so it is properly balanced on removal. On disconnect of Hauppauge SoloHD/DualHD before: lsmod | grep lgdt3306a lgdt3306a 28672 -1 i2c_mux 16384 1 lgdt3306a On disconnect of Hauppauge SoloHD/DualHD after: lsmod | grep lgdt3306a lgdt3306a 28672 0 i2c_mux 16384 1 lgdt3306a Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index fb9c7bc40a9c..adcaf9b20ce3 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -2215,7 +2215,7 @@ static int lgdt3306a_probe(struct i2c_client *client, sizeof(struct lgdt3306a_config)); config->i2c_addr = client->addr; - fe = lgdt3306a_attach(config, client->adapter); + fe = dvb_attach(lgdt3306a_attach, config, client->adapter); if (fe == NULL) { ret = -ENODEV; goto err_fe; -- cgit From 94448e21cf08b10f7dc7acdaca387594370396b0 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 09:57:13 -0500 Subject: media: lgdt3306a: Fix a double kfree on i2c device remove Both lgdt33606a_release and lgdt3306a_remove kfree state, but _release is called first, then _remove operates on states members before kfree'ing it. This can lead to random oops/GPF/etc on USB disconnect. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index adcaf9b20ce3..0ed64604d7af 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1814,7 +1814,13 @@ static void lgdt3306a_release(struct dvb_frontend *fe) struct lgdt3306a_state *state = fe->demodulator_priv; dbg_info("\n"); - kfree(state); + + /* + * If state->muxc is not NULL, then we are an i2c device + * and lgdt3306a_remove will clean up state + */ + if (!state->muxc) + kfree(state); } static const struct dvb_frontend_ops lgdt3306a_ops; -- cgit From d571b592c6206d33731f41aa710fa0f69ac8611b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 27 Feb 2018 06:08:09 -0500 Subject: media: em28xx: don't use coherent buffer for DMA transfers While coherent memory is cheap on x86, it may cause performance impacts on other archs. As we don't have any good reason to use it, let's change the logic by allocating memory via kmalloc() and letting the USB core to do the DMA mapping and memory free for us. While here, also fixes an issue that it was not de-allocating memories if something gets wrong during memory block allocation. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 51 +++++++++++++++------------------- drivers/media/usb/em28xx/em28xx.h | 2 +- 2 files changed, 24 insertions(+), 29 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 903d0b34f557..69c74febd184 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -821,7 +821,6 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) { struct urb *urb; struct em28xx_usb_bufs *usb_bufs; - struct usb_device *udev = interface_to_usbdev(dev->intf); int i; em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n", @@ -840,23 +839,16 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) else usb_unlink_urb(urb); - if (usb_bufs->transfer_buffer[i]) { - usb_free_coherent(udev, - urb->transfer_buffer_length, - usb_bufs->transfer_buffer[i], - urb->transfer_dma); - } usb_free_urb(urb); usb_bufs->urb[i] = NULL; } - usb_bufs->transfer_buffer[i] = NULL; } kfree(usb_bufs->urb); - kfree(usb_bufs->transfer_buffer); + kfree(usb_bufs->buf); usb_bufs->urb = NULL; - usb_bufs->transfer_buffer = NULL; + usb_bufs->buf = NULL; usb_bufs->num_bufs = 0; em28xx_capture_start(dev, 0); @@ -933,14 +925,13 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->num_bufs = num_bufs; - usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + usb_bufs->urb = kcalloc(sizeof(void *), num_bufs, GFP_KERNEL); if (!usb_bufs->urb) return -ENOMEM; - usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!usb_bufs->transfer_buffer) { - kfree(usb_bufs->urb); + usb_bufs->buf = kcalloc(sizeof(void *), num_bufs, GFP_KERNEL); + if (!usb_bufs->buf) { + kfree(usb_bufs->buf); return -ENOMEM; } @@ -963,37 +954,41 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, } usb_bufs->urb[i] = urb; - usb_bufs->transfer_buffer[i] = usb_alloc_coherent(udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!usb_bufs->transfer_buffer[i]) { + usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL); + if (!usb_bufs->buf[i]) { dev_err(&dev->intf->dev, "unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); + em28xx_uninit_usb_xfer(dev, mode); + + for (i--; i >= 0; i--) + kfree(usb_bufs->buf[i]); + + kfree(usb_bufs->buf); + usb_bufs->buf = NULL; + return -ENOMEM; } - memset(usb_bufs->transfer_buffer[i], 0, sb_size); + + urb->transfer_flags = URB_FREE_BUFFER; if (xfer_bulk) { /* bulk */ pipe = usb_rcvbulkpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_bulk : dev->dvb_ep_bulk); - usb_fill_bulk_urb(urb, udev, pipe, - usb_bufs->transfer_buffer[i], sb_size, - em28xx_irq_callback, dev); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->buf[i], + sb_size, em28xx_irq_callback, dev); } else { /* isoc */ pipe = usb_rcvisocpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_isoc : dev->dvb_ep_isoc); - usb_fill_int_urb(urb, udev, pipe, - usb_bufs->transfer_buffer[i], sb_size, - em28xx_irq_callback, dev, 1); - urb->transfer_flags = URB_ISO_ASAP | - URB_NO_TRANSFER_DMA_MAP; + usb_fill_int_urb(urb, udev, pipe, usb_bufs->buf[i], + sb_size, em28xx_irq_callback, dev, 1); + urb->transfer_flags |= URB_ISO_ASAP; k = 0; for (j = 0; j < usb_bufs->num_packets; j++) { urb->iso_frame_desc[j].offset = k; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 3dbcc9d05a8a..a52f23efd624 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -242,7 +242,7 @@ struct em28xx_usb_bufs { struct urb **urb; /* transfer buffers for isoc/bulk transfer */ - char **transfer_buffer; + char **buf; }; struct em28xx_usb_ctl { -- cgit From 6cda90b63edd1d2b1446793e0fcb8b4a725f8ac5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Mar 2018 09:59:28 -0500 Subject: media: em28xx: improve the logic with sets Xclk and I2C speed The logic there should be called on two places. Also, ideally, it should not be modifying the device struct. So, change the logic accordingly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 45 +++++++++++++++++---------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index eb3dcfbac6aa..996e8994f4a6 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2685,20 +2685,35 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg) } EXPORT_SYMBOL_GPL(em28xx_tuner_callback); -static inline void em28xx_set_model(struct em28xx *dev) +static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) { - dev->board = em28xx_boards[dev->model]; + struct em28xx_board *board = &em28xx_boards[dev->model]; + u8 xclk = board->xclk, i2c_speed = board->i2c_speed; /* Those are the default values for the majority of boards Use those values if not specified otherwise at boards entry */ - if (!dev->board.xclk) - dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | + if (!xclk) + xclk = EM28XX_XCLK_IR_RC5_MODE | EM28XX_XCLK_FREQUENCY_12MHZ; - if (!dev->board.i2c_speed) - dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_FREQ_100_KHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); + + + if (!i2c_speed) + i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ; + + if (!dev->board.is_em2800) + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed); + msleep(50); +} + +static inline void em28xx_set_model(struct em28xx *dev) +{ + dev->board = em28xx_boards[dev->model]; + + em28xx_set_xclk_i2c_speed(dev); /* Should be initialized early, for I2C to work */ dev->def_i2c_bus = dev->board.def_i2c_bus; @@ -2741,10 +2756,7 @@ static void em28xx_pre_card_setup(struct em28xx *dev) { /* Set the initial XCLK and I2C clock values based on the board definition */ - em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); - if (!dev->board.is_em2800) - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - msleep(50); + em28xx_set_xclk_i2c_speed(dev); /* request some modules */ switch (dev->model) { @@ -3399,17 +3411,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, em28xx_pre_card_setup(dev); - if (!dev->board.is_em2800) { - /* Resets I2C speed */ - retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); - if (retval < 0) { - dev_err(&dev->intf->dev, - "%s: em28xx_write_reg failed! retval [%d]\n", - __func__, retval); - return retval; - } - } - rt_mutex_init(&dev->i2c_bus_lock); /* register i2c bus 0 */ -- cgit From aa62980be47e1fe1f40cbaf0a80589193faa7ab9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Mar 2018 10:08:42 -0500 Subject: media: em28xx: stop rewriting device's struct Writing at the device's struct is evil, as two em28xx devices may be using it. So, stop abusing it, storing the values inside struct em28xx_dev. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 14 ++++++++------ drivers/media/usb/em28xx/em28xx-core.c | 4 ++-- drivers/media/usb/em28xx/em28xx-video.c | 26 +++++++++++++------------- drivers/media/usb/em28xx/em28xx.h | 2 ++ 4 files changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 996e8994f4a6..bb6a84891bba 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2712,6 +2712,8 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) static inline void em28xx_set_model(struct em28xx *dev) { dev->board = em28xx_boards[dev->model]; + dev->has_msp34xx = dev->board.has_msp34xx; + dev->is_webcam = dev->board.is_webcam; em28xx_set_xclk_i2c_speed(dev); @@ -2871,7 +2873,7 @@ static int em28xx_hint_board(struct em28xx *dev) { int i; - if (dev->board.is_webcam) { + if (dev->is_webcam) { if (dev->em28xx_sensor == EM28XX_MT9V011) { dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; } else if (dev->em28xx_sensor == EM28XX_MT9M001 || @@ -2963,11 +2965,11 @@ static void em28xx_card_setup(struct em28xx *dev) * If the device can be a webcam, seek for a sensor. * If sensor is not found, then it isn't a webcam. */ - if (dev->board.is_webcam) { + if (dev->is_webcam) { em28xx_detect_sensor(dev); if (dev->em28xx_sensor == EM28XX_NOSENSOR) /* NOTE: error/unknown sensor/no sensor */ - dev->board.is_webcam = 0; + dev->is_webcam = 0; } switch (dev->model) { @@ -3029,7 +3031,7 @@ static void em28xx_card_setup(struct em28xx *dev) if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) { dev->i2s_speed = 2048000; - dev->board.has_msp34xx = 1; + dev->has_msp34xx = 1; } break; } @@ -3742,7 +3744,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if (usb_xfer_mode < 0) { - if (dev->board.is_webcam) + if (dev->is_webcam) try_bulk = 1; else try_bulk = 0; @@ -3794,7 +3796,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */ if (usb_xfer_mode < 0) { - if (dev->dev_next->board.is_webcam) + if (dev->dev_next->is_webcam) try_bulk = 1; else try_bulk = 0; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 69c74febd184..0ea1d72bc02b 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -378,7 +378,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } - if (dev->board.has_msp34xx) + if (dev->has_msp34xx) input = EM28XX_AUDIO_SRC_TUNER; else { switch (dev->ctl_ainput) { @@ -672,7 +672,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; if (start) { - if (dev->board.is_webcam) + if (dev->is_webcam) rc = em28xx_write_reg(dev, 0x13, 0x0c); /* Enable video capture */ diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2724e3b99af2..3744c31e2a91 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -148,7 +148,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (dev->board.is_webcam) + if (dev->is_webcam) return v4l2->sensor_xres; if (dev->board.max_range_640_480) @@ -161,7 +161,7 @@ static inline unsigned int norm_maxh(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (dev->board.is_webcam) + if (dev->is_webcam) return v4l2->sensor_yres; if (dev->board.max_range_640_480) @@ -176,7 +176,7 @@ static int em28xx_vbi_supported(struct em28xx *dev) if (disable_vbi == 1) return 0; - if (dev->board.is_webcam) + if (dev->is_webcam) return 0; /* FIXME: check subdevices for VBI support */ @@ -976,7 +976,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) } /* Webcams don't have input connectors */ - if (dev->board.is_webcam) + if (dev->is_webcam) return; /* Create entities for each input connector */ @@ -1277,7 +1277,7 @@ static void video_mux(struct em28xx *dev, int index) v4l2_device_call_all(v4l2_dev, 0, video, s_routing, INPUT(index)->vmux, 0, 0); - if (dev->board.has_msp34xx) { + if (dev->has_msp34xx) { if (dev->i2s_speed) { v4l2_device_call_all(v4l2_dev, 0, audio, s_i2s_clock_freq, dev->i2s_speed); @@ -1593,7 +1593,7 @@ static int vidioc_g_parm(struct file *file, void *priv, p->parm.capture.readbuffers = EM28XX_MIN_BUF; p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - if (dev->board.is_webcam) { + if (dev->is_webcam) { rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0, video, g_frame_interval, &ival); if (!rc) @@ -1616,7 +1616,7 @@ static int vidioc_s_parm(struct file *file, void *priv, }; int rc = 0; - if (!dev->board.is_webcam) + if (!dev->is_webcam) return -ENOTTY; if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && @@ -1655,7 +1655,7 @@ static int vidioc_enum_input(struct file *file, void *priv, i->std = dev->v4l2->vdev.tvnorms; /* webcams do not have the STD API */ - if (dev->board.is_webcam) + if (dev->is_webcam) i->capabilities = 0; return 0; @@ -2369,7 +2369,7 @@ static void em28xx_vdev_init(struct em28xx *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2->v4l2_dev; vfd->lock = &dev->lock; - if (dev->board.is_webcam) + if (dev->is_webcam) vfd->tvnorms = 0; snprintf(vfd->name, sizeof(vfd->name), "%s %s", @@ -2484,7 +2484,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2_ctrl_handler_init(hdl, 8); v4l2->v4l2_dev.ctrl_handler = hdl; - if (dev->board.is_webcam) + if (dev->is_webcam) v4l2->progressive = true; /* @@ -2496,7 +2496,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* request some modules */ - if (dev->board.has_msp34xx) + if (dev->has_msp34xx) v4l2_i2c_new_subdev(&v4l2->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "msp3400", 0, msp3400_addrs); @@ -2585,7 +2585,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vbiq.active); - if (dev->board.has_msp34xx) { + if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { @@ -2679,7 +2679,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->vdev.queue->lock = &v4l2->vb_queue_lock; /* disable inapplicable ioctls */ - if (dev->board.is_webcam) { + if (dev->is_webcam) { v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD); v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD); v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a52f23efd624..b640fb0683b0 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -623,6 +623,8 @@ struct em28xx { unsigned char disconnected:1; /* device has been diconnected */ unsigned int has_video:1; unsigned int is_audio_only:1; + unsigned int is_webcam:1; + unsigned int has_msp34xx:1; enum em28xx_int_audio_type int_audio_type; enum em28xx_usb_audio_type usb_audio_type; unsigned char name[32]; -- cgit From 0108ae7fd2972707cde3fafa6fec555c50c64e28 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Mar 2018 10:34:34 -0500 Subject: media: em28xx: constify most static structs There are several em28xx static structs that can now be constified. That caused a significant reduction at data segment: Before: text data bss dec hex filename 85017 59588 576 145181 2371d drivers/media/usb/em28xx/em28xx.o After: text data bss dec hex filename 112345 32292 576 145213 2373d drivers/media/usb/em28xx/em28xx.o Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 106 ++++++++++++++++---------------- drivers/media/usb/em28xx/em28xx-core.c | 2 +- drivers/media/usb/em28xx/em28xx-input.c | 6 +- drivers/media/usb/em28xx/em28xx.h | 16 ++--- 4 files changed, 66 insertions(+), 64 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index bb6a84891bba..5277f1cda253 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -81,26 +81,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev); */ /* Reset for the most [analog] boards */ -static struct em28xx_reg_seq default_analog[] = { +static const struct em28xx_reg_seq default_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; /* Reset for the most [digital] boards */ -static struct em28xx_reg_seq default_digital[] = { +static const struct em28xx_reg_seq default_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 analog */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { {EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10}, { 0x05, 0xff, 0x10, 10}, { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x04, 0x0f, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, @@ -108,14 +108,14 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { }; /* Board Hauppauge WinTV HVR 900 (R2) digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { +static const struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, { -1, -1, -1, -1}, }; /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { +static const struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; @@ -126,7 +126,7 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { Analog - No input analog */ /* Board - EM2882 Kworld 315U digital */ -static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { +static const struct em28xx_reg_seq em2882_kworld_315u_digital[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, {EM2880_R04_GPO, 0x04, 0xff, 10}, @@ -135,7 +135,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { +static const struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { {EM2880_R04_GPO, 0x08, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, @@ -143,13 +143,13 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_330u_analog[] = { +static const struct em28xx_reg_seq kworld_330u_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_330u_digital[] = { +static const struct em28xx_reg_seq kworld_330u_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, @@ -161,12 +161,12 @@ static struct em28xx_reg_seq kworld_330u_digital[] = { GPIO4 - xc3028 reset GOP3 - s5h1409 reset */ -static struct em28xx_reg_seq evga_indtube_analog[] = { +static const struct em28xx_reg_seq evga_indtube_analog[] = { {EM2820_R08_GPIO_CTRL, 0x79, 0xff, 60}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq evga_indtube_digital[] = { +static const struct em28xx_reg_seq evga_indtube_digital[] = { {EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1}, {EM2880_R04_GPO, 0x04, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 1}, @@ -184,12 +184,12 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { * EM_GPIO_6 - currently unknown * EM_GPIO_7 - currently unknown */ -static struct em28xx_reg_seq kworld_a340_digital[] = { +static const struct em28xx_reg_seq kworld_a340_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { +static const struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100}, @@ -198,25 +198,25 @@ static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { }; /* Pinnacle Hybrid Pro eb1a:2881 */ -static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { +static const struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { {EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { +static const struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */ {EM2880_R04_GPO, 0x0c, 0xff, 1}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { +static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { +static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, @@ -226,7 +226,7 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { 0-5: not used 6: demod reset, active low 7: LED on, active high */ -static struct em28xx_reg_seq em2874_pctv_80e_digital[] = { +static const struct em28xx_reg_seq em2874_pctv_80e_digital[] = { {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10}, @@ -236,7 +236,7 @@ static struct em28xx_reg_seq em2874_pctv_80e_digital[] = { /* eb1a:2868 Reddo DVB-C USB TV Box GPIO4 - CU1216L NIM Other GPIOs seems to be don't care. */ -static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { +static const struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xde, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, @@ -248,7 +248,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { }; /* Callback for the most boards */ -static struct em28xx_reg_seq default_tuner_gpio[] = { +static const struct em28xx_reg_seq default_tuner_gpio[] = { {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, @@ -256,58 +256,58 @@ static struct em28xx_reg_seq default_tuner_gpio[] = { }; /* Mute/unmute */ -static struct em28xx_reg_seq compro_unmute_tv_gpio[] = { +static const struct em28xx_reg_seq compro_unmute_tv_gpio[] = { {EM2820_R08_GPIO_CTRL, 5, 7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq compro_unmute_svid_gpio[] = { +static const struct em28xx_reg_seq compro_unmute_svid_gpio[] = { {EM2820_R08_GPIO_CTRL, 4, 7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq compro_mute_gpio[] = { +static const struct em28xx_reg_seq compro_mute_gpio[] = { {EM2820_R08_GPIO_CTRL, 6, 7, 10}, { -1, -1, -1, -1}, }; /* Terratec AV350 */ -static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { +static const struct em28xx_reg_seq terratec_av350_mute_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0x7f, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { +static const struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq silvercrest_reg_seq[] = { +static const struct em28xx_reg_seq silvercrest_reg_seq[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0x01, 0xf7, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq vc211a_enable[] = { +static const struct em28xx_reg_seq vc211a_enable[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0x07, 10}, {EM2820_R08_GPIO_CTRL, 0xff, 0x0f, 10}, {EM2820_R08_GPIO_CTRL, 0xff, 0x0b, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq dikom_dk300_digital[] = { +static const struct em28xx_reg_seq dikom_dk300_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, { -1, -1, -1, -1}, }; /* Reset for the most [digital] boards */ -static struct em28xx_reg_seq leadership_digital[] = { +static const struct em28xx_reg_seq leadership_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq leadership_reset[] = { +static const struct em28xx_reg_seq leadership_reset[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, @@ -318,7 +318,7 @@ static struct em28xx_reg_seq leadership_reset[] = { * GPIO_6 - demod reset * GPIO_7 - LED */ -static struct em28xx_reg_seq pctv_290e[] = { +static const struct em28xx_reg_seq pctv_290e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80}, {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */ @@ -326,7 +326,7 @@ static struct em28xx_reg_seq pctv_290e[] = { }; #if 0 -static struct em28xx_reg_seq terratec_h5_gpio[] = { +static const struct em28xx_reg_seq terratec_h5_gpio[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50}, @@ -334,7 +334,7 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_h5_digital[] = { +static const struct em28xx_reg_seq terratec_h5_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, @@ -352,7 +352,7 @@ static struct em28xx_reg_seq terratec_h5_digital[] = { * GPIO_6 - RESET_DEM * GPIO_7 - LED (green LED) */ -static struct em28xx_reg_seq pctv_460e[] = { +static const struct em28xx_reg_seq pctv_460e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50}, { 0x0d, 0xff, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */ @@ -361,7 +361,7 @@ static struct em28xx_reg_seq pctv_460e[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { +static const struct em28xx_reg_seq c3tech_digital_duo_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10}, /* xc5000 reset */ {EM2874_R80_GPIO_P0_CTRL, 0xf9, 0xff, 35}, @@ -384,7 +384,7 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { * GPIO 6 = #RESET_DEM * GPIO 7 = P07_LED (green LED) */ -static struct em28xx_reg_seq pctv_461e[] = { +static const struct em28xx_reg_seq pctv_461e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0}, {0x0d, 0xff, 0xff, 0}, {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */ @@ -396,7 +396,7 @@ static struct em28xx_reg_seq pctv_461e[] = { }; #if 0 -static struct em28xx_reg_seq hauppauge_930c_gpio[] = { +static const struct em28xx_reg_seq hauppauge_930c_gpio[] = { {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */ {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, @@ -404,7 +404,7 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = { { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq hauppauge_930c_digital[] = { +static const struct em28xx_reg_seq hauppauge_930c_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, @@ -417,7 +417,7 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = { * GPIO_6 - demod reset, 0=active * GPIO_7 - LED, 0=active */ -static struct em28xx_reg_seq maxmedia_ub425_tc[] = { +static const struct em28xx_reg_seq maxmedia_ub425_tc[] = { {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ @@ -430,7 +430,7 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = { * GPIO_6: demod reset, 0=active * GPIO_7: LED, 1=active */ -static struct em28xx_reg_seq pctv_510e[] = { +static const struct em28xx_reg_seq pctv_510e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ @@ -443,7 +443,7 @@ static struct em28xx_reg_seq pctv_510e[] = { * GPIO_6: demod reset, 0=active * GPIO_7: LED, 1=active */ -static struct em28xx_reg_seq pctv_520e[] = { +static const struct em28xx_reg_seq pctv_520e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ @@ -460,13 +460,13 @@ static struct em28xx_reg_seq pctv_520e[] = { * reg 0x81/0x85: * GPIO_7: snapshot button, 0=pressed, 1=unpressed */ -static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { +static const struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10}, { -1, -1, -1, -1}, }; -static struct em28xx_reg_seq pctv_292e[] = { +static const struct em28xx_reg_seq pctv_292e[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 950}, {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100}, @@ -478,7 +478,7 @@ static struct em28xx_reg_seq pctv_292e[] = { {-1, -1, -1, -1}, }; -static struct em28xx_reg_seq terratec_t2_stick_hd[] = { +static const struct em28xx_reg_seq terratec_t2_stick_hd[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 600}, {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 10}, @@ -492,7 +492,7 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = { {-1, -1, -1, -1}, }; -static struct em28xx_reg_seq plex_px_bcud[] = { +static const struct em28xx_reg_seq plex_px_bcud[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 0}, {EM2874_R50_IR_CONFIG, 0x01, 0xff, 0}, @@ -519,7 +519,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = { * GPIO_5: Reset #2, 0=active * GPIO_6: Reset #1, 0=active */ -static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { +static const struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, {0x0d, 0xff, 0xff, 200}, {0x50, 0x04, 0xff, 300}, @@ -536,7 +536,7 @@ static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { /* * Button definitions */ -static struct em28xx_button std_snapshot_button[] = { +static const struct em28xx_button std_snapshot_button[] = { { .role = EM28XX_BUTTON_SNAPSHOT, .reg_r = EM28XX_R0C_USBSUSP, @@ -547,7 +547,7 @@ static struct em28xx_button std_snapshot_button[] = { {-1, 0, 0, 0, 0}, }; -static struct em28xx_button speedlink_vad_laplace_buttons[] = { +static const struct em28xx_button speedlink_vad_laplace_buttons[] = { { .role = EM28XX_BUTTON_SNAPSHOT, .reg_r = EM2874_R85_GPIO_P1_STATE, @@ -631,7 +631,7 @@ static struct em28xx_led hauppauge_dualhd_leds[] = { /* * Board definitions */ -struct em28xx_board em28xx_boards[] = { +const struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "EM2710/EM2750/EM2751 webcam grabber", .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, @@ -2642,7 +2642,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table); /* * EEPROM hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_eeprom_hash[] = { +static const struct em28xx_hash_table em28xx_eeprom_hash[] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, @@ -2655,7 +2655,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { }; /* I2C devicelist hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_i2c_hash[] = { +static const struct em28xx_hash_table em28xx_i2c_hash[] = { {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, @@ -2687,7 +2687,7 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback); static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) { - struct em28xx_board *board = &em28xx_boards[dev->model]; + const struct em28xx_board *board = &em28xx_boards[dev->model]; u8 xclk = board->xclk, i2c_speed = board->i2c_speed; /* Those are the default values for the majority of boards diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 0ea1d72bc02b..44a162dd4867 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -712,7 +712,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; } -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) +int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio) { int rc = 0; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 046223de1e91..270cd68df4a2 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -515,7 +515,8 @@ static void em28xx_query_buttons(struct work_struct *work) j = 0; while (dev->board.buttons[j].role >= 0 && dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) { - struct em28xx_button *button = &dev->board.buttons[j]; + const struct em28xx_button *button = &dev->board.buttons[j]; + /* Check if button uses the current address */ if (button->reg_r != dev->button_polling_addresses[i]) { j++; @@ -618,7 +619,8 @@ static void em28xx_init_buttons(struct em28xx *dev) dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL; while (dev->board.buttons[i].role >= 0 && dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) { - struct em28xx_button *button = &dev->board.buttons[i]; + const struct em28xx_button *button = &dev->board.buttons[i]; + /* Check if polling address is already on the list */ addr_new = true; for (j = 0; j < dev->num_button_polling_addresses; j++) { diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index b640fb0683b0..1d367177a84a 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -386,7 +386,7 @@ struct em28xx_input { unsigned int vmux; enum em28xx_amux amux; enum em28xx_aout aout; - struct em28xx_reg_seq *gpio; + const struct em28xx_reg_seq *gpio; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -450,10 +450,10 @@ struct em28xx_board { unsigned int tda9887_conf; /* GPIO sequences */ - struct em28xx_reg_seq *dvb_gpio; - struct em28xx_reg_seq *suspend_gpio; - struct em28xx_reg_seq *tuner_gpio; - struct em28xx_reg_seq *mute_gpio; + const struct em28xx_reg_seq *dvb_gpio; + const struct em28xx_reg_seq *suspend_gpio; + const struct em28xx_reg_seq *tuner_gpio; + const struct em28xx_reg_seq *mute_gpio; unsigned int is_em2800:1; unsigned int has_msp34xx:1; @@ -480,7 +480,7 @@ struct em28xx_board { struct em28xx_led *leds; /* Buttons */ - struct em28xx_button *buttons; + const struct em28xx_button *buttons; }; struct em28xx_eeprom { @@ -792,7 +792,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode); void em28xx_stop_urbs(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); +int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); @@ -801,7 +801,7 @@ int em28xx_suspend_extension(struct em28xx *dev); int em28xx_resume_extension(struct em28xx *dev); /* Provided by em28xx-cards.c */ -extern struct em28xx_board em28xx_boards[]; +extern const struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl); -- cgit From cf68c22f106369f6124342c58c4a50f07edd2174 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Mar 2018 12:54:06 -0500 Subject: media: em28xx: adjust I2C timeout according with I2C speed If the I2C speed is too slow, it should wait more for an answer. While here, change disconnected type from char to unsigned int, just like all other bitmask fields there at em28xx struct. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 ++ drivers/media/usb/em28xx/em28xx-i2c.c | 36 ++++++++++++++++++++++++++++++--- drivers/media/usb/em28xx/em28xx.h | 19 ++--------------- 3 files changed, 37 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 5277f1cda253..fc4654f7eece 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2704,6 +2704,8 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ; + dev->i2c_speed = i2c_speed & 0x03; + if (!dev->board.is_em2800) em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed); msleep(50); diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9ad958004990..fc90f5a32255 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -51,13 +51,43 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I } while (0) +/* + * Time in msecs to wait for i2c xfers to finish. + * 35ms is the maximum time a SMBUS device could wait when + * clock stretching is used. As the transfer itself will take + * some time to happen, set it to 35 ms. + * + * Ok, I2C doesn't specify any limit. So, eventually, we may need + * to increase this timeout. + */ +#define EM28XX_I2C_XFER_TIMEOUT 35 /* ms */ + +static int em28xx_i2c_timeout(struct em28xx *dev) +{ + int time = EM28XX_I2C_XFER_TIMEOUT; + + switch (dev->i2c_speed & 0x03) { + case EM28XX_I2C_FREQ_25_KHZ: + time += 4; /* Assume 4 ms for transfers */ + break; + case EM28XX_I2C_FREQ_100_KHZ: + case EM28XX_I2C_FREQ_400_KHZ: + time += 1; /* Assume 1 ms for transfers */ + break; + default: /* EM28XX_I2C_FREQ_1_5_MHZ */ + break; + } + + return msecs_to_jiffies(time); +} + /* * em2800_i2c_send_bytes() * send up to 4 bytes to the em2800 i2c device */ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); int ret; u8 b2[6]; @@ -110,7 +140,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) */ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); u8 buf2[4]; int ret; int i; @@ -186,7 +216,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len, int stop) { - unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + unsigned long timeout = jiffies + em28xx_i2c_timeout(dev); int ret; if (len < 1 || len > 64) diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 1d367177a84a..0646367568ab 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -195,22 +195,6 @@ #define EM28XX_INTERLACED_DEFAULT 1 -/* - * Time in msecs to wait for i2c xfers to finish. - * 35ms is the maximum time a SMBUS device could wait when - * clock stretching is used. As the transfer itself will take - * some time to happen, set it to 35 ms. - * - * Ok, I2C doesn't specify any limit. So, eventually, we may need - * to increase this timeout. - * - * FIXME: this assumes that an I2C message is not longer than 1ms. - * This is actually dependent on the I2C bus speed, although most - * devices use a 100kHz clock. So, this assumtion is true most of - * the time. - */ -#define EM28XX_I2C_XFER_TIMEOUT 36 - /* time in msecs to wait for AC97 xfers to finish */ #define EM28XX_AC97_XFER_TIMEOUT 100 @@ -620,11 +604,12 @@ struct em28xx { enum em28xx_chip_id chip_id; unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ - unsigned char disconnected:1; /* device has been diconnected */ + unsigned int disconnected:1; /* device has been diconnected */ unsigned int has_video:1; unsigned int is_audio_only:1; unsigned int is_webcam:1; unsigned int has_msp34xx:1; + unsigned int i2c_speed:2; enum em28xx_int_audio_type int_audio_type; enum em28xx_usb_audio_type usb_audio_type; unsigned char name[32]; -- cgit From f410b4093fdd4d8f4644d3d486afe3040eceef7b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 11 Dec 2017 07:05:02 -0500 Subject: media: em28xx: split up em28xx_dvb_init to reduce stack size With CONFIG_KASAN, the init function uses a large amount of kernel stack: drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init.part.4': drivers/media/usb/em28xx/em28xx-dvb.c:2061:1: error: the frame size of 3232 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] Using gcc-7 with -fsanitize-address-use-after-scope makes this even worse: drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init': drivers/media/usb/em28xx/em28xx-dvb.c:2069:1: error: the frame size of 4280 bytes is larger than 3072 bytes [-Werror=frame-larger-than=] By splitting out each part of the switch/case statement that has its own local variables into a separate function, no single one of them uses more than 500 bytes, and with a noinline_for_stack annotation we can ensure that they are not merged back together. [mchehab@s-opensource.com: fix conflict with changeset be7fd3c3a8c5 ("media: em28xx: Hauppauge DualHD second tuner functionality")] Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab <> Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 971 ++++++++++++++++++---------------- 1 file changed, 520 insertions(+), 451 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9bc957690b45..ea921da43ea6 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -932,7 +932,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = { /* ------------------------------------------------------------------ */ -static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) +static noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; @@ -1124,6 +1124,504 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) dvb_unregister_adapter(&dvb->adapter); } +static noinline_for_stack int em28174_dvb_init_pctv_460e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_client *client; + struct i2c_board_info board_info; + struct tda10071_platform_data tda10071_pdata = {}; + struct a8293_platform_data a8293_pdata = {}; + int result; + + /* attach demod + tuner combo */ + tda10071_pdata.clk = 40444000, /* 40.444 MHz */ + tda10071_pdata.i2c_wr_max = 64, + tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, + tda10071_pdata.pll_multiplier = 20, + tda10071_pdata.tuner_i2c_addr = 0x14, + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); + board_info.addr = 0x55; + board_info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client); + dvb->i2c_client_demod = client; + + /* attach SEC */ + a8293_pdata.dvb_frontend = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); + board_info.addr = 0x08; + board_info.platform_data = &a8293_pdata; + request_module("a8293"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_sec = client; + result = 0; +out_free: + return result; +} + +static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_client *client; + struct i2c_adapter *i2c_adapter; + struct i2c_board_info board_info; + struct m88ds3103_platform_data m88ds3103_pdata = {}; + struct ts2020_config ts2020_config = {}; + struct a8293_platform_data a8293_pdata = {}; + int result; + + /* attach demod */ + m88ds3103_pdata.clk = 27000000; + m88ds3103_pdata.i2c_wr_max = 33; + m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; + m88ds3103_pdata.ts_clk = 16000; + m88ds3103_pdata.ts_clk_pol = 1; + m88ds3103_pdata.agc = 0x99; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); + board_info.addr = 0x68; + board_info.platform_data = &m88ds3103_pdata; + request_module("m88ds3103"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client); + i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client); + dvb->i2c_client_demod = client; + + /* attach tuner */ + ts2020_config.fe = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); + board_info.addr = 0x60; + board_info.platform_data = &ts2020_config; + request_module("ts2020"); + client = i2c_new_device(i2c_adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_tuner = client; + /* delegate signal strength measurement to tuner */ + dvb->fe[0]->ops.read_signal_strength = + dvb->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SEC */ + a8293_pdata.dvb_frontend = dvb->fe[0]; + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); + board_info.addr = 0x08; + board_info.platform_data = &a8293_pdata; + request_module("a8293"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_tuner->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_tuner); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_tuner->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_tuner); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_sec = client; + result = 0; +out_free: + return result; +} + +static noinline_for_stack int em28178_dvb_init_pctv_292e(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + int result; + + /* attach demod */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; + result = 0; +out_free: + return result; +} + +static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + int result; + + /* attach demod */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 0; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2146", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("si2157"); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + result = 0; +out_free: + return result; +} + +static noinline_for_stack int em28178_dvb_init_plex_px_bcud(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_client *client; + struct i2c_board_info info; + struct tc90522_config tc90522_config; + struct qm1d1c0042_config qm1d1c0042_config; + int result; + + /* attach demod */ + memset(&tc90522_config, 0, sizeof(tc90522_config)); + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); + info.addr = 0x15; + info.platform_data = &tc90522_config; + request_module("tc90522"); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_demod = client; + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + /* attach tuner */ + memset(&qm1d1c0042_config, 0, + sizeof(qm1d1c0042_config)); + qm1d1c0042_config.fe = tc90522_config.fe; + qm1d1c0042_config.lpf = 1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); + info.addr = 0x61; + info.platform_data = &qm1d1c0042_config; + request_module(info.type); + client = i2c_new_device(tc90522_config.tuner_i2c, + &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_tuner = client; + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + dvb->fe[0] = tc90522_config.fe; + px_bcud_init(dev); + result = 0; +out_free: + return result; +} + +static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + int result; + + /* attach demod */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + if (dev->ts == PRIMARY_TS) + info.addr = 0x64; + else + info.addr = 0x67; + info.platform_data = &si2168_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + if (dev->ts == PRIMARY_TS) + info.addr = 0x60; + else + info.addr = 0x63; + info.platform_data = &si2157_config; + request_module(info.type); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + result = 0; +out_free: + return result; +} + +static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev) +{ + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info = {}; + struct lgdt3306a_config lgdt3306a_config; + struct si2157_config si2157_config = {}; + int result; + + /* attach demod */ + lgdt3306a_config = hauppauge_01595_lgdt3306a_config; + lgdt3306a_config.fe = &dvb->fe[0]; + lgdt3306a_config.i2c_adapter = &adapter; + strlcpy(info.type, "lgdt3306a", sizeof(info.type)); + if (dev->ts == PRIMARY_TS) + info.addr = 0x59; + else + info.addr = 0x0e; + info.platform_data = &lgdt3306a_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], + &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + si2157_config.fe = dvb->fe[0]; + si2157_config.if_port = 1; + si2157_config.inversion = 1; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", sizeof(info.type)); + if (dev->ts == PRIMARY_TS) + info.addr = 0x60; + else + info.addr = 0x62; + info.platform_data = &si2157_config; + request_module(info.type); + + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + result = 0; +out_free: + return result; +} static int em28xx_dvb_init(struct em28xx *dev) { int result = 0, dvb_alt = 0; @@ -1426,60 +1924,11 @@ static int em28xx_dvb_init(struct em28xx *dev) &dev->i2c_adap[dev->def_i2c_bus], &c3tech_duo_tda18271_config); break; - case EM28174_BOARD_PCTV_460E: { - struct i2c_client *client; - struct i2c_board_info board_info; - struct tda10071_platform_data tda10071_pdata = {}; - struct a8293_platform_data a8293_pdata = {}; - - /* attach demod + tuner combo */ - tda10071_pdata.clk = 40444000, /* 40.444 MHz */ - tda10071_pdata.i2c_wr_max = 64, - tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, - tda10071_pdata.pll_multiplier = 20, - tda10071_pdata.tuner_i2c_addr = 0x14, - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); - board_info.addr = 0x55; - board_info.platform_data = &tda10071_pdata; - request_module("tda10071"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; + case EM28174_BOARD_PCTV_460E: + result = em28174_dvb_init_pctv_460e(dev); + if (result) goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client); - dvb->i2c_client_demod = client; - - /* attach SEC */ - a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_sec = client; break; - } case EM2874_BOARD_DELOCK_61959: case EM2874_BOARD_MAXMEDIA_UB425_TC: /* attach demodulator */ @@ -1626,415 +2075,35 @@ static int em28xx_dvb_init(struct em28xx *dev) } } break; - case EM28178_BOARD_PCTV_461E: { - struct i2c_client *client; - struct i2c_adapter *i2c_adapter; - struct i2c_board_info board_info; - struct m88ds3103_platform_data m88ds3103_pdata = {}; - struct ts2020_config ts2020_config = {}; - struct a8293_platform_data a8293_pdata = {}; - - /* attach demod */ - m88ds3103_pdata.clk = 27000000; - m88ds3103_pdata.i2c_wr_max = 33; - m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; - m88ds3103_pdata.ts_clk = 16000; - m88ds3103_pdata.ts_clk_pol = 1; - m88ds3103_pdata.agc = 0x99; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); - board_info.addr = 0x68; - board_info.platform_data = &m88ds3103_pdata; - request_module("m88ds3103"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; + case EM28178_BOARD_PCTV_461E: + result = em28178_dvb_init_pctv_461e(dev); + if (result) goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client); - i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client); - dvb->i2c_client_demod = client; - - /* attach tuner */ - ts2020_config.fe = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); - board_info.addr = 0x60; - board_info.platform_data = &ts2020_config; - request_module("ts2020"); - client = i2c_new_device(i2c_adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_tuner = client; - /* delegate signal strength measurement to tuner */ - dvb->fe[0]->ops.read_signal_strength = - dvb->fe[0]->ops.tuner_ops.get_rf_strength; - - /* attach SEC */ - a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_sec = client; break; - } case EM28178_BOARD_PCTV_292E: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; - } + result = em28178_dvb_init_pctv_292e(dev); + if (result) + goto out_free; break; case EM28178_BOARD_TERRATEC_T2_STICK_HD: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 0; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2146", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - } + result = em28178_dvb_init_terratec_t2_stick_hd(dev); + if (result) + goto out_free; break; - case EM28178_BOARD_PLEX_PX_BCUD: - { - struct i2c_client *client; - struct i2c_board_info info; - struct tc90522_config tc90522_config; - struct qm1d1c0042_config qm1d1c0042_config; - - /* attach demod */ - memset(&tc90522_config, 0, sizeof(tc90522_config)); - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); - info.addr = 0x15; - info.platform_data = &tc90522_config; - request_module("tc90522"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_demod = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - /* attach tuner */ - memset(&qm1d1c0042_config, 0, - sizeof(qm1d1c0042_config)); - qm1d1c0042_config.fe = tc90522_config.fe; - qm1d1c0042_config.lpf = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); - info.addr = 0x61; - info.platform_data = &qm1d1c0042_config; - request_module(info.type); - client = i2c_new_device(tc90522_config.tuner_i2c, - &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_tuner = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = tc90522_config.fe; - px_bcud_init(dev); - } + result = em28178_dvb_init_plex_px_bcud(dev); + if (result) + goto out_free; break; case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &dvb->fe[0]; - si2168_config.ts_mode = SI2168_TS_SERIAL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - if (dev->ts == PRIMARY_TS) - info.addr = 0x64; - else - info.addr = 0x67; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - if (dev->ts == PRIMARY_TS) - info.addr = 0x60; - else - info.addr = 0x63; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - - } + result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev); + if (result) + goto out_free; break; case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595: - { - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info = {}; - struct lgdt3306a_config lgdt3306a_config; - struct si2157_config si2157_config = {}; - - /* attach demod */ - lgdt3306a_config = hauppauge_01595_lgdt3306a_config; - lgdt3306a_config.fe = &dvb->fe[0]; - lgdt3306a_config.i2c_adapter = &adapter; - strlcpy(info.type, "lgdt3306a", sizeof(info.type)); - if (dev->ts == PRIMARY_TS) - info.addr = 0x59; - else - info.addr = 0x0e; - info.platform_data = &lgdt3306a_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], - &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; - - /* attach tuner */ - si2157_config.fe = dvb->fe[0]; - si2157_config.if_port = 1; - si2157_config.inversion = 1; -#ifdef CONFIG_MEDIA_CONTROLLER_DVB - si2157_config.mdev = dev->media_dev; -#endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", sizeof(info.type)); - if (dev->ts == PRIMARY_TS) - info.addr = 0x60; - else - info.addr = 0x62; - info.platform_data = &si2157_config; - request_module(info.type); - - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_tuner = client; - } + result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev); + if (result) + goto out_free; break; default: dev_err(&dev->intf->dev, -- cgit From 8f569c0b4e6b6bd5db1d09551b2df87d912f124e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 2 Mar 2018 10:21:16 -0500 Subject: media: dvb-core: add helper functions for I2C binding The dvb_attach()/dvb_detach() methods are ugly hacks designed to keep using the I2C low-level API. The proper way is to do I2C bus bindings instead. Several modules were already converted to use it. Yet, it is painful to use it, as lots of code need to be duplicated. Make it easier by providing two new helper functions: - dvb_module_probe() - dvb_module_release() Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 60e9c2ba26be..a840133feacb 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -941,6 +942,53 @@ out: return err; } +#ifdef CONFIG_I2C +struct i2c_client *dvb_module_probe(const char *module_name, + const char *name, + struct i2c_adapter *adap, + unsigned char addr, + void *platform_data) +{ + struct i2c_client *client; + struct i2c_board_info *board_info; + + board_info = kzalloc(sizeof(*board_info), GFP_KERNEL); + + if (name) + strlcpy(board_info->type, name, I2C_NAME_SIZE); + else + strlcpy(board_info->type, module_name, I2C_NAME_SIZE); + + board_info->addr = addr; + board_info->platform_data = platform_data; + request_module(module_name); + client = i2c_new_device(adap, board_info); + if (client == NULL || client->dev.driver == NULL) { + kfree(board_info); + return NULL; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + client = NULL; + } + + kfree(board_info); + return client; +} +EXPORT_SYMBOL_GPL(dvb_module_probe); + +void dvb_module_release(struct i2c_client *client) +{ + if (!client) + return; + + module_put(client->dev.driver->owner); + i2c_unregister_device(client); +} +EXPORT_SYMBOL_GPL(dvb_module_release); +#endif + static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct dvb_device *dvbdev = dev_get_drvdata(dev); -- cgit From ad32495b1513fe8cbab717411b9cd8d2d285de30 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 2 Mar 2018 09:23:04 -0500 Subject: media: em28xx-dvb: simplify DVB module probing logic The module probing logic there is a way more complex than it should be, and requires some special magic to avoid stack overflows when KASAN is enabled. Solve it by creating ancillary functions to setup the platform data and request module. Now, the probing functions are cleaner and easier to understand. As a side effect, the size of the module was reduced by about 9.7% on x86_64: Before this patch: text data bss dec hex filename 51090 14192 96 65378 ff62 drivers/media/usb/em28xx/em28xx-dvb.o After this patch: text data bss dec hex filename 44743 14192 96 59031 e697 drivers/media/usb/em28xx/em28xx-dvb.o Tested with a PCTV 461e device. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 546 +++++++++------------------------- 1 file changed, 145 insertions(+), 401 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index ea921da43ea6..8b6eeb5c1f77 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1124,76 +1124,48 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) dvb_unregister_adapter(&dvb->adapter); } -static noinline_for_stack int em28174_dvb_init_pctv_460e(struct em28xx *dev) +static int em28174_dvb_init_pctv_460e(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; - struct i2c_client *client; - struct i2c_board_info board_info; struct tda10071_platform_data tda10071_pdata = {}; struct a8293_platform_data a8293_pdata = {}; - int result; /* attach demod + tuner combo */ - tda10071_pdata.clk = 40444000, /* 40.444 MHz */ - tda10071_pdata.i2c_wr_max = 64, - tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, - tda10071_pdata.pll_multiplier = 20, - tda10071_pdata.tuner_i2c_addr = 0x14, - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); - board_info.addr = 0x55; - board_info.platform_data = &tda10071_pdata; - request_module("tda10071"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client); - dvb->i2c_client_demod = client; + tda10071_pdata.clk = 40444000; /* 40.444 MHz */ + tda10071_pdata.i2c_wr_max = 64; + tda10071_pdata.ts_mode = TDA10071_TS_SERIAL; + tda10071_pdata.pll_multiplier = 20; + tda10071_pdata.tuner_i2c_addr = 0x14; + + dvb->i2c_client_demod = dvb_module_probe("tda10071", "tda10071_cx24118", + &dev->i2c_adap[dev->def_i2c_bus], + 0x55, &tda10071_pdata); + if (!dvb->i2c_client_demod) + return -ENODEV; + + dvb->fe[0] = tda10071_pdata.get_dvb_frontend(dvb->i2c_client_demod); /* attach SEC */ a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + + dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x08, &a8293_pdata); + if (!dvb->i2c_client_sec) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_sec = client; - result = 0; -out_free: - return result; + + return 0; } -static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev) +static int em28178_dvb_init_pctv_461e(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; - struct i2c_client *client; struct i2c_adapter *i2c_adapter; - struct i2c_board_info board_info; struct m88ds3103_platform_data m88ds3103_pdata = {}; struct ts2020_config ts2020_config = {}; struct a8293_platform_data a8293_pdata = {}; - int result; /* attach demod */ m88ds3103_pdata.clk = 27000000; @@ -1202,184 +1174,98 @@ static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev) m88ds3103_pdata.ts_clk = 16000; m88ds3103_pdata.ts_clk_pol = 1; m88ds3103_pdata.agc = 0x99; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); - board_info.addr = 0x68; - board_info.platform_data = &m88ds3103_pdata; - request_module("m88ds3103"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client); - i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client); - dvb->i2c_client_demod = client; + + dvb->i2c_client_demod = dvb_module_probe("m88ds3103", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x68, &m88ds3103_pdata); + if (!dvb->i2c_client_demod) + return -ENODEV; + + dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod); + i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod); /* attach tuner */ ts2020_config.fe = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); - board_info.addr = 0x60; - board_info.platform_data = &ts2020_config; - request_module("ts2020"); - client = i2c_new_device(i2c_adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + + dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022", + i2c_adapter, + 0x60, &ts2020_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_tuner = client; + /* delegate signal strength measurement to tuner */ dvb->fe[0]->ops.read_signal_strength = dvb->fe[0]->ops.tuner_ops.get_rf_strength; /* attach SEC */ a8293_pdata.dvb_frontend = dvb->fe[0]; - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); - board_info.addr = 0x08; - board_info.platform_data = &a8293_pdata; - request_module("a8293"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_tuner->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_tuner); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x08, &a8293_pdata); + if (!dvb->i2c_client_sec) { + dvb_module_release(dvb->i2c_client_tuner); + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_sec = client; - result = 0; -out_free: - return result; + + return 0; } -static noinline_for_stack int em28178_dvb_init_pctv_292e(struct em28xx *dev) +static int em28178_dvb_init_pctv_292e(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - int result; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x64, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dvb->fe[0]; si2157_config.if_port = 1; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - - dvb->i2c_client_tuner = client; dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; - result = 0; -out_free: - return result; + + return 0; } -static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev) +static int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - int result; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + 0x64, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); @@ -1388,130 +1274,67 @@ static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28x #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2146", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + dvb->i2c_client_tuner = dvb_module_probe("si2157", "si2146", + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_tuner = client; - result = 0; -out_free: - return result; + return 0; } -static noinline_for_stack int em28178_dvb_init_plex_px_bcud(struct em28xx *dev) +static int em28178_dvb_init_plex_px_bcud(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; - struct i2c_client *client; - struct i2c_board_info info; - struct tc90522_config tc90522_config; - struct qm1d1c0042_config qm1d1c0042_config; - int result; + struct tc90522_config tc90522_config = {}; + struct qm1d1c0042_config qm1d1c0042_config = {}; /* attach demod */ - memset(&tc90522_config, 0, sizeof(tc90522_config)); - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); - info.addr = 0x15; - info.platform_data = &tc90522_config; - request_module("tc90522"); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_demod = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } + dvb->i2c_client_demod = dvb_module_probe("tc90522", "tc90522sat", + &dev->i2c_adap[dev->def_i2c_bus], + 0x15, &tc90522_config); + if (!dvb->i2c_client_demod) + return -ENODEV; /* attach tuner */ - memset(&qm1d1c0042_config, 0, - sizeof(qm1d1c0042_config)); qm1d1c0042_config.fe = tc90522_config.fe; qm1d1c0042_config.lpf = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE); - info.addr = 0x61; - info.platform_data = &qm1d1c0042_config; - request_module(info.type); - client = i2c_new_device(tc90522_config.tuner_i2c, - &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dvb->i2c_client_tuner = client; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + + dvb->i2c_client_tuner = dvb_module_probe("qm1d1c0042", NULL, + tc90522_config.tuner_i2c, + 0x61, &qm1d1c0042_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } + dvb->fe[0] = tc90522_config.fe; px_bcud_init(dev); - result = 0; -out_free: - return result; + + return 0; } -static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev) +static int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - int result; + struct si2168_config si2168_config = {}; + struct si2157_config si2157_config = {}; + unsigned char addr; /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; si2168_config.ts_mode = SI2168_TS_SERIAL; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - if (dev->ts == PRIMARY_TS) - info.addr = 0x64; - else - info.addr = 0x67; - info.platform_data = &si2168_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } + addr = (dev->ts == PRIMARY_TS) ? 0x64 : 0x67; - dvb->i2c_client_demod = client; + dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + addr, &si2168_config); + if (!dvb->i2c_client_demod) + return -ENODEV; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); @@ -1520,71 +1343,38 @@ static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - if (dev->ts == PRIMARY_TS) - info.addr = 0x60; - else - info.addr = 0x63; - info.platform_data = &si2157_config; - request_module(info.type); - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } + addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x63; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + addr, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_tuner = client; - result = 0; -out_free: - return result; + return 0; } static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev) { struct em28xx_dvb *dvb = dev->dvb; struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info = {}; - struct lgdt3306a_config lgdt3306a_config; + struct lgdt3306a_config lgdt3306a_config = {}; struct si2157_config si2157_config = {}; - int result; + unsigned char addr; /* attach demod */ lgdt3306a_config = hauppauge_01595_lgdt3306a_config; lgdt3306a_config.fe = &dvb->fe[0]; lgdt3306a_config.i2c_adapter = &adapter; - strlcpy(info.type, "lgdt3306a", sizeof(info.type)); - if (dev->ts == PRIMARY_TS) - info.addr = 0x59; - else - info.addr = 0x0e; - info.platform_data = &lgdt3306a_config; - request_module(info.type); - client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], - &info); - if (client == NULL || client->dev.driver == NULL) { - result = -ENODEV; - goto out_free; - } + addr = (dev->ts == PRIMARY_TS) ? 0x59 : 0x0e; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; + dvb->i2c_client_demod = dvb_module_probe("lgdt3306a", NULL, + &dev->i2c_adap[dev->def_i2c_bus], + addr, &lgdt3306a_config); + if (!dvb->i2c_client_demod) + return -ENODEV; /* attach tuner */ si2157_config.fe = dvb->fe[0]; @@ -1593,35 +1383,19 @@ static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2157", sizeof(info.type)); - if (dev->ts == PRIMARY_TS) - info.addr = 0x60; - else - info.addr = 0x62; - info.platform_data = &si2157_config; - request_module(info.type); - - client = i2c_new_device(adapter, &info); - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; + addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x62; + + dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL, + adapter, + 0x60, &si2157_config); + if (!dvb->i2c_client_tuner) { + dvb_module_release(dvb->i2c_client_demod); + return -ENODEV; } - dvb->i2c_client_tuner = client; - result = 0; -out_free: - return result; + return 0; } + static int em28xx_dvb_init(struct em28xx *dev) { int result = 0, dvb_alt = 0; @@ -1857,7 +1631,7 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: { - struct xc5000_config cfg; + struct xc5000_config cfg = {}; hauppauge_hvr930c_init(dev); @@ -1874,7 +1648,6 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; /* Attach xc5000 */ - memset(&cfg, 0, sizeof(cfg)); cfg.i2c_address = 0x61; cfg.if_khz = 4000; @@ -2027,13 +1800,7 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2874_BOARD_KWORLD_UB435Q_V3: { - struct i2c_client *client; struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus]; - struct i2c_board_info board_info = { - .type = "tda18212", - .addr = 0x60, - .platform_data = &kworld_ub435q_v3_config, - }; dvb->fe[0] = dvb_attach(lgdt3305_attach, &em2874_lgdt3305_nogate_dev, @@ -2045,22 +1812,16 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach tuner */ kworld_ub435q_v3_config.fe = dvb->fe[0]; - request_module("tda18212"); - client = i2c_new_device(adapter, &board_info); - if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dvb->fe[0]); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL, + adapter, + 0x60, + &kworld_ub435q_v3_config); + if (!dvb->i2c_client_tuner) { dvb_frontend_detach(dvb->fe[0]); result = -ENODEV; goto out_free; } - - dvb->i2c_client_tuner = client; break; } case EM2874_BOARD_PCTV_HD_MINI_80E: @@ -2159,7 +1920,6 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops) static int em28xx_dvb_fini(struct em28xx *dev) { struct em28xx_dvb *dvb; - struct i2c_client *client; if (dev->is_audio_only) { /* Shouldn't initialize IR for this interface */ @@ -2195,26 +1955,10 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_unregister_dvb(dvb); - /* remove I2C SEC */ - client = dvb->i2c_client_sec; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - /* remove I2C tuner */ - client = dvb->i2c_client_tuner; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - /* remove I2C demod */ - client = dvb->i2c_client_demod; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + /* release I2C module bindings */ + dvb_module_release(dvb->i2c_client_sec); + dvb_module_release(dvb->i2c_client_tuner); + dvb_module_release(dvb->i2c_client_demod); kfree(dvb); dev->dvb = NULL; -- cgit From ad05ff091f004b621da1bb17f66181ef0ef4da0c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 09:53:32 -0500 Subject: media: s5h14*.h: fix typos for CONTINUOUS There is a typo at the several s5h14*.h headers: continuous were spelled incorrectly. Fix it with this script: for i in $(git grep -l S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK); do sed s,S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,g -i $i done for i in $(git grep -l -i continous drivers/media); do sed s,CONTINOUS,CONTINUOUS,g -i $i; done Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/s5h1409.c | 8 ++++---- drivers/media/dvb-frontends/s5h1409.h | 8 ++++---- drivers/media/dvb-frontends/s5h1411.c | 8 ++++---- drivers/media/dvb-frontends/s5h1411.h | 8 ++++---- drivers/media/dvb-frontends/s5h1432.h | 8 ++++---- drivers/media/pci/cx18/cx18-dvb.c | 4 ++-- drivers/media/pci/cx23885/cx23885-dvb.c | 16 ++++++++-------- drivers/media/pci/cx88/cx88-dvb.c | 8 ++++---- drivers/media/pci/saa7134/saa7134-dvb.c | 2 +- drivers/media/pci/saa7164/saa7164-dvb.c | 2 +- drivers/media/usb/cx231xx/cx231xx-dvb.c | 6 +++--- drivers/media/usb/dvb-usb/dib0700_devices.c | 2 +- drivers/media/usb/em28xx/em28xx-dvb.c | 2 +- 13 files changed, 41 insertions(+), 41 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index aced6a956ec5..a23ba8727218 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -682,17 +682,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) val = s5h1409_readreg(state, 0xac) & 0xcfff; switch (mode) { - case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK: val |= 0x0000; break; - case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK: dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); val |= 0x1000; break; - case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK: val |= 0x2000; break; - case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK: val |= 0x3000; break; default: diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index b38557c451b9..87de58ffc822 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -52,10 +52,10 @@ struct s5h1409_config { u8 status_mode; /* MPEG signal timing */ -#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* HVR-1600 optimizations (to better work with MXL5005s) diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index c4b1e9725f3e..af5962807f2c 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -433,17 +433,17 @@ static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode) val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff; switch (mode) { - case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK: val |= 0x0000; break; - case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK: dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); val |= 0x1000; break; - case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK: val |= 0x2000; break; - case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK: val |= 0x3000; break; default: diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index 791bab0e16e9..850ee713d64c 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -40,10 +40,10 @@ struct s5h1411_config { u8 gpio; /* MPEG signal timing */ -#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* IF Freq for QAM and VSB in KHz */ diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h index af3a157b5e77..646dda36262b 100644 --- a/drivers/media/dvb-frontends/s5h1432.h +++ b/drivers/media/dvb-frontends/s5h1432.h @@ -42,10 +42,10 @@ struct s5h1432_config { u8 gpio; /* MPEG signal timing */ -#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 +#define S5H1432_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0 +#define S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1 +#define S5H1432_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2 +#define S5H1432_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3 u16 mpeg_timing; /* IF Freq for QAM and VSB in KHz */ diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c index 53f4d6bf81fb..010f39eafce1 100644 --- a/drivers/media/pci/cx18/cx18-dvb.c +++ b/drivers/media/pci/cx18/cx18-dvb.c @@ -72,7 +72,7 @@ static struct s5h1409_config hauppauge_hvr1600_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE }; @@ -86,7 +86,7 @@ static struct s5h1411_config hcw_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda18271_std_map hauppauge_tda18271_std_map = { diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 700422b538c0..6061e36d76b1 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -193,7 +193,7 @@ static struct s5h1409_config hauppauge_generic_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda10048_config hauppauge_hvr1200_config = { @@ -225,7 +225,7 @@ static struct s5h1409_config hauppauge_ezqam_config = { .qam_if = 4000, .inversion = S5H1409_INVERSION_ON, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1800lp_config = { @@ -235,7 +235,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1500_config = { @@ -244,7 +244,7 @@ static struct s5h1409_config hauppauge_hvr1500_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -264,7 +264,7 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config dvico_s5h1409_config = { @@ -274,7 +274,7 @@ static struct s5h1409_config dvico_s5h1409_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config dvico_s5h1411_config = { @@ -284,7 +284,7 @@ static struct s5h1411_config dvico_s5h1411_config = { .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config hcw_s5h1411_config = { @@ -294,7 +294,7 @@ static struct s5h1411_config hcw_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 49a335f4603e..ec65eca713f9 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -558,7 +558,7 @@ static const struct s5h1409_config pinnacle_pctv_hd_800i_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK, }; static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { @@ -567,7 +567,7 @@ static const struct s5h1409_config dvico_hdtv5_pci_nano_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static const struct s5h1409_config kworld_atsc_120_config = { @@ -576,7 +576,7 @@ static const struct s5h1409_config kworld_atsc_120_config = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { @@ -599,7 +599,7 @@ static const struct zl10353_config cx88_geniatech_x8000_mt = { static const struct s5h1411_config dvico_fusionhdtv7_config = { .output_mode = S5H1411_SERIAL_OUTPUT, .gpio = S5H1411_GPIO_ON, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, .qam_if = S5H1411_IF_44000, .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index a7a63d608dde..3025d38ddb2b 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1195,7 +1195,7 @@ static struct s5h1411_config kworld_s5h1411_config = { .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, .mpeg_timing = - S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index e76d3bafe2ce..4f9f03c3b252 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -78,7 +78,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = { .vsb_if = S5H1411_IF_3250, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct lgdt3306a_config hauppauge_hvr2255a_config = { diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index fb5654062b1a..4ec7da07c8d7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -79,7 +79,7 @@ static struct s5h1432_config dvico_s5h1432_config = { .vsb_if = S5H1432_IF_4000, .inversion = S5H1432_INVERSION_OFF, .status_mode = S5H1432_DEMODLOCKING, - .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { @@ -108,7 +108,7 @@ static struct s5h1411_config tda18271_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config xc5000_s5h1411_config = { .output_mode = S5H1411_SERIAL_OUTPUT, @@ -117,7 +117,7 @@ static struct s5h1411_config xc5000_s5h1411_config = { .qam_if = S5H1411_IF_3250, .inversion = S5H1411_INVERSION_OFF, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct lgdt3305_config hcw_lgdt3305_config = { diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 3d99e141d566..c53a969bc6be 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -3412,7 +3412,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) static struct s5h1411_config pinnacle_801e_config = { .output_mode = S5H1411_PARALLEL_OUTPUT, .gpio = S5H1411_GPIO_OFF, - .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK, .qam_if = S5H1411_IF_44000, .vsb_if = S5H1411_IF_44000, .inversion = S5H1411_INVERSION_OFF, diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 8b6eeb5c1f77..05d0abdb8758 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -356,7 +356,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK + .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK }; static struct tda18271_std_map kworld_a340_std_map = { -- cgit From fe8d54f0e9aa12e2f032dadc2c6df87a0c3b57be Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 09:49:42 -0500 Subject: media: em28xx-dvb: do some coding style improvements As we're touching a lot on this file, let's solve several Coding Style issues there using checkpatch --fix-inline --strict, and manually adjusting the results. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 181 ++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 84 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 05d0abdb8758..d553c29ee356 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -96,7 +96,7 @@ struct em28xx_dvb { struct dvb_net net; /* Due to DRX-K - probably need changes */ - int (*gate_ctrl)(struct dvb_frontend *, int); + int (*gate_ctrl)(struct dvb_frontend *fe, int gate); struct semaphore pll_mutex; bool dont_attach_fe1; int lna_gpio; @@ -276,14 +276,13 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed) mutex_lock(&dvb->lock); dvb->nfeeds--; - if (0 == dvb->nfeeds) + if (!dvb->nfeeds) err = em28xx_stop_streaming(dvb); mutex_unlock(&dvb->lock); return err; } - /* ------------------------------------------------------------------ */ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { @@ -512,14 +511,15 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) em28xx_gpio_set(dev, hauppauge_hvr930c_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, hauppauge_hvr930c_end); msleep(100); @@ -528,8 +528,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) msleep(30); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); - msleep(10); - + usleep_range(10000, 11000); } static void terratec_h5_init(struct em28xx *dev) @@ -569,14 +568,15 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_h5_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_h5_end); }; @@ -622,14 +622,15 @@ static void terratec_htc_stick_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_htc_stick_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_stick_end); }; @@ -680,14 +681,15 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_htc_usb_xs_init); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); - msleep(10); + usleep_range(10000, 11000); dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_usb_xs_end); }; @@ -716,7 +718,8 @@ static void pctv_520e_init(struct em28xx *dev) dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */ for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + regs[i].r, regs[i].len); }; static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) @@ -778,7 +781,7 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) static u8 tuner_go[] = { TUNER_GO, 0x01}; mt352_write(fe, clock_config, sizeof(clock_config)); - udelay(200); + usleep_range(200, 250); mt352_write(fe, reset, sizeof(reset)); mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); mt352_write(fe, agc_cfg, sizeof(agc_cfg)); @@ -838,8 +841,8 @@ static void px_bcud_init(struct em28xx *dev) /* sleeping ISDB-T */ dev->dvb->i2c_client_demod->addr = 0x14; for (i = 0; i < ARRAY_SIZE(regs1); i++) - i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r, - regs1[i].len); + i2c_master_send(dev->dvb->i2c_client_demod, + regs1[i].r, regs1[i].len); /* sleeping ISDB-S */ dev->dvb->i2c_client_demod->addr = 0x15; for (i = 0; i < ARRAY_SIZE(regs2); i++) @@ -1075,7 +1078,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); /* If the analog part won't create RF connectors, DVB will do it */ - if (!dev->has_video || (dev->tuner_type == TUNER_ABSENT)) + if (!dev->has_video || dev->tuner_type == TUNER_ABSENT) create_rf_connector = true; result = dvb_create_media_graph(&dvb->adapter, create_rf_connector); @@ -1188,8 +1191,8 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev) ts2020_config.fe = dvb->fe[0]; dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022", - i2c_adapter, - 0x60, &ts2020_config); + i2c_adapter, + 0x60, &ts2020_config); if (!dvb->i2c_client_tuner) { dvb_module_release(dvb->i2c_client_demod); return -ENODEV; @@ -1202,8 +1205,8 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev) /* attach SEC */ a8293_pdata.dvb_frontend = dvb->fe[0]; dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, - &dev->i2c_adap[dev->def_i2c_bus], - 0x08, &a8293_pdata); + &dev->i2c_adap[dev->def_i2c_bus], + 0x08, &a8293_pdata); if (!dvb->i2c_client_sec) { dvb_module_release(dvb->i2c_client_tuner); dvb_module_release(dvb->i2c_client_demod); @@ -1414,12 +1417,13 @@ static int em28xx_dvb_init(struct em28xx *dev) dev_info(&dev->intf->dev, "Binding DVB extension\n"); - dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); + dvb = kzalloc(sizeof(*dvb), GFP_KERNEL); if (!dvb) return -ENOMEM; dev->dvb = dvb; - dvb->fe[0] = dvb->fe[1] = NULL; + dvb->fe[0] = NULL; + dvb->fe[1] = NULL; /* pre-allocate DVB usb transfer buffers */ if (dev->dvb_xfer_bulk) { @@ -1449,7 +1453,8 @@ static int em28xx_dvb_init(struct em28xx *dev) switch (dev->model) { case EM2874_BOARD_LEADERSHIP_ISDBT: dvb->fe[0] = dvb_attach(s921_attach, - &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]); + &sharp_isdbt, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; @@ -1462,8 +1467,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->fe[0] = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap[dev->def_i2c_bus]); + &em2880_lgdt3303_dev, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1471,8 +1476,8 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2880_BOARD_KWORLD_DVB_310U: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_with_xc3028, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1482,8 +1487,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2882_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1494,16 +1499,17 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2881_BOARD_PINNACLE_HYBRID_PRO: case EM2882_BOARD_DIKOM_DK300: case EM2882_BOARD_KWORLD_VS_DVBT: + /* + * Those boards could have either a zl10353 or a mt352. + * If the chip id isn't for zl10353, try mt352. + */ dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] == NULL) { - /* This board could have either a zl10353 or a mt352. - If the chip id isn't for zl10353, try mt352 */ + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap[dev->def_i2c_bus]); + if (!dvb->fe[0]) dvb->fe[0] = dvb_attach(mt352_attach, - &terratec_xs_mt352_cfg, - &dev->i2c_adap[dev->def_i2c_bus]); - } + &terratec_xs_mt352_cfg, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; @@ -1512,27 +1518,28 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2870_BOARD_TERRATEC_XS_MT2060: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_no_i2c_gate_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { dvb_attach(mt2060_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], - &em28xx_mt2060_config, 1220); + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_mt2060_config, 1220); } break; case EM2870_BOARD_KWORLD_355U: dvb->fe[0] = dvb_attach(zl10353_attach, - &em28xx_zl10353_no_i2c_gate_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) dvb_attach(qt1010_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config); + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_qt1010_config); break; case EM2883_BOARD_KWORLD_HYBRID_330U: case EM2882_BOARD_EVGA_INDTUBE: dvb->fe[0] = dvb_attach(s5h1409_attach, - &em28xx_s5h1409_with_xc3028, - &dev->i2c_adap[dev->def_i2c_bus]); + &em28xx_s5h1409_with_xc3028, + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1540,9 +1547,9 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2882_BOARD_KWORLD_ATSC_315U: dvb->fe[0] = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { + &em2880_lgdt3303_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) { @@ -1564,8 +1571,9 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2870_BOARD_REDDO_DVB_C_USB_BOX: /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ dvb->fe[0] = dvb_attach(tda10023_attach, - &em28xx_tda10023_config, - &dev->i2c_adap[dev->def_i2c_bus], 0x48); + &em28xx_tda10023_config, + &dev->i2c_adap[dev->def_i2c_bus], + 0x48); if (dvb->fe[0]) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], @@ -1577,18 +1585,18 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2870_BOARD_KWORLD_A340: dvb->fe[0] = dvb_attach(lgdt3305_attach, - &em2870_lgdt3304_dev, - &dev->i2c_adap[dev->def_i2c_bus]); + &em2870_lgdt3304_dev, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; } if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, &dev->i2c_adap[dev->def_i2c_bus], - &kworld_a340_config)) { - dvb_frontend_detach(dvb->fe[0]); - result = -EINVAL; - goto out_free; + &kworld_a340_config)) { + dvb_frontend_detach(dvb->fe[0]); + result = -EINVAL; + goto out_free; } break; case EM28174_BOARD_PCTV_290E: @@ -1606,7 +1614,6 @@ static int em28xx_dvb_init(struct em28xx *dev) 0x60, &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { - dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -1636,7 +1643,8 @@ static int em28xx_dvb_init(struct em28xx *dev) hauppauge_hvr930c_init(dev); dvb->fe[0] = dvb_attach(drxk_attach, - &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]); + &hauppauge_930c_drxk, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1653,8 +1661,8 @@ static int em28xx_dvb_init(struct em28xx *dev) if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], - &cfg)) { + if (!dvb_attach(xc5000_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], &cfg)) { result = -EINVAL; goto out_free; } @@ -1666,7 +1674,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2884_BOARD_TERRATEC_H5: terratec_h5_init(dev); - dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]); + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1680,7 +1689,8 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Attach tda18271 to DVB-C frontend */ if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { + if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { result = -EINVAL; goto out_free; } @@ -1690,9 +1700,9 @@ static int em28xx_dvb_init(struct em28xx *dev) break; case EM2884_BOARD_C3TECH_DIGITAL_DUO: dvb->fe[0] = dvb_attach(mb86a20s_attach, - &c3tech_duo_mb86a20s_config, - &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) + &c3tech_duo_mb86a20s_config, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) dvb_attach(tda18271_attach, dvb->fe[0], 0x60, &dev->i2c_adap[dev->def_i2c_bus], &c3tech_duo_tda18271_config); @@ -1706,7 +1716,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2874_BOARD_MAXMEDIA_UB425_TC: /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, - &dev->i2c_adap[dev->def_i2c_bus]); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* disable I2C-gate */ @@ -1728,7 +1738,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, - &dev->i2c_adap[dev->def_i2c_bus]); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* attach tuner */ @@ -1814,8 +1824,7 @@ static int em28xx_dvb_init(struct em28xx *dev) kworld_ub435q_v3_config.fe = dvb->fe[0]; dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL, - adapter, - 0x60, + adapter, 0x60, &kworld_ub435q_v3_config); if (!dvb->i2c_client_tuner) { dvb_frontend_detach(dvb->fe[0]); @@ -1825,9 +1834,11 @@ static int em28xx_dvb_init(struct em28xx *dev) break; } case EM2874_BOARD_PCTV_HD_MINI_80E: - dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]); - if (dvb->fe[0] != NULL) { - dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + dvb->fe[0] = dvb_attach(drx39xxj_attach, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0]) { + dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], + 0x60, &dev->i2c_adap[dev->def_i2c_bus], &pinnacle_80e_dvb_config); if (!dvb->fe[0]) { @@ -1871,7 +1882,7 @@ static int em28xx_dvb_init(struct em28xx *dev) "The frontend of your DVB/ATSC card isn't supported yet\n"); break; } - if (NULL == dvb->fe[0]) { + if (!dvb->fe[0]) { dev_err(&dev->intf->dev, "frontend initialization failed\n"); result = -EINVAL; goto out_free; @@ -1941,8 +1952,10 @@ static int em28xx_dvb_fini(struct em28xx *dev) em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); if (dev->disconnected) { - /* We cannot tell the device to sleep - * once it has been unplugged. */ + /* + * We cannot tell the device to sleep + * once it has been unplugged. + */ if (dvb->fe[0]) { prevent_sleep(&dvb->fe[0]->ops); dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED; -- cgit From f22e9e7133ab42d790604c21afc38632e616fc63 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 10:43:14 -0500 Subject: media: em28xx: Add SPDX license tags where needed Most of the files there are missing a SPDX license tag. Add. While here fix some DRIVER_LICENSE macro in order to reflect the source file license, as some of the headers are GPL v2 only. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 46 ++++++++++++++-------------- drivers/media/usb/em28xx/em28xx-camera.c | 36 ++++++++++------------ drivers/media/usb/em28xx/em28xx-cards.c | 44 ++++++++++++--------------- drivers/media/usb/em28xx/em28xx-core.c | 44 ++++++++++++--------------- drivers/media/usb/em28xx/em28xx-dvb.c | 46 ++++++++++++++-------------- drivers/media/usb/em28xx/em28xx-i2c.c | 43 ++++++++++++-------------- drivers/media/usb/em28xx/em28xx-input.c | 42 ++++++++++++-------------- drivers/media/usb/em28xx/em28xx-reg.h | 5 +++ drivers/media/usb/em28xx/em28xx-v4l.h | 27 +++++++++-------- drivers/media/usb/em28xx/em28xx-vbi.c | 39 +++++++++++------------- drivers/media/usb/em28xx/em28xx-video.c | 52 +++++++++++++++----------------- drivers/media/usb/em28xx/em28xx.h | 41 ++++++++++++------------- 12 files changed, 220 insertions(+), 245 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 4628d73f46f2..f8854b570f0d 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -1,25 +1,25 @@ -/* - * Empiatech em28x1 audio extension - * - * Copyright (C) 2006 Markus Rechberger - * - * Copyright (C) 2007-2016 Mauro Carvalho Chehab - * - Port to work with the in-kernel driver - * - Cleanups, fixes, alsa-controls, etc. - * - * This driver is based on my previous au600 usb pstn audio driver - * and inherits all the copyrights - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Empiatech em28x1 audio extension +// +// Copyright (C) 2006 Markus Rechberger +// +// Copyright (C) 2007-2016 Mauro Carvalho Chehab +// - Port to work with the in-kernel driver +// - Cleanups, fixes, alsa-controls, etc. +// +// This driver is based on my previous au600 usb pstn audio driver +// and inherits all the copyrights +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" @@ -1050,7 +1050,7 @@ static void __exit em28xx_alsa_unregister(void) em28xx_unregister_extension(&audio_ops); } -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Markus Rechberger "); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index ae87dd3e671f..f0c52da17372 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -1,23 +1,19 @@ -/* - em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices - - Copyright (C) 2009 Mauro Carvalho Chehab - Copyright (C) 2013 Frank Schäfer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices +// +// Copyright (C) 2009 Mauro Carvalho Chehab +// Copyright (C) 2013 Frank Schäfer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index fc4654f7eece..ce04b5023440 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1,27 +1,23 @@ -/* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - Copyright (C) 2012 Frank Schäfer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB +// video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon +// Markus Rechberger +// Mauro Carvalho Chehab +// Sascha Sommer +// Copyright (C) 2012 Frank Schäfer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 44a162dd4867..269649c81432 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -1,26 +1,22 @@ -/* - em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - Copyright (C) 2012 Frank Schäfer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon +// Markus Rechberger +// Mauro Carvalho Chehab +// Sascha Sommer +// Copyright (C) 2012 Frank Schäfer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" @@ -41,7 +37,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(EM28XX_VERSION); /* #define ENABLE_DEBUG_ISOC_FRAMES */ diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index d553c29ee356..9bf781f9b93f 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1,25 +1,25 @@ -/* - DVB device driver for em28xx - - (c) 2008-2011 Mauro Carvalho Chehab - - (c) 2008 Devin Heitmueller - - Fixes for the driver to properly work with HVR-950 - - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick - - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 - - (c) 2008 Aidan Thornton - - (c) 2012 Frank Schäfer - - Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: - (c) 2004, 2005 Chris Pascoe - (c) 2004 Gerd Knorr [SuSE Labs] - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// DVB device driver for em28xx +// +// (c) 2008-2011 Mauro Carvalho Chehab +// +// (c) 2008 Devin Heitmueller +// - Fixes for the driver to properly work with HVR-950 +// - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick +// - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 +// +// (c) 2008 Aidan Thornton +// +// (c) 2012 Frank Schäfer +// +// Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: +// (c) 2004, 2005 Chris Pascoe +// (c) 2004 Gerd Knorr [SuSE Labs] +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation version 2 of the License. #include "em28xx.h" @@ -64,7 +64,7 @@ #include "qm1d1c0042.h" MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface"); MODULE_VERSION(EM28XX_VERSION); diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index fc90f5a32255..50b0791a68a5 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -1,26 +1,23 @@ -/* - em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - Copyright (C) 2013 Frank Schäfer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon +// Markus Rechberger +// Mauro Carvalho Chehab +// Sascha Sommer +// Copyright (C) 2013 Frank Schäfer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 270cd68df4a2..c7afcf67ccc5 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -1,25 +1,21 @@ -/* - handle em28xx IR remotes via linux kernel input layer. - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// handle em28xx IR remotes via linux kernel input layer. +// +// Copyright (C) 2005 Ludovico Cavedon +// Markus Rechberger +// Mauro Carvalho Chehab +// Sascha Sommer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" @@ -926,7 +922,7 @@ static void __exit em28xx_rc_unregister(void) em28xx_unregister_extension(&rc_ops); } -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION(DRIVER_DESC " - input interface"); MODULE_VERSION(EM28XX_VERSION); diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 9e5cdfb25a73..26a06b1b1077 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ + +/* + * em28xx-reg.h - Register definitions for em28xx driver + */ + #define EM_GPIO_0 (1 << 0) #define EM_GPIO_1 (1 << 1) #define EM_GPIO_2 (1 << 2) diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h index 9c411aac3878..1788dbf9024a 100644 --- a/drivers/media/usb/em28xx/em28xx-v4l.h +++ b/drivers/media/usb/em28xx/em28xx-v4l.h @@ -1,17 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2013-2014 Mauro Carvalho Chehab - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB + * video capture devices + * + * Copyright (C) 2013-2014 Mauro Carvalho Chehab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index f5123651ef30..63c48361d3f2 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -1,25 +1,20 @@ -/* - em28xx-vbi.c - VBI driver for em28xx - - Copyright (C) 2009 Devin Heitmueller - - This work was sponsored by EyeMagnet Limited. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-vbi.c - VBI driver for em28xx +// +// Copyright (C) 2009 Devin Heitmueller +// +// This work was sponsored by EyeMagnet Limited. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3744c31e2a91..7649deec3c1c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1,30 +1,26 @@ -/* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon - Markus Rechberger - Mauro Carvalho Chehab - Sascha Sommer - Copyright (C) 2012 Frank Schäfer - - Some parts based on SN9C10x PC Camera Controllers GPL driver made - by Luca Risolia - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB +// video capture devices +// +// Copyright (C) 2005 Ludovico Cavedon +// Markus Rechberger +// Mauro Carvalho Chehab +// Sascha Sommer +// Copyright (C) 2012 Frank Schäfer +// +// Some parts based on SN9C10x PC Camera Controllers GPL driver made +// by Luca Risolia +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "em28xx.h" @@ -77,7 +73,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(EM28XX_VERSION); #define EM25XX_FRMDATAHDR_BYTE1 0x02 diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 0646367568ab..94fbc90d22e5 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -1,26 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* - em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Markus Rechberger - Ludovico Cavedon - Mauro Carvalho Chehab - Copyright (C) 2012 Frank Schäfer - - Based on the em2800 driver from Sascha Sommer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices + * + * Copyright (C) 2005 Markus Rechberger + * Ludovico Cavedon + * Mauro Carvalho Chehab + * Copyright (C) 2012 Frank Schäfer + * + * Based on the em2800 driver from Sascha Sommer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef _EM28XX_H -- cgit From c69ce6156341e5d24d04689dc429c419fe7c0f9d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 11:49:27 -0500 Subject: media: em28xx.h: Fix most coding style issues There used to have a lot of coding style issues there. The ones detected by checkpatch, in strict mode, got fixed. Still, we need to work more on it, in order to document all struct fields using kernel-doc macros, but this will be done on some future patch. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 310 ++++++++++++++++++++++---------------- 1 file changed, 181 insertions(+), 129 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 94fbc90d22e5..63c7c6124707 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -23,6 +23,8 @@ #ifndef _EM28XX_H #define _EM28XX_H +#include + #define EM28XX_VERSION "0.2.2" #define DRIVER_DESC "Empia em28xx device driver" @@ -177,15 +179,17 @@ /* max number of I2C buses on em28xx devices */ #define NUM_I2C_BUSES 2 -/* isoc transfers: number of packets for each buffer - windows requests only 64 packets .. so we better do the same - this is what I found out for all alternate numbers there! +/* + * isoc transfers: number of packets for each buffer + * windows requests only 64 packets .. so we better do the same + * this is what I found out for all alternate numbers there! */ #define EM28XX_NUM_ISOC_PACKETS 64 #define EM28XX_DVB_NUM_ISOC_PACKETS 64 -/* bulk transfers: transfer buffer size = packet size * packet multiplier - USB 2.0 spec says bulk packet size is always 512 bytes +/* + * bulk transfers: transfer buffer size = packet size * packet multiplier + * USB 2.0 spec says bulk packet size is always 512 bytes */ #define EM28XX_BULK_PACKET_MULTIPLIER 384 #define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94 @@ -209,64 +213,83 @@ enum em28xx_mode { struct em28xx; +/** + * struct em28xx_usb_bufs - Contains URB-related buffer data + * + * @max_pkt_size: max packet size of isoc transaction + * @num_packets: number of packets in each buffer + * @num_bufs: number of allocated urb + * @urb: urb for isoc/bulk transfers + * @buf: transfer buffers for isoc/bulk transfer + */ struct em28xx_usb_bufs { - /* max packet size of isoc transaction */ int max_pkt_size; - - /* number of packets in each buffer */ int num_packets; - - /* number of allocated urbs */ int num_bufs; - - /* urb for isoc/bulk transfers */ struct urb **urb; - - /* transfer buffers for isoc/bulk transfer */ char **buf; }; +/** + * struct em28xx_usb_ctl - Contains URB-related buffer data + * + * @analog_bufs: isoc/bulk transfer buffers for analog mode + * @digital_bufs: isoc/bulk transfer buffers for digital mode + * @vid_buf: Stores already requested video buffers + * @vbi_buf: Stores already requested VBI buffers + * @urb_data_copy: copy data from URB + */ struct em28xx_usb_ctl { - /* isoc/bulk transfer buffers for analog mode */ struct em28xx_usb_bufs analog_bufs; - - /* isoc/bulk transfer buffers for digital mode */ struct em28xx_usb_bufs digital_bufs; - - /* Stores already requested buffers */ struct em28xx_buffer *vid_buf; struct em28xx_buffer *vbi_buf; - - /* copy data from URB */ int (*urb_data_copy)(struct em28xx *dev, struct urb *urb); - }; -/* Struct to enumberate video formats */ +/** + * struct em28xx_fmt - Struct to enumberate video formats + * + * @name: Name for the video standard + * @fourcc: v4l2 format id + * @depth: mean number of bits to represent a pixel + * @reg: em28xx register value to set it + */ struct em28xx_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int reg; + char *name; + u32 fourcc; + int depth; + int reg; }; -/* buffer for one video frame */ +/** + * struct em28xx_buffer- buffer for storing one video frame + * + * @vb: common v4l buffer stuff + * @list: List to associate it with the other buffers + * @mem: pointer to the buffer, as returned by vb2_plane_vaddr() + * @length: length of the buffer, as returned by vb2_plane_size() + * @top_field: If non-zero, indicate that the buffer is the top field + * @pos: Indicate the next position of the buffer to be filled. + * @vb_buf: pointer to vmalloc memory address in vb + * + * .. note:: + * + * in interlaced mode, @pos is reset to zero at the start of each new + * field (not frame !) + */ struct em28xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head list; + struct vb2_v4l2_buffer vb; /* must be first */ + + struct list_head list; - void *mem; - unsigned int length; - int top_field; + void *mem; + unsigned int length; + int top_field; - /* counter to control buffer fill */ - unsigned int pos; - /* NOTE; in interlaced mode, this value is reset to zero at - * the start of each new field (not frame !) */ + unsigned int pos; - /* pointer to vmalloc memory address in vb */ - char *vb_buf; + char *vb_buf; }; struct em28xx_dmaqueue { @@ -308,20 +331,48 @@ enum em28xx_usb_audio_type { EM28XX_USB_AUDIO_VENDOR, }; -/* em28xx has two audio inputs: tuner and line in. - However, on most devices, an auxiliary AC97 codec device is used. - The AC97 device may have several different inputs and outputs, - depending on their model. So, it is possible to use AC97 mixer to - address more than two different entries. +/** + * em28xx_amux - describes the type of audio input used by em28xx + * + * @EM28XX_AMUX_VIDEO: + * On devices without AC97, this is the only value that it is currently + * allowed. + * On devices with AC97, it corresponds to the AC97 mixer "Video" control. + * @EM28XX_AMUX_LINE_IN: + * Only for devices with AC97. Corresponds to AC97 mixer "Line In". + * @EM28XX_AMUX_VIDEO2: + * Only for devices with AC97. It means that em28xx should use "Line In" + * And AC97 should use the "Video" mixer control. + * @EM28XX_AMUX_PHONE: + * Only for devices with AC97. Corresponds to AC97 mixer "Phone". + * @EM28XX_AMUX_MIC: + * Only for devices with AC97. Corresponds to AC97 mixer "Mic". + * @EM28XX_AMUX_CD: + * Only for devices with AC97. Corresponds to AC97 mixer "CD". + * @EM28XX_AMUX_AUX: + * Only for devices with AC97. Corresponds to AC97 mixer "Aux". + * @EM28XX_AMUX_PCM_OUT: + * Only for devices with AC97. Corresponds to AC97 mixer "PCM out". + * + * The em28xx chip itself has only two audio inputs: tuner and line in. + * On almost all devices, only the tuner input is used. + * + * However, on most devices, an auxiliary AC97 codec device is used, + * usually connected to the em28xx tuner input (except for + * @EM28XX_AMUX_LINE_IN). + * + * The AC97 device typically have several different inputs and outputs. + * The exact number and description depends on their model. + * + * It is possible to AC97 to mixer more than one different entries at the + * same time, via the alsa mux. */ enum em28xx_amux { - /* This is the only entry for em28xx tuner input */ - EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */ - - EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */ + EM28XX_AMUX_VIDEO, + EM28XX_AMUX_LINE_IN, /* Some less-common mixer setups */ - EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */ + EM28XX_AMUX_VIDEO2, EM28XX_AMUX_PHONE, EM28XX_AMUX_MIC, EM28XX_AMUX_CD, @@ -331,14 +382,14 @@ enum em28xx_amux { enum em28xx_aout { /* AC97 outputs */ - EM28XX_AOUT_MASTER = 1 << 0, - EM28XX_AOUT_LINE = 1 << 1, - EM28XX_AOUT_MONO = 1 << 2, - EM28XX_AOUT_LFE = 1 << 3, - EM28XX_AOUT_SURR = 1 << 4, + EM28XX_AOUT_MASTER = BIT(0), + EM28XX_AOUT_LINE = BIT(1), + EM28XX_AOUT_MONO = BIT(2), + EM28XX_AOUT_LFE = BIT(3), + EM28XX_AOUT_SURR = BIT(4), /* PCM IN Mixer - used by AC97_RECORD_SELECT register */ - EM28XX_AOUT_PCM_IN = 1 << 7, + EM28XX_AOUT_PCM_IN = BIT(7), /* Bits 10-8 are used to indicate the PCM IN record select */ EM28XX_AOUT_PCM_MIC_PCM = 0 << 8, @@ -425,7 +476,7 @@ struct em28xx_board { int vchannels; int tuner_type; int tuner_addr; - unsigned def_i2c_bus; /* Default I2C bus */ + unsigned int def_i2c_bus; /* Default I2C bus */ /* i2c flags */ unsigned int tda9887_conf; @@ -504,8 +555,8 @@ struct em28xx_v4l2 { /* Videobuf2 */ struct vb2_queue vb_vidq; struct vb2_queue vb_vbiq; - struct mutex vb_queue_lock; - struct mutex vb_vbi_queue_lock; + struct mutex vb_queue_lock; /* Protects vb_vidq */ + struct mutex vb_vbi_queue_lock; /* Protects vb_vbiq */ u8 vinmode; u8 vinctl; @@ -531,8 +582,8 @@ struct em28xx_v4l2 { /* Frame properties */ int width; /* current frame width */ int height; /* current frame height */ - unsigned hscale; /* horizontal scale factor (see datasheet) */ - unsigned vscale; /* vertical scale factor (see datasheet) */ + unsigned int hscale; /* horizontal scale factor (see datasheet) */ + unsigned int vscale; /* vertical scale factor (see datasheet) */ unsigned int vbi_width; unsigned int vbi_height; /* lines per field */ @@ -550,7 +601,7 @@ struct em28xx_v4l2 { struct em28xx_audio { char name[50]; - unsigned num_urb; + unsigned int num_urb; char **transfer_buffer; struct urb **urb; struct usb_device *udev; @@ -563,7 +614,7 @@ struct em28xx_audio { size_t period; int users; - spinlock_t slock; + spinlock_t slock; /* Protects struct em28xx_audio */ /* Controls streaming */ struct work_struct wq_trigger; /* trigger to start/stop audio */ @@ -581,7 +632,7 @@ enum em28xx_i2c_algo_type { struct em28xx_i2c_bus { struct em28xx *dev; - unsigned bus; + unsigned int bus; enum em28xx_i2c_algo_type algo_type; }; @@ -589,19 +640,19 @@ struct em28xx_i2c_bus { struct em28xx { struct kref ref; - /* Sub-module data */ + // Sub-module data struct em28xx_v4l2 *v4l2; struct em28xx_dvb *dvb; struct em28xx_audio adev; struct em28xx_IR *ir; - /* generic device properties */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ + // generic device properties + int model; // index in the device_data struct + int devno; // marks the number of this device enum em28xx_chip_id chip_id; - unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ - unsigned int disconnected:1; /* device has been diconnected */ + unsigned int is_em25xx:1; // em25xx/em276x/7x/8x family bridge + unsigned int disconnected:1; // device has been diconnected unsigned int has_video:1; unsigned int is_audio_only:1; unsigned int is_webcam:1; @@ -613,86 +664,87 @@ struct em28xx { struct em28xx_board board; - enum em28xx_sensor em28xx_sensor; /* camera specific */ + enum em28xx_sensor em28xx_sensor; // camera specific - /* Some older em28xx chips needs a waiting time after writing */ + // Some older em28xx chips needs a waiting time after writing unsigned int wait_after_write; struct list_head devlist; - u32 i2s_speed; /* I2S speed for audio digital stream */ + u32 i2s_speed; // I2S speed for audio digital stream struct em28xx_audio_mode audio_mode; - int tuner_type; /* type of the tuner */ + int tuner_type; // type of the tuner - /* i2c i/o */ + // i2c i/o struct i2c_adapter i2c_adap[NUM_I2C_BUSES]; struct i2c_client i2c_client[NUM_I2C_BUSES]; struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES]; unsigned char eeprom_addrwidth_16bit:1; - unsigned def_i2c_bus; /* Default I2C bus */ - unsigned cur_i2c_bus; /* Current I2C bus */ + unsigned int def_i2c_bus; // Default I2C bus + unsigned int cur_i2c_bus; // Current I2C bus struct rt_mutex i2c_bus_lock; - /* video for linux */ - unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput;/* selected audio input */ - unsigned int ctl_aoutput;/* selected audio output */ + // video for linux + unsigned int ctl_input; // selected input + unsigned int ctl_ainput;// selected audio input + unsigned int ctl_aoutput;// selected audio output int mute; int volume; - unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - - for boards with generic ID */ + unsigned long hash; // eeprom hash - for boards with generic ID + unsigned long i2c_hash; // i2c devicelist hash - + // for boards with generic ID struct work_struct request_module_wk; - /* locks */ - struct mutex lock; + // locks + struct mutex lock; /* protects em28xx struct */ struct mutex ctrl_urb_lock; /* protects urb_buf */ - /* resources in use */ + // resources in use unsigned int resources; - /* eeprom content */ + // eeprom content u8 *eedata; u16 eedata_len; - /* Isoc control struct */ + // Isoc control struct struct em28xx_dmaqueue vidq; struct em28xx_dmaqueue vbiq; struct em28xx_usb_ctl usb_ctl; - spinlock_t slock; - - /* usb transfer */ - struct usb_interface *intf; /* the usb interface */ - u8 ifnum; /* number of the assigned usb interface */ - u8 analog_ep_isoc; /* address of isoc endpoint for analog */ - u8 analog_ep_bulk; /* address of bulk endpoint for analog */ - u8 dvb_ep_isoc_ts2; /* address of isoc endpoint for DVB TS2*/ - u8 dvb_ep_bulk_ts2; /* address of bulk endpoint for DVB TS2*/ - u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ - u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */ - int alt; /* alternate setting */ - int max_pkt_size; /* max packet size of the selected ep at alt */ - int packet_multiplier; /* multiplier for wMaxPacketSize, used for - URB buffer size definition */ - int num_alt; /* number of alternative settings */ - unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */ - unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc - transfers for analog */ - int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */ - unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the - selected DVB ep at dvb_alt */ - unsigned int dvb_max_pkt_size_isoc_ts2; /* isoc max packet size of the - selected DVB ep at dvb_alt */ - unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc - transfers for DVB */ - char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ - - /* helper funcs that call usb_control_msg */ + + spinlock_t slock; /* Protects em28xx video/vbi/dvb IRQ stream data */ + + // usb transfer + struct usb_interface *intf; // the usb interface + u8 ifnum; // number of the assigned usb interface + u8 analog_ep_isoc; // address of isoc endpoint for analog + u8 analog_ep_bulk; // address of bulk endpoint for analog + u8 dvb_ep_isoc_ts2; // address of isoc endpoint for DVB TS2 + u8 dvb_ep_bulk_ts2; // address of bulk endpoint for DVB TS2 + u8 dvb_ep_isoc; // address of isoc endpoint for DVB + u8 dvb_ep_bulk; // address of bulk endpoint for DVB + int alt; // alternate setting + int max_pkt_size; // max packet size of the selected ep at alt + int packet_multiplier; // multiplier for wMaxPacketSize, used for + // URB buffer size definition + int num_alt; // number of alternative settings + unsigned int *alt_max_pkt_size_isoc; // array of isoc wMaxPacketSize + unsigned int analog_xfer_bulk:1; // use bulk instead of isoc + // transfers for analog + int dvb_alt_isoc; // alternate setting for DVB isoc transfers + unsigned int dvb_max_pkt_size_isoc; // isoc max packet size of the + // selected DVB ep at dvb_alt + unsigned int dvb_max_pkt_size_isoc_ts2; // isoc max packet size of the + // selected DVB ep at dvb_alt + unsigned int dvb_xfer_bulk:1; // use bulk instead of isoc + // transfers for DVB + char urb_buf[URB_MAX_CTRL_SIZE]; // urb control msg buffer + + // helper funcs that call usb_control_msg int (*em28xx_write_regs)(struct em28xx *dev, u16 reg, char *buf, int len); int (*em28xx_read_reg)(struct em28xx *dev, u16 reg); @@ -704,14 +756,14 @@ struct em28xx { enum em28xx_mode mode; - /* Button state polling */ + // Button state polling struct delayed_work buttons_query_work; u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; u8 num_button_polling_addresses; - u16 button_polling_interval; /* [ms] */ - /* Snapshot button input device */ - char snapshot_button_path[30]; /* path of the input dev */ + u16 button_polling_interval; // [ms] + // Snapshot button input device + char snapshot_button_path[30]; // path of the input dev struct input_dev *sbutton_input_dev; #ifdef CONFIG_MEDIA_CONTROLLER @@ -730,17 +782,17 @@ struct em28xx_ops { struct list_head next; char *name; int id; - int (*init)(struct em28xx *); - int (*fini)(struct em28xx *); - int (*suspend)(struct em28xx *); - int (*resume)(struct em28xx *); + int (*init)(struct em28xx *dev); + int (*fini)(struct em28xx *dev); + int (*suspend)(struct em28xx *dev); + int (*resume)(struct em28xx *dev); }; /* Provided by em28xx-i2c.c */ -void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus); -int em28xx_i2c_register(struct em28xx *dev, unsigned bus, +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus); +int em28xx_i2c_register(struct em28xx *dev, unsigned int bus, enum em28xx_i2c_algo_type algo_type); -int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus); +int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus); /* Provided by em28xx-core.c */ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, -- cgit From 2e1e84c587d792c4ad0abfbaed22201d9aac7b72 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 11:54:19 -0500 Subject: media: em28xx-reg.h: Fix coding style issues Use BIT() macros and fix one comment that is not following the Kernel coding style. It should be noticed that the registers bit masks should be casted to unsigned char, as, otherwise, it would produce warnings like: drivers/media/usb/em28xx/em28xx-cards.c:81:33: warning: large integer implicitly truncated to unsigned type [-Woverflow] {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-reg.h | 47 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 26a06b1b1077..f53afe18e92d 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -4,19 +4,19 @@ * em28xx-reg.h - Register definitions for em28xx driver */ -#define EM_GPIO_0 (1 << 0) -#define EM_GPIO_1 (1 << 1) -#define EM_GPIO_2 (1 << 2) -#define EM_GPIO_3 (1 << 3) -#define EM_GPIO_4 (1 << 4) -#define EM_GPIO_5 (1 << 5) -#define EM_GPIO_6 (1 << 6) -#define EM_GPIO_7 (1 << 7) - -#define EM_GPO_0 (1 << 0) -#define EM_GPO_1 (1 << 1) -#define EM_GPO_2 (1 << 2) -#define EM_GPO_3 (1 << 3) +#define EM_GPIO_0 ((unsigned char)BIT(0)) +#define EM_GPIO_1 ((unsigned char)BIT(1)) +#define EM_GPIO_2 ((unsigned char)BIT(2)) +#define EM_GPIO_3 ((unsigned char)BIT(3)) +#define EM_GPIO_4 ((unsigned char)BIT(4)) +#define EM_GPIO_5 ((unsigned char)BIT(5)) +#define EM_GPIO_6 ((unsigned char)BIT(6)) +#define EM_GPIO_7 ((unsigned char)BIT(7)) + +#define EM_GPO_0 ((unsigned char)BIT(0)) +#define EM_GPO_1 ((unsigned char)BIT(1)) +#define EM_GPO_2 ((unsigned char)BIT(2)) +#define EM_GPO_3 ((unsigned char)BIT(3)) /* em28xx endpoints */ /* 0x82: (always ?) analog */ @@ -208,10 +208,11 @@ #define EM28XX_R43_AC97BUSY 0x43 #define EM28XX_R45_IR 0x45 - /* 0x45 bit 7 - parity bit - bits 6-0 - count - 0x46 IR brand - 0x47 IR data + /* + * 0x45 bit 7 - parity bit + * bits 6-0 - count + * 0x46 IR brand + * 0x47 IR data */ /* em2874 registers */ @@ -254,12 +255,12 @@ #define EM2874_IR_RC6_MODE_6A 0x0b /* em2874 Transport Stream Enable Register (0x5f) */ -#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) -#define EM2874_TS1_FILTER_ENABLE (1 << 1) -#define EM2874_TS1_NULL_DISCARD (1 << 2) -#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) -#define EM2874_TS2_FILTER_ENABLE (1 << 5) -#define EM2874_TS2_NULL_DISCARD (1 << 6) +#define EM2874_TS1_CAPTURE_ENABLE ((unsigned char)BIT(0)) +#define EM2874_TS1_FILTER_ENABLE ((unsigned char)BIT(1)) +#define EM2874_TS1_NULL_DISCARD ((unsigned char)BIT(2)) +#define EM2874_TS2_CAPTURE_ENABLE ((unsigned char)BIT(4)) +#define EM2874_TS2_FILTER_ENABLE ((unsigned char)BIT(5)) +#define EM2874_TS2_NULL_DISCARD ((unsigned char)BIT(6)) /* register settings */ #define EM2800_AUDIO_SRC_TUNER 0x0d -- cgit From 9f90f5371f52b44ff7d5251e5d54c15ab91fc3de Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 12:14:02 -0500 Subject: media: em28xx-audio: fix coding style issues There are a number of coding style issues at em28xx-audio. Fix them, by using checkpatch in strict mode to point for it. Automatic fixes with --fix-inplace were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 70 +++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index f8854b570f0d..8e799ae1df69 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -103,7 +103,7 @@ static void em28xx_audio_isocirq(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dprintk("urb completition error %d.\n", urb->status); + dprintk("urb completion error %d.\n", urb->status); break; } @@ -165,12 +165,11 @@ static void em28xx_audio_isocirq(struct urb *urb) dev_err(&dev->intf->dev, "resubmit of audio urb failed (error=%i)\n", status); - return; } static int em28xx_init_audio_isoc(struct em28xx *dev) { - int i, errCode; + int i, err; dprintk("Starting isoc transfers\n"); @@ -179,16 +178,15 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) memset(dev->adev.transfer_buffer[i], 0x80, dev->adev.urb[i]->transfer_buffer_length); - errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); - if (errCode) { + err = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); + if (err) { dev_err(&dev->intf->dev, "submit of audio urb failed (error=%i)\n", - errCode); + err); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); - return errCode; + return err; } - } return 0; @@ -268,14 +266,17 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } runtime->hw = snd_em28xx_hw_capture; if (dev->adev.users == 0) { - if (dev->alt == 0 || dev->is_audio_only) { - struct usb_device *udev = interface_to_usbdev(dev->intf); + if (!dev->alt || dev->is_audio_only) { + struct usb_device *udev; + + udev = interface_to_usbdev(dev->intf); if (dev->is_audio_only) /* audio is on a separate interface */ @@ -367,9 +368,11 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; #if 0 - /* TODO: set up em28xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ + /* + * TODO: set up em28xx audio chip to deliver the correct audio format, + * current default is 48000hz multiplexed => 96000hz mono + * which shouldn't matter since analogue TV only supports mono + */ unsigned int channels, rate, format; format = params_format(hw_params); @@ -513,8 +516,9 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -551,8 +555,9 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -586,8 +591,9 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -627,8 +633,9 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, if (nonblock) { if (!mutex_trylock(&dev->lock)) return -EAGAIN; - } else + } else { mutex_lock(&dev->lock); + } val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -762,7 +769,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (intf->num_altsetting <= alt) { dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n", - dev->ifnum, alt); + dev->ifnum, alt); return -ENODEV; } @@ -836,9 +843,8 @@ static int em28xx_audio_urb_init(struct em28xx *dev) dev->adev.transfer_buffer = kcalloc(num_urb, sizeof(*dev->adev.transfer_buffer), GFP_ATOMIC); - if (!dev->adev.transfer_buffer) { + if (!dev->adev.transfer_buffer) return -ENOMEM; - } dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC); if (!dev->adev.urb) { @@ -899,9 +905,11 @@ static int em28xx_audio_init(struct em28xx *dev) int err; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ + /* + * This device does not support the extension (in this case + * the device is expecting the snd-usb-audio module or + * doesn't have analog audio support at all) + */ return 0; } @@ -977,13 +985,15 @@ card_free: static int em28xx_audio_fini(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module or - doesn't have analog audio support at all) */ + /* + * This device does not support the extension (in this case + * the device is expecting the snd-usb-audio module or + * doesn't have analog audio support at all) + */ return 0; } @@ -1005,7 +1015,7 @@ static int em28xx_audio_fini(struct em28xx *dev) static int em28xx_audio_suspend(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) @@ -1019,7 +1029,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) static int em28xx_audio_resume(struct em28xx *dev) { - if (dev == NULL) + if (!dev) return 0; if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) -- cgit From 04964eb0eb0b6869c3d5d2a95afcc2d192094556 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 12:17:54 -0500 Subject: media: em28xx-camera: fix coding style issues There are some coding style issues at em28xx-camera. Fix them, by using checkpatch in strict mode to point for it. Automatic fixes with --fix-inplace were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index f0c52da17372..3c2694a16ed1 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -45,7 +45,7 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev) { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ { 0x0d, 0x00, 0x00, }, { 0x0a, 0x00, 0x21, }, - { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ + { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */ }; for (i = 0; i < ARRAY_SIZE(regs); i++) @@ -153,7 +153,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) break; default: dev_info(&dev->intf->dev, - "unknown Micron sensor detected: 0x%04x\n", id); + "unknown Micron sensor detected: 0x%04x\n", + id); return 0; } @@ -182,8 +183,10 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; dev->em28xx_sensor = EM28XX_NOSENSOR; - /* NOTE: these devices have the register auto incrementation disabled - * by default, so we have to use single byte reads ! */ + /* + * NOTE: these devices have the register auto incrementation disabled + * by default, so we have to use single byte reads ! + */ for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { client->addr = omnivision_sensor_addrs[i]; /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ @@ -393,7 +396,7 @@ int em28xx_init_camera(struct em28xx *dev) subdev = v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &ov2640_info, NULL); - if (subdev == NULL) + if (!subdev) return -ENODEV; format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; -- cgit From 0086085b30937416d8b04a8ece698adcba8ef497 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 12:41:32 -0500 Subject: media: em28xx-cards: fix most coding style issues There are a number of coding style issues, pointed by checkpatch on strict mode. Fix the ones that don't require code refactor here. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 321 +++++++++++++++++++------------- 1 file changed, 189 insertions(+), 132 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index ce04b5023440..e592cd7cd3a4 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -36,7 +36,6 @@ #include #include - #define DRIVER_NAME "em28xx" static int tuner = -1; @@ -116,11 +115,6 @@ static const struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { { -1, -1, -1, -1}, }; -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ - -/* Board - EM2870 Kworld 355u - Analog - No input analog */ - /* Board - EM2882 Kworld 315U digital */ static const struct em28xx_reg_seq em2882_kworld_315u_digital[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, @@ -151,11 +145,12 @@ static const struct em28xx_reg_seq kworld_330u_digital[] = { { -1, -1, -1, -1}, }; -/* Evga inDtube - GPIO0 - Enable digital power (s5h1409) - low to enable - GPIO1 - Enable analog power (tvp5150/emp202) - low to enable - GPIO4 - xc3028 reset - GOP3 - s5h1409 reset +/* + * Evga inDtube + * GPIO0 - Enable digital power (s5h1409) - low to enable + * GPIO1 - Enable analog power (tvp5150/emp202) - low to enable + * GPIO4 - xc3028 reset + * GOP3 - s5h1409 reset */ static const struct em28xx_reg_seq evga_indtube_analog[] = { {EM2820_R08_GPIO_CTRL, 0x79, 0xff, 60}, @@ -218,10 +213,12 @@ static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { { -1, -1, -1, -1}, }; -/* PCTV HD Mini (80e) GPIOs - 0-5: not used - 6: demod reset, active low - 7: LED on, active high */ +/* + * PCTV HD Mini (80e) GPIOs + * 0-5: not used + * 6: demod reset, active low + * 7: LED on, active high + */ static const struct em28xx_reg_seq em2874_pctv_80e_digital[] = { {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/ @@ -229,9 +226,11 @@ static const struct em28xx_reg_seq em2874_pctv_80e_digital[] = { { -1, -1, -1, -1}, }; -/* eb1a:2868 Reddo DVB-C USB TV Box - GPIO4 - CU1216L NIM - Other GPIOs seems to be don't care. */ +/* + * eb1a:2868 Reddo DVB-C USB TV Box + * GPIO4 - CU1216L NIM + * Other GPIOs seems to be don't care. + */ static const struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xde, 0xff, 10}, @@ -310,7 +309,8 @@ static const struct em28xx_reg_seq leadership_reset[] = { { -1, -1, -1, -1}, }; -/* 2013:024f PCTV nanoStick T2 290e +/* + * 2013:024f PCTV nanoStick T2 290e * GPIO_6 - demod reset * GPIO_7 - LED */ @@ -338,7 +338,8 @@ static const struct em28xx_reg_seq terratec_h5_digital[] = { }; #endif -/* 2013:024f PCTV DVB-S2 Stick 460e +/* + * 2013:024f PCTV DVB-S2 Stick 460e * GPIO_0 - POWER_ON * GPIO_1 - BOOST * GPIO_2 - VUV_LNB (red LED) @@ -408,7 +409,8 @@ static const struct em28xx_reg_seq hauppauge_930c_digital[] = { }; #endif -/* 1b80:e425 MaxMedia UB425-TC +/* + * 1b80:e425 MaxMedia UB425-TC * 1b80:e1cc Delock 61959 * GPIO_6 - demod reset, 0=active * GPIO_7 - LED, 0=active @@ -420,7 +422,8 @@ static const struct em28xx_reg_seq maxmedia_ub425_tc[] = { { -1, -1, -1, -1}, }; -/* 2304:0242 PCTV QuatroStick (510e) +/* + * 2304:0242 PCTV QuatroStick (510e) * GPIO_2: decoder reset, 0=active * GPIO_4: decoder suspend, 0=active * GPIO_6: demod reset, 0=active @@ -433,7 +436,8 @@ static const struct em28xx_reg_seq pctv_510e[] = { { -1, -1, -1, -1}, }; -/* 2013:0251 PCTV QuatroStick nano (520e) +/* + * 2013:0251 PCTV QuatroStick nano (520e) * GPIO_2: decoder reset, 0=active * GPIO_4: decoder suspend, 0=active * GPIO_6: demod reset, 0=active @@ -447,7 +451,8 @@ static const struct em28xx_reg_seq pctv_520e[] = { { -1, -1, -1, -1}, }; -/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam +/* + * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam * reg 0x80/0x84: * GPIO_0: capturing LED, 0=on, 1=off * GPIO_2: AV mute button, 0=pressed, 1=unpressed @@ -1434,9 +1439,11 @@ const struct em28xx_board em28xx_boards[] = { .gpio = default_analog, } }, }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ + /* + * maybe there's a reason behind it why Terratec sells the Hybrid XS + * as Prodigy XS with a different PID, let's keep it separated for now + * maybe we'll need it later on + */ [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .tuner_type = TUNER_XC2028, @@ -1780,8 +1787,9 @@ const struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_KWORLD_315U, .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, - /* Analog mode - still not ready */ - /*.input = { { +#if 0 + /* FIXME: Analog mode - still not ready */ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = EM28XX_AMUX_VIDEO, @@ -1799,7 +1807,8 @@ const struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, .gpio = em2882_kworld_315u_analog1, .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, - } }, */ + } }, +#endif }, [EM2880_BOARD_EMPIRE_DUAL_TV] = { .name = "Empire dual TV", @@ -2160,17 +2169,21 @@ const struct em28xx_board em28xx_boards[] = { .gpio = evga_indtube_analog, } }, }, - /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 + - Infineon TUA6034) */ + /* + * eb1a:2868 Empia EM2870 + Philips CU1216L NIM + * (Philips TDA10023 + Infineon TUA6034) + */ [EM2870_BOARD_REDDO_DVB_C_USB_BOX] = { .name = "Reddo DVB-C USB TV Box", .tuner_type = TUNER_ABSENT, .tuner_gpio = reddo_dvb_c_usb_box, .has_dvb = 1, }, - /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold + /* + * 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold * initially as the KWorld PlusTV 340U, then as the UB435-Q. - * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */ + * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 + */ [EM2870_BOARD_KWORLD_A340] = { .name = "KWorld PlusTV 340U or UB435-Q (ATSC)", .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ @@ -2178,30 +2191,38 @@ const struct em28xx_board em28xx_boards[] = { .dvb_gpio = kworld_a340_digital, .tuner_gpio = default_tuner_gpio, }, - /* 2013:024f PCTV nanoStick T2 290e. - * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ + /* + * 2013:024f PCTV nanoStick T2 290e. + * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 + */ [EM28174_BOARD_PCTV_290E] = { .name = "PCTV nanoStick T2 290e", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_290e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* 2013:024f PCTV DVB-S2 Stick 460e - * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */ + /* + * 2013:024f PCTV DVB-S2 Stick 460e + * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 + */ [EM28174_BOARD_PCTV_460E] = { .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .name = "PCTV DVB-S2 Stick (460e)", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_460e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* eb1a:5006 Honestech VIDBOX NW03 - * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */ + /* + * eb1a:5006 Honestech VIDBOX NW03 + * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner + */ [EM2860_BOARD_HT_VIDBOX_NW03] = { .name = "Honestech Vidbox NW03", .tuner_type = TUNER_ABSENT, @@ -2212,12 +2233,14 @@ const struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */ + .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs check */ .amux = EM28XX_AMUX_LINE_IN, } }, }, - /* 1b80:e425 MaxMedia UB425-TC - * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */ + /* + * 1b80:e425 MaxMedia UB425-TC + * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 + */ [EM2874_BOARD_MAXMEDIA_UB425_TC] = { .name = "MaxMedia UB425-TC", .tuner_type = TUNER_ABSENT, @@ -2228,8 +2251,10 @@ const struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 2304:0242 PCTV QuatroStick (510e) - * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ + /* + * 2304:0242 PCTV QuatroStick (510e) + * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 + */ [EM2884_BOARD_PCTV_510E] = { .name = "PCTV QuatroStick (510e)", .tuner_type = TUNER_ABSENT, @@ -2240,8 +2265,10 @@ const struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 2013:0251 PCTV QuatroStick nano (520e) - * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ + /* + * 2013:0251 PCTV QuatroStick nano (520e) + * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 + */ [EM2884_BOARD_PCTV_520E] = { .name = "PCTV QuatroStick nano (520e)", .tuner_type = TUNER_ABSENT, @@ -2261,9 +2288,11 @@ const struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, - /* 1b80:e1cc Delock 61959 + /* + * 1b80:e1cc Delock 61959 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 - * mostly the same as MaxMedia UB-425-TC but different remote */ + * mostly the same as MaxMedia UB-425-TC but different remote + */ [EM2874_BOARD_DELOCK_61959] = { .name = "Delock 61959", .tuner_type = TUNER_ABSENT, @@ -2309,8 +2338,10 @@ const struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_PINNACLE_PCTV_HD, .leds = pctv_80e_leds, }, - /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam - * Empia EM2765 + OmniVision OV2640 */ + /* + * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam + * Empia EM2765 + OmniVision OV2640 + */ [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = { .name = "SpeedLink Vicious And Devine Laplace webcam", .xclk = EM28XX_XCLK_FREQUENCY_24MHZ, @@ -2327,23 +2358,29 @@ const struct em28xx_board em28xx_boards[] = { .buttons = speedlink_vad_laplace_buttons, .leds = speedlink_vad_laplace_leds, }, - /* 2013:0258 PCTV DVB-S2 Stick (461e) - * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */ + /* + * 2013:0258 PCTV DVB-S2 Stick (461e) + * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 + */ [EM28178_BOARD_PCTV_461E] = { .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .name = "PCTV DVB-S2 Stick (461e)", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_461e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, - /* 2013:025f PCTV tripleStick (292e). - * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */ + /* + * 2013:025f PCTV tripleStick (292e). + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 + */ [EM28178_BOARD_PCTV_292E] = { .name = "PCTV tripleStick (292e)", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_292e, .has_dvb = 1, @@ -2363,12 +2400,15 @@ const struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, - /* eb1a:8179 Terratec Cinergy T2 Stick HD. - * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 */ + /* + * eb1a:8179 Terratec Cinergy T2 Stick HD. + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 + */ [EM28178_BOARD_TERRATEC_T2_STICK_HD] = { .name = "Terratec Cinergy T2 Stick HD", .def_i2c_bus = 1, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = terratec_t2_stick_hd, .has_dvb = 1, @@ -2487,10 +2527,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0xeb1a, 0xe359), .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0x1b80, 0xe302), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ - { USB_DEVICE(0x1b80, 0xe304), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */ + { USB_DEVICE(0x1b80, 0xe302), /* Kaiser Baas Video to DVD maker */ + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x1b80, 0xe304), /* Kworld DVD Maker 2 */ + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, { USB_DEVICE(0x0ccd, 0x004c), @@ -2686,16 +2726,16 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev) const struct em28xx_board *board = &em28xx_boards[dev->model]; u8 xclk = board->xclk, i2c_speed = board->i2c_speed; - /* Those are the default values for the majority of boards - Use those values if not specified otherwise at boards entry + /* + * Those are the default values for the majority of boards + * Use those values if not specified otherwise at boards entry */ if (!xclk) xclk = EM28XX_XCLK_IR_RC5_MODE | - EM28XX_XCLK_FREQUENCY_12MHZ; + EM28XX_XCLK_FREQUENCY_12MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); - if (!i2c_speed) i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ; @@ -2719,7 +2759,8 @@ static inline void em28xx_set_model(struct em28xx *dev) dev->def_i2c_bus = dev->board.def_i2c_bus; } -/* Wait until AC97_RESET reports the expected value reliably before proceeding. +/* + * Wait until AC97_RESET reports the expected value reliably before proceeding. * We also check that two unrelated registers accesses don't return the same * value to avoid premature return. * This procedure helps ensuring AC97 register accesses are reliable. @@ -2749,13 +2790,16 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev, return -ETIMEDOUT; } -/* Since em28xx_pre_card_setup() requires a proper dev->model, +/* + * Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ static void em28xx_pre_card_setup(struct em28xx *dev) { - /* Set the initial XCLK and I2C clock values based on the board - definition */ + /* + * Set the initial XCLK and I2C clock values based on the board + * definition + */ em28xx_set_xclk_i2c_speed(dev); /* request some modules */ @@ -2767,17 +2811,19 @@ static void em28xx_pre_card_setup(struct em28xx *dev) case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x6d); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x7d); - msleep(10); + usleep_range(10000, 11000); break; case EM2870_BOARD_COMPRO_VIDEOMATE: - /* TODO: someone can do some cleanup here... - not everything's needed */ + /* + * TODO: someone can do some cleanup here... + * not everything's needed + */ em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x01); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc); @@ -2788,8 +2834,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev) mdelay(70); break; case EM2870_BOARD_TERRATEC_XS_MT2060: - /* this device needs some gpio writes to get the DVB-T - demod work */ + /* + * this device needs some gpio writes to get the DVB-T + * demod work + */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); @@ -2798,8 +2846,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev) mdelay(70); break; case EM2870_BOARD_PINNACLE_PCTV_DVB: - /* this device needs some gpio writes to get the - DVB-T demod work */ + /* + * this device needs some gpio writes to get the + * DVB-T demod work + */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); mdelay(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); @@ -2815,13 +2865,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev) case EM2882_BOARD_KWORLD_ATSC_315U: em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2880_R04_GPO, 0x08); - msleep(10); + usleep_range(10000, 11000); break; case EM2860_BOARD_KAIOMY_TVNPC_U2: @@ -2829,11 +2879,11 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); em28xx_write_regs(dev, 0x0d, "\x42", 1); em28xx_write_regs(dev, 0x08, "\xfd", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\xff", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\x7f", 1); - msleep(10); + usleep_range(10000, 11000); em28xx_write_regs(dev, 0x08, "\x6b", 1); break; @@ -2845,7 +2895,7 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); @@ -2853,7 +2903,8 @@ static void em28xx_pre_card_setup(struct em28xx *dev) break; case EM2860_BOARD_TERRATEC_GRABBY: - /* HACK?: Ensure AC97 register reading is reliable before + /* + * HACK?: Ensure AC97 register reading is reliable before * proceeding. In practice, this will wait about 1.6 seconds. */ em28xx_wait_until_ac97_features_equals(dev, 0x6a90); @@ -2883,7 +2934,8 @@ static int em28xx_hint_board(struct em28xx *dev) return 0; } - /* HINT method: EEPROM + /* + * HINT method: EEPROM * * This method works only for boards with eeprom. * Uses a hash of all eeprom bytes. The hash should be @@ -2909,7 +2961,8 @@ static int em28xx_hint_board(struct em28xx *dev) } } - /* HINT method: I2C attached devices + /* + * HINT method: I2C attached devices * * This method works for all boards. * Uses a hash of i2c scanned devices. @@ -2987,9 +3040,9 @@ static void em28xx_card_setup(struct em28xx *dev) * This solution is only valid if they do not share eeprom * hash identities which has not been determined as yet. */ - if (em28xx_hint_board(dev) < 0) + if (em28xx_hint_board(dev) < 0) { dev_err(&dev->intf->dev, "Board not discovered\n"); - else { + } else { em28xx_set_model(dev); em28xx_pre_card_setup(dev); } @@ -2999,7 +3052,7 @@ static void em28xx_card_setup(struct em28xx *dev) } dev_info(&dev->intf->dev, "Identified as %s (card=%d)\n", - dev->board.name, dev->model); + dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -3016,7 +3069,7 @@ static void em28xx_card_setup(struct em28xx *dev) { struct tveeprom tv; - if (dev->eedata == NULL) + if (!dev->eedata) break; #if defined(CONFIG_MODULES) && defined(MODULE) request_module("tveeprom"); @@ -3035,9 +3088,9 @@ static void em28xx_card_setup(struct em28xx *dev) } case EM2882_BOARD_KWORLD_ATSC_315U: em28xx_write_reg(dev, 0x0d, 0x42); - msleep(10); + usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); - msleep(10); + usleep_range(10000, 11000); break; case EM2820_BOARD_KWORLD_PVRTV2800RF: /* GPIO enables sound on KWORLD PVR TV 2800RF */ @@ -3062,10 +3115,12 @@ static void em28xx_card_setup(struct em28xx *dev) if (!em28xx_hint_board(dev)) em28xx_set_model(dev); - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ + /* + * In cases where we had to use a board hint, the call to + * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + * so make the call now so the analog GPIOs are set properly + * before probing the i2c bus. + */ em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; @@ -3087,10 +3142,12 @@ static void em28xx_card_setup(struct em28xx *dev) if (!em28xx_hint_board(dev)) em28xx_set_model(dev); - /* In cases where we had to use a board hint, the call to - em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, - so make the call now so the analog GPIOs are set properly - before probing the i2c bus. */ + /* + * In cases where we had to use a board hint, the call to + * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + * so make the call now so the analog GPIOs are set properly + * before probing the i2c bus. + */ em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; @@ -3175,8 +3232,8 @@ static void request_module_async(struct work_struct *work) */ /* - * Devicdes with an audio-only interface also have a V4L/DVB/RC - * interface. Don't register extensions twice on those devices. + * Devices with an audio-only intf also have a V4L/DVB/RC + * intf. Don't register extensions twice on those devices. */ if (dev->is_audio_only) { #if defined(CONFIG_MODULES) && defined(MODULE) @@ -3237,7 +3294,6 @@ static int em28xx_media_device_init(struct em28xx *dev, static void em28xx_unregister_media_device(struct em28xx *dev) { - #ifdef CONFIG_MEDIA_CONTROLLER if (dev->media_dev) { media_device_unregister(dev->media_dev); @@ -3252,7 +3308,7 @@ static void em28xx_unregister_media_device(struct em28xx *dev) * em28xx_release_resources() * unregisters the v4l2,i2c and usb devices * called when the device gets disconnected or at module unload -*/ + */ static void em28xx_release_resources(struct em28xx *dev) { struct usb_device *udev = interface_to_usbdev(dev->intf); @@ -3435,8 +3491,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { dev_err(&dev->intf->dev, - "%s: em28xx_i2c_register bus 1 - error [%d]!\n", - __func__, retval); + "%s: em28xx_i2c_register bus 1 - error [%d]!\n", + __func__, retval); em28xx_i2c_unregister(dev, 0); @@ -3455,7 +3511,7 @@ static int em28xx_duplicate_dev(struct em28xx *dev) int nr; struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); - if (sec_dev == NULL) { + if (!sec_dev) { dev->dev_next = NULL; return -ENOMEM; } @@ -3466,7 +3522,7 @@ static int em28xx_duplicate_dev(struct em28xx *dev) if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); + EM28XX_MAXBOARDS); kfree(sec_dev); dev->dev_next = NULL; return -ENOMEM; @@ -3527,7 +3583,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { + if (!dev) { retval = -ENOMEM; goto err; } @@ -3536,7 +3592,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->alt_max_pkt_size_isoc = kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) * interface->num_altsetting, GFP_KERNEL); - if (dev->alt_max_pkt_size_isoc == NULL) { + if (!dev->alt_max_pkt_size_isoc) { kfree(dev); retval = -ENOMEM; goto err; @@ -3546,7 +3602,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, for (i = 0; i < interface->num_altsetting; i++) { int ep; - for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { + for (ep = 0; + ep < interface->altsetting[i].desc.bNumEndpoints; + ep++) { const struct usb_endpoint_descriptor *e; int sizedescr, size; @@ -3611,7 +3669,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, break; } } - /* NOTE: + /* + * NOTE: * Old logic with support for isoc transfers only was: * 0x82 isoc => analog * 0x83 isoc => audio @@ -3709,7 +3768,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_vendor_audio) dev_err(&interface->dev, "em28xx: device seems to have vendor AND usb audio class interfaces !\n" - "\t\tThe vendor interface will be ignored. Please contact the developers \n"); + "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; } @@ -3728,7 +3787,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->num_alt = interface->num_altsetting; - if ((unsigned)card[nr] < em28xx_bcount) + if ((unsigned int)card[nr] < em28xx_bcount) dev->model = card[nr]; /* save our data pointer in this interface device */ @@ -3737,9 +3796,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate device struct and check if the device is a webcam */ mutex_init(&dev->lock); retval = em28xx_init_dev(dev, udev, interface, nr); - if (retval) { + if (retval) goto err_free; - } if (usb_xfer_mode < 0) { if (dev->is_webcam) @@ -3754,7 +3812,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video && dev->board.decoder == EM28XX_NODECODER && dev->em28xx_sensor == EM28XX_NOSENSOR) { - dev_err(&interface->dev, "Currently, V4L2 is not supported on this model\n"); has_video = false; @@ -3805,10 +3862,10 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Select USB transfer types to use */ if (has_dvb) { if (!dev->dvb_ep_isoc_ts2 || - (try_bulk && dev->dvb_ep_bulk_ts2)) + (try_bulk && dev->dvb_ep_bulk_ts2)) dev->dev_next->dvb_xfer_bulk = 1; dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n", - dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc"); + dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc"); } dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2; @@ -3876,10 +3933,10 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (!dev) return; - if (dev->dev_next != NULL) { + if (dev->dev_next) { dev->dev_next->disconnected = 1; dev_info(&dev->intf->dev, "Disconnecting %s\n", - dev->dev_next->name); + dev->dev_next->name); flush_request_modules(dev->dev_next); } @@ -3891,11 +3948,11 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_close_extension(dev); - if (dev->dev_next != NULL) + if (dev->dev_next) em28xx_release_resources(dev->dev_next); em28xx_release_resources(dev); - if (dev->dev_next != NULL) { + if (dev->dev_next) { kref_put(&dev->dev_next->ref, em28xx_free_device); dev->dev_next = NULL; } -- cgit From 4a089668ef22c295ed4997289cc48446c849249c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 13:11:11 -0500 Subject: media: em28xx-cards: rework the em28xx probing code There is a complex loop there with identifies the em28xx endpoints. It has lots of identations inside, and big names, making harder to understand. Simplify it by moving the main logic into a static function. While here, rename "interface" var to "intf". Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 283 +++++++++++++++++--------------- 1 file changed, 149 insertions(+), 134 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index e592cd7cd3a4..6e8247849c4f 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3358,13 +3358,13 @@ EXPORT_SYMBOL_GPL(em28xx_free_device); * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, - struct usb_interface *interface, + struct usb_interface *intf, int minor) { int retval; const char *chip_name = NULL; - dev->intf = interface; + dev->intf = intf; mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); @@ -3538,11 +3538,115 @@ static int em28xx_duplicate_dev(struct em28xx *dev) /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) +static void em28xx_check_usb_descriptor(struct em28xx *dev, + struct usb_device *udev, + struct usb_interface *intf, + int alt, int ep, + bool *has_vendor_audio, + bool *has_video, + bool *has_dvb) +{ + const struct usb_endpoint_descriptor *e; + int sizedescr, size; + + /* + * NOTE: + * + * Old logic with support for isoc transfers only was: + * 0x82 isoc => analog + * 0x83 isoc => audio + * 0x84 isoc => digital + * + * New logic with support for bulk transfers + * 0x82 isoc => analog + * 0x82 bulk => analog + * 0x83 isoc* => audio + * 0x84 isoc => digital + * 0x84 bulk => analog or digital** + * 0x85 isoc => digital TS2 + * 0x85 bulk => digital TS2 + * (*: audio should always be isoc) + * (**: analog, if ep 0x82 is isoc, otherwise digital) + * + * The new logic preserves backwards compatibility and + * reflects the endpoint configurations we have seen + * so far. But there might be devices for which this + * logic is not sufficient... + */ + + e = &intf->altsetting[alt].endpoint[ep].desc; + + if (!usb_endpoint_dir_in(e)) + return; + + sizedescr = le16_to_cpu(e->wMaxPacketSize); + size = sizedescr & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(sizedescr); + + /* Only inspect input endpoints */ + + switch (e->bEndpointAddress) { + case 0x82: + *has_video = true; + if (usb_endpoint_xfer_isoc(e)) { + dev->analog_ep_isoc = e->bEndpointAddress; + dev->alt_max_pkt_size_isoc[alt] = size; + } else if (usb_endpoint_xfer_bulk(e)) { + dev->analog_ep_bulk = e->bEndpointAddress; + } + return; + case 0x83: + if (usb_endpoint_xfer_isoc(e)) + *has_vendor_audio = true; + else + dev_err(&intf->dev, + "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); + return; + case 0x84: + if (*has_video && (usb_endpoint_xfer_bulk(e))) { + dev->analog_ep_bulk = e->bEndpointAddress; + } else { + if (usb_endpoint_xfer_isoc(e)) { + if (size > dev->dvb_max_pkt_size_isoc) { + /* + * 2) some manufacturers (e.g. Terratec) + * disable endpoints by setting + * wMaxPacketSize to 0 bytes for all + * alt settings. So far, we've seen + * this for DVB isoc endpoints only. + */ + *has_dvb = true; + dev->dvb_ep_isoc = e->bEndpointAddress; + dev->dvb_max_pkt_size_isoc = size; + dev->dvb_alt_isoc = alt; + } + } else { + *has_dvb = true; + dev->dvb_ep_bulk = e->bEndpointAddress; + } + } + return; + case 0x85: + if (usb_endpoint_xfer_isoc(e)) { + if (size > dev->dvb_max_pkt_size_isoc_ts2) { + dev->dvb_ep_isoc_ts2 = e->bEndpointAddress; + dev->dvb_max_pkt_size_isoc_ts2 = size; + dev->dvb_alt_isoc = alt; + } + } else { + dev->dvb_ep_bulk_ts2 = e->bEndpointAddress; + } + return; + } +} + /* * em28xx_usb_probe() * checks for supported devices */ -static int em28xx_usb_probe(struct usb_interface *interface, +static int em28xx_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev; @@ -3550,17 +3654,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, int retval; bool has_vendor_audio = false, has_video = false, has_dvb = false; int i, nr, try_bulk; - const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; + const int ifnum = intf->altsetting[0].desc.bInterfaceNumber; char *speed; - udev = usb_get_dev(interface_to_usbdev(interface)); + udev = usb_get_dev(interface_to_usbdev(intf)); /* Check to see next free device and mark as used */ do { nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - dev_err(&interface->dev, + dev_err(&intf->dev, "Driver supports up to %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; @@ -3569,13 +3673,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, } while (test_and_set_bit(nr, em28xx_devused)); /* Don't register audio interfaces */ - if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev_err(&interface->dev, + if (intf->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev_err(&intf->dev, "audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, - interface->altsetting[0].desc.bInterfaceClass); + intf->altsetting[0].desc.bInterfaceClass); retval = -ENODEV; goto err; @@ -3589,9 +3693,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, } /* compute alternate max packet sizes */ - dev->alt_max_pkt_size_isoc = - kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) * - interface->num_altsetting, GFP_KERNEL); + dev->alt_max_pkt_size_isoc = kcalloc(intf->num_altsetting, + sizeof(dev->alt_max_pkt_size_isoc[0]), + GFP_KERNEL); if (!dev->alt_max_pkt_size_isoc) { kfree(dev); retval = -ENOMEM; @@ -3599,106 +3703,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, } /* Get endpoints */ - for (i = 0; i < interface->num_altsetting; i++) { + for (i = 0; i < intf->num_altsetting; i++) { int ep; for (ep = 0; - ep < interface->altsetting[i].desc.bNumEndpoints; - ep++) { - const struct usb_endpoint_descriptor *e; - int sizedescr, size; - - e = &interface->altsetting[i].endpoint[ep].desc; - - sizedescr = le16_to_cpu(e->wMaxPacketSize); - size = sizedescr & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(sizedescr); - - if (usb_endpoint_dir_in(e)) { - switch (e->bEndpointAddress) { - case 0x82: - has_video = true; - if (usb_endpoint_xfer_isoc(e)) { - dev->analog_ep_isoc = - e->bEndpointAddress; - dev->alt_max_pkt_size_isoc[i] = size; - } else if (usb_endpoint_xfer_bulk(e)) { - dev->analog_ep_bulk = - e->bEndpointAddress; - } - break; - case 0x83: - if (usb_endpoint_xfer_isoc(e)) { - has_vendor_audio = true; - } else { - dev_err(&interface->dev, - "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); - } - break; - case 0x84: - if (has_video && - (usb_endpoint_xfer_bulk(e))) { - dev->analog_ep_bulk = - e->bEndpointAddress; - } else { - if (usb_endpoint_xfer_isoc(e)) { - if (size > dev->dvb_max_pkt_size_isoc) { - has_dvb = true; /* see NOTE (~) */ - dev->dvb_ep_isoc = e->bEndpointAddress; - dev->dvb_max_pkt_size_isoc = size; - dev->dvb_alt_isoc = i; - } - } else { - has_dvb = true; - dev->dvb_ep_bulk = e->bEndpointAddress; - } - } - break; - case 0x85: - if (usb_endpoint_xfer_isoc(e)) { - if (size > dev->dvb_max_pkt_size_isoc_ts2) { - dev->dvb_ep_isoc_ts2 = e->bEndpointAddress; - dev->dvb_max_pkt_size_isoc_ts2 = size; - dev->dvb_alt_isoc = i; - } - } else { - dev->dvb_ep_bulk_ts2 = e->bEndpointAddress; - } - break; - } - } - /* - * NOTE: - * Old logic with support for isoc transfers only was: - * 0x82 isoc => analog - * 0x83 isoc => audio - * 0x84 isoc => digital - * - * New logic with support for bulk transfers - * 0x82 isoc => analog - * 0x82 bulk => analog - * 0x83 isoc* => audio - * 0x84 isoc => digital - * 0x84 bulk => analog or digital** - * 0x85 isoc => digital TS2 - * 0x85 bulk => digital TS2 - * (*: audio should always be isoc) - * (**: analog, if ep 0x82 is isoc, otherwise digital) - * - * The new logic preserves backwards compatibility and - * reflects the endpoint configurations we have seen - * so far. But there might be devices for which this - * logic is not sufficient... - */ - /* - * NOTE (~): some manufacturers (e.g. Terratec) disable - * endpoints by setting wMaxPacketSize to 0 bytes for - * all alt settings. So far, we've seen this for - * DVB isoc endpoints only. - */ - } + ep < intf->altsetting[i].desc.bNumEndpoints; + ep++) + em28xx_check_usb_descriptor(dev, udev, intf, + i, ep, + &has_vendor_audio, + &has_video, + &has_dvb); } if (!(has_vendor_audio || has_video || has_dvb)) { @@ -3721,7 +3736,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - dev_err(&interface->dev, + dev_err(&intf->dev, "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", @@ -3729,7 +3744,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, - interface->altsetting->desc.bInterfaceNumber); + intf->altsetting->desc.bInterfaceNumber); /* * Make sure we have 480 Mbps of bandwidth, otherwise things like @@ -3737,8 +3752,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - dev_err(&interface->dev, "Device initialization failed.\n"); - dev_err(&interface->dev, + dev_err(&intf->dev, "Device initialization failed.\n"); + dev_err(&intf->dev, "Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; @@ -3756,17 +3771,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->dev_next = NULL; if (has_vendor_audio) { - dev_err(&interface->dev, + dev_err(&intf->dev, "Audio interface %i found (Vendor Class)\n", ifnum); dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; } - /* Checks if audio is provided by a USB Audio Class interface */ + /* Checks if audio is provided by a USB Audio Class intf */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { struct usb_interface *uif = udev->config->interface[i]; if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) - dev_err(&interface->dev, + dev_err(&intf->dev, "em28xx: device seems to have vendor AND usb audio class interfaces !\n" "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; @@ -3775,27 +3790,27 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if (has_video) - dev_err(&interface->dev, "Video interface %i found:%s%s\n", + dev_err(&intf->dev, "Video interface %i found:%s%s\n", ifnum, dev->analog_ep_bulk ? " bulk" : "", dev->analog_ep_isoc ? " isoc" : ""); if (has_dvb) - dev_err(&interface->dev, "DVB interface %i found:%s%s\n", + dev_err(&intf->dev, "DVB interface %i found:%s%s\n", ifnum, dev->dvb_ep_bulk ? " bulk" : "", dev->dvb_ep_isoc ? " isoc" : ""); - dev->num_alt = interface->num_altsetting; + dev->num_alt = intf->num_altsetting; if ((unsigned int)card[nr] < em28xx_bcount) dev->model = card[nr]; - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); + /* save our data pointer in this intf device */ + usb_set_intfdata(intf, dev); /* allocate device struct and check if the device is a webcam */ mutex_init(&dev->lock); - retval = em28xx_init_dev(dev, udev, interface, nr); + retval = em28xx_init_dev(dev, udev, intf, nr); if (retval) goto err_free; @@ -3812,7 +3827,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video && dev->board.decoder == EM28XX_NODECODER && dev->em28xx_sensor == EM28XX_NOSENSOR) { - dev_err(&interface->dev, + dev_err(&intf->dev, "Currently, V4L2 is not supported on this model\n"); has_video = false; dev->has_video = false; @@ -3822,13 +3837,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - dev_err(&interface->dev, "analog set to %s mode.\n", + dev_err(&intf->dev, "analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; - dev_err(&interface->dev, "dvb set to %s mode.\n", + dev_err(&intf->dev, "dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); } @@ -3842,8 +3857,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->dev_next->model = id->driver_info; mutex_init(&dev->dev_next->lock); - retval = em28xx_init_dev(dev->dev_next, udev, interface, - dev->dev_next->devno); + retval = em28xx_init_dev(dev->dev_next, udev, intf, + dev->dev_next->devno); if (retval) goto err_free; @@ -3923,12 +3938,12 @@ err_no_slot: * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ -static void em28xx_usb_disconnect(struct usb_interface *interface) +static void em28xx_usb_disconnect(struct usb_interface *intf) { struct em28xx *dev; - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); if (!dev) return; @@ -3959,23 +3974,23 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) kref_put(&dev->ref, em28xx_free_device); } -static int em28xx_usb_suspend(struct usb_interface *interface, +static int em28xx_usb_suspend(struct usb_interface *intf, pm_message_t message) { struct em28xx *dev; - dev = usb_get_intfdata(interface); + dev = usb_get_intfdata(intf); if (!dev) return 0; em28xx_suspend_extension(dev); return 0; } -static int em28xx_usb_resume(struct usb_interface *interface) +static int em28xx_usb_resume(struct usb_interface *intf) { struct em28xx *dev; - dev = usb_get_intfdata(interface); + dev = usb_get_intfdata(intf); if (!dev) return 0; em28xx_resume_extension(dev); -- cgit From 349ac5bba1f5862b3baf79183d5583dc9d48731e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 13:43:34 -0500 Subject: media: em28xx-core: fix most coding style issues There are a number of coding style issues at em28xx-core. Fix most of them, by using checkpatch in strict mode to point for it. Automatic fixes were made with --fix-inplace, but those were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 123 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 63 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 269649c81432..bb1b650e7680 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -56,7 +56,6 @@ static unsigned int reg_debug; module_param(reg_debug, int, 0644); MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); - #define em28xx_regdbg(fmt, arg...) do { \ if (reg_debug) \ dev_printk(KERN_DEBUG, &dev->intf->dev, \ @@ -93,10 +92,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed with error %i\n", - pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8, ret); + pipe, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, ret); mutex_unlock(&dev->ctrl_urb_lock); return usb_translate_errors(ret); } @@ -107,10 +107,10 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, mutex_unlock(&dev->ctrl_urb_lock); em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x <<< %*ph\n", - pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8, len, buf); + pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, len, buf); return ret; } @@ -151,7 +151,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if (dev->disconnected) return -ENODEV; - if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) + if (len < 1 || len > URB_MAX_CTRL_SIZE) return -EINVAL; mutex_lock(&dev->ctrl_urb_lock); @@ -337,8 +337,9 @@ static int set_ac97_input(struct em28xx *dev) int ret, i; enum em28xx_amux amux = dev->ctl_ainput; - /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that - em28xx should point to LINE IN, while AC97 should use VIDEO + /* + * EM28XX_AMUX_VIDEO2 is a special case used to indicate that + * em28xx should point to LINE IN, while AC97 should use VIDEO */ if (amux == EM28XX_AMUX_VIDEO2) amux = EM28XX_AMUX_VIDEO; @@ -374,9 +375,9 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } - if (dev->has_msp34xx) + if (dev->has_msp34xx) { input = EM28XX_AUDIO_SRC_TUNER; - else { + } else { switch (dev->ctl_ainput) { case EM28XX_AMUX_VIDEO: input = EM28XX_AUDIO_SRC_TUNER; @@ -395,7 +396,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); if (ret < 0) return ret; - msleep(5); + usleep_range(10000, 11000); switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: @@ -428,8 +429,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) return 0; - /* It is assumed that all devices use master volume for output. - It would be possible to use also line output. + /* + * It is assumed that all devices use master volume for output. + * It would be possible to use also line output. */ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { /* Mute all outputs */ @@ -449,7 +451,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); if (ret < 0) return ret; - msleep(10); + usleep_range(10000, 11000); /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); @@ -483,8 +485,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { int sel = ac97_return_record_select(dev->ctl_aoutput); - /* Use the same input for both left and right - channels */ + /* + * Use the same input for both left and right + * channels + */ sel |= (sel << 8); em28xx_write_ac97(dev, AC97_REC_SEL, sel); @@ -535,7 +539,7 @@ int em28xx_audio_setup(struct em28xx *dev) else i2s_samplerates = 3; dev_info(&dev->intf->dev, "I2S Audio (%d sample rate(s))\n", - i2s_samplerates); + i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; @@ -575,7 +579,7 @@ int em28xx_audio_setup(struct em28xx *dev) dev_warn(&dev->intf->dev, "AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ - if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) + if ((vid == 0xffffffff || vid == 0x83847650) && feat == 0x6a90) dev->audio_mode.ac97 = EM28XX_AC97_EM202; else if ((vid >> 8) == 0x838476) dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; @@ -637,28 +641,26 @@ int em28xx_capture_start(struct em28xx *dev, int start) if (dev->dvb_xfer_bulk) { /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? - EM2874_R5D_TS1_PKT_SIZE : - EM2874_R5E_TS2_PKT_SIZE, - 0xFF); + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + 0xFF); } else { /* ISOC Maximum Transfer Size = 188 * 5 */ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? - EM2874_R5D_TS1_PKT_SIZE : - EM2874_R5E_TS2_PKT_SIZE, - dev->dvb_max_pkt_size_isoc / 188); + EM2874_R5D_TS1_PKT_SIZE : + EM2874_R5E_TS2_PKT_SIZE, + dev->dvb_max_pkt_size_isoc / 188); } if (dev->ts == PRIMARY_TS) rc = em28xx_write_reg_bits(dev, - EM2874_R5F_TS_ENABLE, - start ? - EM2874_TS1_CAPTURE_ENABLE : 0x00, - EM2874_TS1_CAPTURE_ENABLE); + EM2874_R5F_TS_ENABLE, + start ? EM2874_TS1_CAPTURE_ENABLE : 0x00, + EM2874_TS1_CAPTURE_ENABLE); else rc = em28xx_write_reg_bits(dev, - EM2874_R5F_TS_ENABLE, - start ? - EM2874_TS2_CAPTURE_ENABLE : 0x00, - EM2874_TS2_CAPTURE_ENABLE); + EM2874_R5F_TS_ENABLE, + start ? EM2874_TS2_CAPTURE_ENABLE : 0x00, + EM2874_TS2_CAPTURE_ENABLE); } else { /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ @@ -687,7 +689,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) if (rc < 0) return rc; - msleep(6); + usleep_range(10000, 11000); } else { /* disable video capture */ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); @@ -721,7 +723,7 @@ int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio) em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); else em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); - msleep(6); + usleep_range(10000, 11000); } /* Send GPIO reset sequences specified at board entry */ @@ -765,9 +767,9 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) } EXPORT_SYMBOL_GPL(em28xx_set_mode); -/* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ +/* + *URB control + */ /* * URB completion handler for isoc/bulk transfers @@ -786,7 +788,7 @@ static void em28xx_irq_callback(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - em28xx_isocdbg("urb completition error %d.\n", urb->status); + em28xx_isocdbg("urb completion error %d.\n", urb->status); break; } @@ -819,8 +821,7 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) struct em28xx_usb_bufs *usb_bufs; int i; - em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n", - mode); + em28xx_isocdbg("called %s in mode %d\n", __func__, mode); if (mode == EM28XX_DIGITAL_MODE) usb_bufs = &dev->usb_ctl.digital_bufs; @@ -860,7 +861,7 @@ void em28xx_stop_urbs(struct em28xx *dev) struct urb *urb; struct em28xx_usb_bufs *isoc_bufs = &dev->usb_ctl.digital_bufs; - em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n"); + em28xx_isocdbg("called %s\n", __func__); for (i = 0; i < isoc_bufs->num_bufs; i++) { urb = isoc_bufs->urb[i]; @@ -889,10 +890,12 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, int sb_size, pipe; int j, k; - em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); + em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode); - /* Check mode and if we have an endpoint for the selected - transfer type, select buffer */ + /* + * Check mode and if we have an endpoint for the selected + * transfer type, select buffer + */ if (mode == EM28XX_DIGITAL_MODE) { if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { @@ -921,11 +924,11 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->num_bufs = num_bufs; - usb_bufs->urb = kcalloc(sizeof(void *), num_bufs, GFP_KERNEL); + usb_bufs->urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!usb_bufs->urb) return -ENOMEM; - usb_bufs->buf = kcalloc(sizeof(void *), num_bufs, GFP_KERNEL); + usb_bufs->buf = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!usb_bufs->buf) { kfree(usb_bufs->buf); return -ENOMEM; @@ -952,11 +955,6 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL); if (!usb_bufs->buf[i]) { - dev_err(&dev->intf->dev, - "unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - em28xx_uninit_usb_xfer(dev, mode); for (i--; i >= 0; i--) @@ -1017,8 +1015,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, int rc; int alloc; - em28xx_isocdbg("em28xx: called em28xx_init_usb_xfer in mode %d\n", - mode); + em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode); dev->usb_ctl.urb_data_copy = urb_data_copy; @@ -1091,7 +1088,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) list_for_each_entry(dev, &em28xx_devlist, devlist) { if (ops->init) { ops->init(dev); - if (dev->dev_next != NULL) + if (dev->dev_next) ops->init(dev->dev_next); } } @@ -1108,7 +1105,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { if (ops->fini) { - if (dev->dev_next != NULL) + if (dev->dev_next) ops->fini(dev->dev_next); ops->fini(dev); } @@ -1128,7 +1125,7 @@ void em28xx_init_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->init) { ops->init(dev); - if (dev->dev_next != NULL) + if (dev->dev_next) ops->init(dev->dev_next); } } @@ -1142,7 +1139,7 @@ void em28xx_close_extension(struct em28xx *dev) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->fini) { - if (dev->dev_next != NULL) + if (dev->dev_next) ops->fini(dev->dev_next); ops->fini(dev); } @@ -1160,7 +1157,7 @@ int em28xx_suspend_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) ops->suspend(dev); - if (dev->dev_next != NULL) + if (dev->dev_next) ops->suspend(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); @@ -1176,7 +1173,7 @@ int em28xx_resume_extension(struct em28xx *dev) list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) ops->resume(dev); - if (dev->dev_next != NULL) + if (dev->dev_next) ops->resume(dev->dev_next); } mutex_unlock(&em28xx_devlist_mutex); -- cgit From 8adbc7d68a21bc0bb584100adba326f4fa865878 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 14:15:57 -0500 Subject: media: em28xx-i2c: fix most coding style issues There are a number of coding style issues at em28xx-i2c. Fix most of them, by using checkpatch in strict mode to point for it. Automatic fixes were made with --fix-inplace, but those were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 90 +++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 42 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 50b0791a68a5..9151bccd859a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -18,7 +18,6 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. - #include "em28xx.h" #include @@ -47,7 +46,6 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I "i2c: %s: " fmt, __func__, ## arg); \ } while (0) - /* * Time in msecs to wait for i2c xfers to finish. * 35ms is the maximum time a SMBUS device could wait when @@ -91,7 +89,6 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (len < 1 || len > 4) return -EOPNOTSUPP; - BUG_ON(len < 1 || len > 4); b2[5] = 0x80 + len - 1; b2[4] = addr; b2[3] = buf[0]; @@ -125,7 +122,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) ret); return ret; } - msleep(5); + usleep_range(5000, 6000); } dprintk(0, "write to i2c device at 0x%x timed out\n", addr); return -ETIMEDOUT; @@ -172,14 +169,13 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) ret); return ret; } - msleep(5); + usleep_range(5000, 6000); } - if (ret != 0x84 + len - 1) { + if (ret != 0x84 + len - 1) dprintk(0, "read from i2c device at 0x%x timed out\n", addr); - } /* get the received message */ - ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); + ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4 - len, buf2, len); if (ret != len) { dev_warn(&dev->intf->dev, "reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", @@ -231,12 +227,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; - } else { - dev_warn(&dev->intf->dev, - "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); - return -EIO; } + dev_warn(&dev->intf->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); + return -EIO; } /* wait for completion */ @@ -255,7 +250,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret); return ret; } - msleep(5); + usleep_range(5000, 6000); /* * NOTE: do we really have to wait for success ? * Never seen anything else than 0x00 or 0x10 @@ -378,12 +373,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; - } else { - dev_warn(&dev->intf->dev, - "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); - return -EIO; } + + dev_warn(&dev->intf->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); + return -EIO; } /* Check success */ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000); @@ -393,7 +388,8 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) { + + if (ret > 0) { dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -447,7 +443,8 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) { + + if (ret > 0) { dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -535,13 +532,15 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, { struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; struct em28xx *dev = i2c_bus->dev; - unsigned bus = i2c_bus->bus; + unsigned int bus = i2c_bus->bus; int addr, rc, i; u8 reg; - /* prevent i2c xfer attempts after device is disconnected - some fe's try to do i2c writes/reads from their release - interfaces when called in disconnect path */ + /* + * prevent i2c xfer attempts after device is disconnected + * some fe's try to do i2c writes/reads from their release + * interfaces when called in disconnect path + */ if (dev->disconnected) return -ENODEV; @@ -624,12 +623,13 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) if (len == length) { c = (char)len; len = -1; - } else + } else { c = *buf++; + } l = (l << 8) | c; len++; if ((len & (32 / 8 - 1)) == 0) - hash = ((hash^l) * 0x9e370001UL); + hash = ((hash ^ l) * 0x9e370001UL); } while (len); return (hash >> (32 - bits)) & 0xffffffffUL; @@ -639,7 +639,7 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) * Helper function to read data blocks from i2c clients with 8 or 16 bit * address width, 8 bit register width and auto incrementation been activated */ -static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, +static int em28xx_i2c_read_block(struct em28xx *dev, unsigned int bus, u16 addr, bool addr_w16, u16 len, u8 *data) { int remain = len, rsize, rsize_max, ret; @@ -651,7 +651,8 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, /* Select address */ buf[0] = addr >> 8; buf[1] = addr & 0xff; - ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16); + ret = i2c_master_send(&dev->i2c_client[bus], + buf + !addr_w16, 1 + addr_w16); if (ret < 0) return ret; /* Read data */ @@ -676,7 +677,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, return len; } -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, +static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned int bus, u8 **eedata, u16 *eedata_len) { const u16 len = 256; @@ -704,7 +705,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, } data = kzalloc(len, GFP_KERNEL); - if (data == NULL) + if (!data) return -ENOMEM; /* Read EEPROM content */ @@ -796,7 +797,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, return 0; } - /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */ + /* + * TODO: decrypt eeprom data for camera bridges + * (em25xx, em276x+) + */ } else if (!dev->eeprom_addrwidth_16bit && data[0] == 0x1a && data[1] == 0xeb && @@ -886,8 +890,8 @@ static u32 functionality(struct i2c_adapter *i2c_adap) { struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; - if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) || - (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) { + if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX || + i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) { return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) & @@ -920,7 +924,7 @@ static const struct i2c_client em28xx_client_template = { * incomplete list of known devices */ static char *i2c_devs[128] = { - [0x1c >> 1] = "lgdt330x", + [0x1c >> 1] = "lgdt330x", [0x3e >> 1] = "remote IR sensor", [0x4a >> 1] = "saa7113h", [0x52 >> 1] = "drxk", @@ -943,7 +947,7 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus) { u8 i2c_devicelist[128]; unsigned char buf; @@ -971,13 +975,14 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) * em28xx_i2c_register() * register i2c bus */ -int em28xx_i2c_register(struct em28xx *dev, unsigned bus, +int em28xx_i2c_register(struct em28xx *dev, unsigned int bus, enum em28xx_i2c_algo_type algo_type) { int retval; - BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); - BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); + if (WARN_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg || + !dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req)) + return -ENODEV; if (bus >= NUM_I2C_BUSES) return -ENODEV; @@ -1004,8 +1009,9 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, /* Up to now, all eeproms are at bus 0 */ if (!bus) { - retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); - if ((retval < 0) && (retval != -ENODEV)) { + retval = em28xx_i2c_eeprom(dev, bus, + &dev->eedata, &dev->eedata_len); + if (retval < 0 && retval != -ENODEV) { dev_err(&dev->intf->dev, "%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); @@ -1022,7 +1028,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, * em28xx_i2c_unregister() * unregister i2c_bus */ -int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus) +int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus) { if (bus >= NUM_I2C_BUSES) return -ENODEV; -- cgit From 08cc05e4e737c1a4df194624f45bdb1eeae90762 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 14:26:13 -0500 Subject: media: em28xx-input: fix most coding style issues There are a number of coding style issues at em28xx-input. Fix most of them, by using checkpatch in strict mode to point for it. Automatic fixes were made with --fix-inplace, but those were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 121 +++++++++++++++++++------------- 1 file changed, 74 insertions(+), 47 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index c7afcf67ccc5..eb2ec0384b69 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -37,15 +37,15 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define MODULE_NAME "em28xx" -#define dprintk( fmt, arg...) do { \ +#define dprintk(fmt, arg...) do { \ if (ir_debug) \ dev_printk(KERN_DEBUG, &ir->dev->intf->dev, \ "input: %s: " fmt, __func__, ## arg); \ } while (0) -/********************************************************** - Polling structure used by em28xx IR's - **********************************************************/ +/* + * Polling structure used by em28xx IR's + */ struct em28xx_ir_poll_result { unsigned int toggle_bit:1; @@ -72,12 +72,12 @@ struct em28xx_IR { int (*get_key_i2c)(struct i2c_client *ir, enum rc_proto *protocol, u32 *scancode); - int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); + int (*get_key)(struct em28xx_IR *ir, struct em28xx_ir_poll_result *r); }; -/********************************************************** - I2C IR based get keycodes - should be used with ir-kbd-i2c - **********************************************************/ +/* + * I2C IR based get keycodes - should be used with ir-kbd-i2c + */ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, enum rc_proto *protocol, u32 *scancode) @@ -85,11 +85,13 @@ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(i2c_dev, &b, 1)) + if (i2c_master_recv(i2c_dev, &b, 1) != 1) return -EIO; - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold down. */ + /* + * it seems that 0xFE indicates that a button is still hold + * down, while 0xff indicates that no button is hold down. + */ if (b == 0xff) return 0; @@ -141,7 +143,7 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev, /* poll IR chip */ - if (3 != i2c_master_recv(i2c_dev, buf, 3)) + if (i2c_master_recv(i2c_dev, buf, 3) != 3) return -EIO; if (buf[0] != 0x00) @@ -158,18 +160,28 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, { unsigned char subaddr, keydetect, key; - struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1}, - { .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} }; + struct i2c_msg msg[] = { + { + .addr = i2c_dev->addr, + .flags = 0, + .buf = &subaddr, .len = 1 + }, { + .addr = i2c_dev->addr, + .flags = I2C_M_RD, + .buf = &keydetect, + .len = 1 + } + }; subaddr = 0x10; - if (2 != i2c_transfer(i2c_dev->adapter, msg, 2)) + if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2) return -EIO; if (keydetect == 0x00) return 0; subaddr = 0x00; msg[1].buf = &key; - if (2 != i2c_transfer(i2c_dev->adapter, msg, 2)) + if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2) return -EIO; if (key == 0x00) return 0; @@ -179,9 +191,9 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, return 1; } -/********************************************************** - Poll based get keycode functions - **********************************************************/ +/* + * Poll based get keycode functions + */ /* This is for the em2860/em2880 */ static int default_polling_getkey(struct em28xx_IR *ir, @@ -191,8 +203,9 @@ static int default_polling_getkey(struct em28xx_IR *ir, int rc; u8 msg[3] = { 0, 0, 0 }; - /* Read key toggle, brand, and key code - on registers 0x45, 0x46 and 0x47 + /* + * Read key toggle, brand, and key code + * on registers 0x45, 0x46 and 0x47 */ rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, msg, sizeof(msg)); @@ -233,8 +246,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, int rc; u8 msg[5] = { 0, 0, 0, 0, 0 }; - /* Read key toggle, brand, and key code - on registers 0x51-55 + /* + * Read key toggle, brand, and key code + * on registers 0x51-55 */ rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, msg, sizeof(msg)); @@ -290,9 +304,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, return 0; } -/********************************************************** - Polling code for em28xx - **********************************************************/ +/* + * Polling code for em28xx + */ static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir) { @@ -343,11 +357,14 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) if (ir->dev->chip_id == CHIP_ID_EM2874 || ir->dev->chip_id == CHIP_ID_EM2884) - /* The em2874 clears the readcount field every time the - register is read. The em2860/2880 datasheet says that it - is supposed to clear the readcount, but it doesn't. So with - the em2874, we are looking for a non-zero read count as - opposed to a readcount that is incrementing */ + /* + * The em2874 clears the readcount field every time the + * register is read. The em2860/2880 datasheet says + * that it is supposed to clear the readcount, but it + * doesn't. So with the em2874, we are looking for a + * non-zero read count as opposed to a readcount + * that is incrementing + */ ir->last_readcount = 0; else ir->last_readcount = poll_result.read_count; @@ -472,15 +489,18 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto) static int em28xx_probe_i2c_ir(struct em28xx *dev) { int i = 0; - /* Leadtek winfast tv USBII deluxe can find a non working IR-device */ - /* at address 0x18, so if that address is needed for another board in */ - /* the future, please put it after 0x1f. */ + /* + * Leadtek winfast tv USBII deluxe can find a non working IR-device + * at address 0x18, so if that address is needed for another board in + * the future, please put it after 0x1f. + */ const unsigned short addr_list[] = { 0x1f, 0x30, 0x47, I2C_CLIENT_END }; while (addr_list[i] != I2C_CLIENT_END) { - if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1) + if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], + addr_list[i]) == 1) return addr_list[i]; i++; } @@ -488,9 +508,9 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) return -ENODEV; } -/********************************************************** - Handle buttons - **********************************************************/ +/* + * Handle buttons + */ static void em28xx_query_buttons(struct work_struct *work) { @@ -511,7 +531,9 @@ static void em28xx_query_buttons(struct work_struct *work) j = 0; while (dev->board.buttons[j].role >= 0 && dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) { - const struct em28xx_button *button = &dev->board.buttons[j]; + const struct em28xx_button *button; + + button = &dev->board.buttons[j]; /* Check if button uses the current address */ if (button->reg_r != dev->button_polling_addresses[i]) { @@ -647,6 +669,7 @@ static void em28xx_init_buttons(struct em28xx *dev) /* Add read address to list of polling addresses */ if (addr_new) { unsigned int index = dev->num_button_polling_addresses; + dev->button_polling_addresses[index] = button->reg_r; dev->num_button_polling_addresses++; } @@ -675,7 +698,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) /* Clear polling addresses list */ dev->num_button_polling_addresses = 0; /* Deregister input devices */ - if (dev->sbutton_input_dev != NULL) { + if (dev->sbutton_input_dev) { dev_info(&dev->intf->dev, "Deregistering snapshot button\n"); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; @@ -712,7 +735,7 @@ static int em28xx_ir_init(struct em28xx *dev) } } - if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { + if (!dev->board.ir_codes && !dev->board.has_ir_i2c) { /* No remote control support */ dev_warn(&dev->intf->dev, "Remote control support is not available for this card.\n"); @@ -762,7 +785,7 @@ static int em28xx_ir_init(struct em28xx *dev) goto error; } - ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + ir->i2c_client = kzalloc(sizeof(*ir->i2c_client), GFP_KERNEL); if (!ir->i2c_client) goto error; ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus]; @@ -879,9 +902,11 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); - /* is canceling delayed work sufficient or does the rc event - kthread needs stopping? kthread is stopped in - ir_raw_event_unregister() */ + /* + * is canceling delayed work sufficient or does the rc event + * kthread needs stopping? kthread is stopped in + * ir_raw_event_unregister() + */ return 0; } @@ -893,8 +918,10 @@ static int em28xx_ir_resume(struct em28xx *dev) return 0; dev_info(&dev->intf->dev, "Resuming input extension\n"); - /* if suspend calls ir_raw_event_unregister(), the should call - ir_raw_event_register() */ + /* + * if suspend calls ir_raw_event_unregister(), the should call + * ir_raw_event_register() + */ if (ir) schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); if (dev->num_button_polling_addresses) -- cgit From f9fe90a46d12509d8551d215119ccf561eedaa39 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Mar 2018 14:49:09 -0500 Subject: media: em28xx-video: fix most coding style issues There are a number of coding style issues at em28xx-video. Fix most of them, by using checkpatch in strict mode to point for it. Automatic fixes were made with --fix-inplace, but those were complemented by manual work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 277 ++++++++++++++++++-------------- 1 file changed, 158 insertions(+), 119 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 7649deec3c1c..f31339727d3b 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -246,7 +246,8 @@ static int em28xx_set_outfmt(struct em28xx *dev) if (em28xx_vbi_supported(dev) == 1) { vinctrl |= EM28XX_VINCTRL_VBI_RAW; em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); - em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4); + em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, + v4l2->vbi_width / 4); em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height); if (v4l2->norm & V4L2_STD_525_60) { /* NTSC */ @@ -316,8 +317,10 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) buf[0] = v; buf[1] = v >> 8; em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); - /* it seems that both H and V scalers must be active - to work correctly */ + /* + * it seems that both H and V scalers must be active + * to work correctly + */ mode = (h || v) ? 0x30 : 0x00; } return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode); @@ -341,13 +344,15 @@ static int em28xx_resolution_set(struct em28xx *dev) em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); - /* If we don't set the start position to 2 in VBI mode, we end up - with line 20/21 being YUYV encoded instead of being in 8-bit - greyscale. The core of the issue is that line 21 (and line 23 for - PAL WSS) are inside of active video region, and as a result they - get the pixelformatting associated with that area. So by cropping - it out, we end up with the same format as the rest of the VBI - region */ + /* + * If we don't set the start position to 2 in VBI mode, we end up + * with line 20/21 being YUYV encoded instead of being in 8-bit + * greyscale. The core of the issue is that line 21 (and line 23 for + * PAL WSS) are inside of active video region, and as a result they + * get the pixelformatting associated with that area. So by cropping + * it out, we end up with the same format as the rest of the VBI + * region + */ if (em28xx_vbi_supported(dev) == 1) em28xx_capture_area_set(dev, 0, 2, width, height); else @@ -361,14 +366,16 @@ static int em28xx_set_alternate(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); - int errCode; + int err; int i; unsigned int min_pkt_size = v4l2->width * 2 + 4; - /* NOTE: for isoc transfers, only alt settings > 0 are allowed - bulk transfers seem to work only with alt=0 ! */ + /* + * NOTE: for isoc transfers, only alt settings > 0 are allowed + * bulk transfers seem to work only with alt=0 ! + */ dev->alt = 0; - if ((alt > 0) && (alt < dev->num_alt)) { + if (alt > 0 && alt < dev->num_alt) { em28xx_videodbg("alternate forced to %d\n", dev->alt); dev->alt = alt; goto set_alt; @@ -376,9 +383,10 @@ static int em28xx_set_alternate(struct em28xx *dev) if (dev->analog_xfer_bulk) goto set_alt; - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. + /* + * When image size is bigger than a certain value, + * the frame size should be increased, otherwise, only + * green screen will be received. */ if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2) min_pkt_size *= 2; @@ -388,18 +396,22 @@ static int em28xx_set_alternate(struct em28xx *dev) if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { dev->alt = i; break; - /* otherwise make sure that we end up with the maximum bandwidth - because the min_pkt_size equation might be wrong... - */ + /* + * otherwise make sure that we end up with the maximum + * bandwidth because the min_pkt_size equation might be wrong. + * + */ } else if (dev->alt_max_pkt_size_isoc[i] > dev->alt_max_pkt_size_isoc[dev->alt]) dev->alt = i; } set_alt: - /* NOTE: for bulk transfers, we need to call usb_set_interface() + /* + * NOTE: for bulk transfers, we need to call usb_set_interface() * even if the previous settings were the same. Otherwise streaming - * fails with all urbs having status = -EOVERFLOW ! */ + * fails with all urbs having status = -EOVERFLOW ! + */ if (dev->analog_xfer_bulk) { dev->max_pkt_size = 512; /* USB 2.0 spec */ dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; @@ -412,19 +424,19 @@ set_alt: } em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(udev, dev->ifnum, dev->alt); - if (errCode < 0) { + err = usb_set_interface(udev, dev->ifnum, dev->alt); + if (err < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); - return errCode; + dev->alt, err); + return err; } return 0; } -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ +/* + * DMA and thread functions + */ /* * Finish the current buffer @@ -510,8 +522,9 @@ static void em28xx_copy_video(struct em28xx *dev, em28xx_isocdbg("Overflow of %zu bytes past buffer end(2)\n", ((char *)startwrite + lencopy) - ((char *)buf->vb_buf + buf->length)); - lencopy = remain = (char *)buf->vb_buf + buf->length - - (char *)startwrite; + remain = (char *)buf->vb_buf + buf->length - + (char *)startwrite; + lencopy = remain; } if (lencopy <= 0) break; @@ -619,11 +632,11 @@ finish_field_prepare_next(struct em28xx *dev, struct em28xx_v4l2 *v4l2 = dev->v4l2; if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */ - if (buf != NULL) + if (buf) finish_buffer(dev, buf); buf = get_next_buf(dev, dma_q); } - if (buf != NULL) { + if (buf) { buf->top_field = v4l2->top_field; buf->pos = 0; } @@ -644,13 +657,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, struct em28xx_dmaqueue *dma_q = &dev->vidq; struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; - /* capture type 0 = vbi start - capture type 1 = vbi in progress - capture type 2 = video start - capture type 3 = video in progress */ + /* + * capture type 0 = vbi start + * capture type 1 = vbi in progress + * capture type 2 = video start + * capture type 3 = video in progress + */ if (data_len >= 4) { - /* NOTE: Headers are always 4 bytes and - * never split across packets */ + /* + * NOTE: Headers are always 4 bytes and + * never split across packets + */ if (data_pkt[0] == 0x88 && data_pkt[1] == 0x88 && data_pkt[2] == 0x88 && data_pkt[3] == 0x88) { /* Continuation */ @@ -673,8 +690,10 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, data_len -= 4; } } - /* NOTE: With bulk transfers, intermediate data packets - * have no continuation header */ + /* + * NOTE: With bulk transfers, intermediate data packets + * have no continuation header + */ if (v4l2->capture_type == 0) { vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q); @@ -688,7 +707,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, (vbi_size - v4l2->vbi_read) : data_len; /* Copy VBI data */ - if (vbi_buf != NULL) + if (vbi_buf) em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len); v4l2->vbi_read += vbi_data_len; @@ -706,7 +725,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, v4l2->capture_type = 3; } - if (v4l2->capture_type == 3 && buf != NULL && data_len > 0) + if (v4l2->capture_type == 3 && buf && data_len > 0) em28xx_copy_video(dev, buf, data_pkt, data_len); } @@ -723,8 +742,10 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, bool frame_end = false; /* Check for header */ - /* NOTE: at least with bulk transfers, only the first packet - * has a header and has always set the FRAME_END bit */ + /* + * NOTE: at least with bulk transfers, only the first packet + * has a header and has always set the FRAME_END bit + */ if (data_len >= 2) { /* em25xx header is only 2 bytes long */ if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) && ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) { @@ -741,14 +762,15 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, buf = finish_field_prepare_next(dev, buf, dmaq); dev->usb_ctl.vid_buf = buf; } - /* NOTE: in ISOC mode when a new frame starts and buf==NULL, + /* + * NOTE: in ISOC mode when a new frame starts and buf==NULL, * we COULD already prepare a buffer here to avoid skipping the * first frame. */ } /* Copy data */ - if (buf != NULL && data_len > 0) + if (buf && data_len > 0) em28xx_copy_video(dev, buf, data_pkt, data_len); /* Finish frame (ISOC only) => avoids lag of 1 frame */ @@ -757,14 +779,17 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, dev->usb_ctl.vid_buf = buf; } - /* NOTE: Tested with USB bulk transfers only ! + /* + * NOTES: + * + * 1) Tested with USB bulk transfers only ! * The wording in the datasheet suggests that isoc might work different. * The current code assumes that with isoc transfers each packet has a * header like with the other em28xx devices. + * + * 2) Support for interlaced mode is pure theory. It has not been + * tested and it is unknown if these devices actually support it. */ - /* NOTE: Support for interlaced mode is pure theory. It has not been - * tested and it is unknown if these devices actually support it. */ - /* NOTE: No VBI support yet (these chips likely do not support VBI). */ } /* Processes and copies the URB data content (video and VBI data) */ @@ -825,12 +850,11 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) else process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len); - } return 1; } -static int get_ressource(enum v4l2_buf_type f_type) +static int get_resource(enum v4l2_buf_type f_type) { switch (f_type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -838,14 +862,15 @@ static int get_ressource(enum v4l2_buf_type f_type) case V4L2_BUF_TYPE_VBI_CAPTURE: return EM28XX_RESOURCE_VBI; default: - BUG(); + WARN_ON(1); + return -1; /* Indicate that device is busy */ } } /* Usage lock check functions */ static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type) { - int res_type = get_ressource(f_type); + int res_type = get_resource(f_type); /* is it free? */ if (dev->resources & res_type) { @@ -861,7 +886,7 @@ static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type) static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type) { - int res_type = get_ressource(f_type); + int res_type = get_resource(f_type); dev->resources &= ~res_type; em28xx_videodbg("res: put %d\n", res_type); @@ -933,10 +958,11 @@ static int em28xx_enable_analog_tuner(struct em28xx *dev) flags ? "enabled" : "disabled", ret); return ret; - } else - em28xx_videodbg("link %s->%s was %s\n", - source->name, sink->name, - flags ? "ENABLED" : "disabled"); + } + + em28xx_videodbg("link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); } #endif return 0; @@ -1012,10 +1038,9 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) #endif } - -/* ------------------------------------------------------------------ - Videobuf2 operations - ------------------------------------------------------------------*/ +/* + * Videobuf2 operations + */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, @@ -1068,8 +1093,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) em28xx_videodbg("%s\n", __func__); - /* Make sure streaming is not already in progress for this type - of filehandle (e.g. video, vbi) */ + /* + * Make sure streaming is not already in progress for this type + * of filehandle (e.g. video, vbi) + */ rc = res_get(dev, vq->type); if (rc) return rc; @@ -1080,9 +1107,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) /* Allocate the USB bandwidth */ em28xx_set_alternate(dev); - /* Needed, since GPIO might have disabled power of - some i2c device - */ + /* + * Needed, since GPIO might have disabled power of + * some i2c device + */ em28xx_wake_i2c(dev); v4l2->capture_type = -1; @@ -1141,7 +1169,7 @@ static void em28xx_stop_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); - if (dev->usb_ctl.vid_buf != NULL) { + if (dev->usb_ctl.vid_buf) { vb2_buffer_done(&dev->usb_ctl.vid_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); dev->usb_ctl.vid_buf = NULL; @@ -1176,7 +1204,7 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); - if (dev->usb_ctl.vbi_buf != NULL) { + if (dev->usb_ctl.vbi_buf) { vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); dev->usb_ctl.vbi_buf = NULL; @@ -1257,7 +1285,9 @@ static int em28xx_vb2_setup(struct em28xx *dev) return 0; } -/********************* v4l2 interface **************************************/ +/* + * v4l2 interface + */ static void video_mux(struct em28xx *dev, int index) { @@ -1390,9 +1420,9 @@ static void scale_to_size(struct em28xx *dev, *height = 1; } -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ +/* + * IOCTL vidioc handling + */ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -1458,8 +1488,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, if (width == maxw && height == maxh) width /= 2; } else { - /* width must even because of the YUYV format - height must be even because of interlacing */ + /* + * width must even because of the YUYV format + * height must be even because of interlacing + */ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); } @@ -1489,7 +1521,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, - unsigned width, unsigned height) + unsigned int width, unsigned int height) { struct em28xx_fmt *fmt; struct em28xx_v4l2 *v4l2 = dev->v4l2; @@ -1638,15 +1670,14 @@ static int vidioc_enum_input(struct file *file, void *priv, n = i->index; if (n >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(n)->type) + if (!INPUT(n)->type) return -EINVAL; - i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type)) + if (INPUT(n)->type == EM28XX_VMUX_TELEVISION) i->type = V4L2_INPUT_TYPE_TUNER; i->std = dev->v4l2->vdev.tvnorms; @@ -1672,7 +1703,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (i >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(i)->type) + if (!INPUT(i)->type) return -EINVAL; video_mux(dev, i); @@ -1718,13 +1749,14 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) return 0; } -static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) +static int vidioc_s_audio(struct file *file, void *priv, + const struct v4l2_audio *a) { struct em28xx *dev = video_drvdata(file); if (a->index >= MAX_EM28XX_INPUT) return -EINVAL; - if (0 == INPUT(a->index)->type) + if (!INPUT(a->index)->type) return -EINVAL; dev->ctl_ainput = INPUT(a->index)->amux; @@ -1741,7 +1773,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; strcpy(t->name, "Tuner"); @@ -1755,7 +1787,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); @@ -1768,7 +1800,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (0 != f->tuner) + if (f->tuner != 0) return -EINVAL; f->frequency = v4l2->frequency; @@ -1782,7 +1814,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (0 != f->tuner) + if (f->tuner != 0) return -EINVAL; v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f); @@ -1906,8 +1938,9 @@ static int vidioc_querycap(struct file *file, void *priv, if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | + V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; if (video_is_registered(&v4l2->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; if (video_is_registered(&v4l2->radio_dev)) @@ -2000,9 +2033,9 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, return 0; } -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ +/* + * RADIO ESPECIFIC IOCTLS + */ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) @@ -2024,7 +2057,7 @@ static int radio_s_tuner(struct file *file, void *priv, { struct em28xx *dev = video_drvdata(file); - if (0 != t->index) + if (t->index != 0) return -EINVAL; v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); @@ -2119,7 +2152,7 @@ static int em28xx_v4l2_open(struct file *filp) * em28xx_v4l2_fini() * unregisters the v4l2,i2c and usb devices * called when the device gets disconected or at module unload -*/ + */ static int em28xx_v4l2_fini(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; @@ -2134,7 +2167,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) return 0; } - if (v4l2 == NULL) + if (!v4l2) return 0; dev_info(&dev->intf->dev, "Closing video extension\n"); @@ -2149,17 +2182,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (video_is_registered(&v4l2->radio_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2211,7 +2244,7 @@ static int em28xx_v4l2_close(struct file *filp) struct em28xx *dev = video_drvdata(filp); struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); - int errCode; + int err; em28xx_videodbg("users=%d\n", v4l2->users); @@ -2232,11 +2265,11 @@ static int em28xx_v4l2_close(struct file *filp) /* set alternate 0 */ dev->alt = 0; em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(udev, 0, 0); - if (errCode < 0) { + err = usb_set_interface(udev, 0, 0); + if (err < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to 0 (error=%i)\n", - errCode); + err); } } @@ -2394,7 +2427,7 @@ static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr) 0, tuner, s_type_addr, &tun_setup); } - if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type) { tun_setup.type = dev->tuner_type; tun_setup.addr = tuner_addr; @@ -2457,7 +2490,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_lock(&dev->lock); - v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL); + v4l2 = kzalloc(sizeof(*v4l2), GFP_KERNEL); if (!v4l2) { mutex_unlock(&dev->lock); return -ENOMEM; @@ -2590,7 +2623,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) __func__, ret); goto unregister_dev; } - msleep(3); + usleep_range(10000, 11000); ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { @@ -2599,7 +2632,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) __func__, ret); goto unregister_dev; } - msleep(3); + usleep_range(10000, 11000); } /* set default norm */ @@ -2611,8 +2644,10 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->format = &format[0]; maxw = norm_maxw(dev); - /* MaxPacketSize for em2800 is too small to capture at full resolution - * use half of maxw as the scaler can only scale to 50% */ + /* + * MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% + */ if (dev->board.is_em2800) maxw /= 2; @@ -2633,29 +2668,33 @@ static int em28xx_v4l2_init(struct em28xx *dev) em28xx_set_outfmt(dev); /* Add image controls */ - /* NOTE: at this point, the subdevices are already registered, so bridge - * controls are only added/enabled when no subdevice provides them */ - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST)) + + /* + * NOTE: at this point, the subdevices are already registered, so + * bridge controls are only added/enabled when no subdevice provides + * them + */ + if (!v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_CONTRAST, 0, 0x1f, 1, CONTRAST_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BRIGHTNESS, -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_SATURATION)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SATURATION, 0, 0x1f, 1, SATURATION_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, RED_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS)) + if (!v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS)) v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SHARPNESS, 0, 0x0f, 1, SHARPNESS_DEFAULT); @@ -2705,7 +2744,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Allocate and fill vbi video_device struct */ if (em28xx_vbi_supported(dev) == 1) { em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template, - "vbi"); + "vbi"); v4l2->vbi_dev.queue = &v4l2->vb_vbiq; v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock; @@ -2735,7 +2774,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template, - "radio"); + "radio"); ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { -- cgit From 8177733af1f1639005f532ac2cf2f5c1cce7b8e6 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 19:48:19 -0500 Subject: media: cx23885: Enable new Hauppauge PCIe ImpactVCBe variant Add ID of new card revision to driver list Analog PAL/NTSC capture. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 3622521431f5..c4b312377e38 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1027,6 +1027,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7133, .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE, + }, { + .subvendor = 0x0070, + .subdevice = 0x7137, + .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE, }, { .subvendor = 0x18ac, .subdevice = 0xdb98, -- cgit From 94f115188e4546a26ac4f267d22e0a66e57af5f7 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 19:48:20 -0500 Subject: media: cx23885: Add support for Hauppauge PCIe HVR1265 K4 Add new PCIe board to driver list and board register/configure functions cx23885 + lgdt3306a + si2157 digital/analog Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 27 ++++++++++++++++++ drivers/media/pci/cx23885/cx23885-dvb.c | 46 +++++++++++++++++++++++++++++++ drivers/media/pci/cx23885/cx23885-input.c | 3 ++ drivers/media/pci/cx23885/cx23885-video.c | 5 +++- drivers/media/pci/cx23885/cx23885.h | 1 + 5 files changed, 81 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c4b312377e38..e2c12ebba738 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -776,6 +776,11 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = { + .name = "Hauppauge WinTV-HVR-1265(161111)", + .portc = CX23885_MPEG_DVB, + .force_bff = 1, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -1091,6 +1096,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x6b18, .card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 2 */ + }, { + .subvendor = 0x0070, + .subdevice = 0x2a18, + .card = CX23885_BOARD_HAUPPAUGE_HVR1265_K4, /* Hauppauge WinTV HVR-1265 (Model 161xx1, Hybrid ATSC/QAM-B) */ }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1291,6 +1300,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 150329: /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; + case 161111: + /* WinTV-HVR-1265 K4 (PCIe, Analog/ATSC/QAM-B) */ + break; case 166100: /* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height, DVB-T/T2/C, DVB-T/T2/C */ @@ -1813,6 +1825,18 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) * card does not have any GPIO's connected to subcomponents. */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + /* + * GPIO-08 TER1_RESN + * GPIO-09 TER2_RESN + */ + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); + cx23885_gpio_clear(dev, GPIO_8 | GPIO_9); + msleep(100); + cx23885_gpio_set(dev, GPIO_8 | GPIO_9); + msleep(100); + break; } } @@ -2058,6 +2082,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_STARBURST: case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: case CX23885_BOARD_HAUPPAUGE_HVR5525: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: if (dev->i2c_bus[0].i2c_rc == 0) @@ -2205,6 +2230,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ @@ -2263,6 +2289,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 6061e36d76b1..97bbf10a8481 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -930,6 +930,18 @@ static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = { .agc = 0x99, }; +static struct lgdt3306a_config hauppauge_hvr1265k4_config = { + .i2c_addr = 0x59, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -2490,7 +2502,41 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + switch (port->nr) { + /* port c - Terrestrial/cable */ + case 2: + /* attach frontend */ + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr1265k4_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend == NULL) + break; + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; + si2157_config.inversion = 1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!client_tuner || !client_tuner->dev.driver) + goto frontend_detach; + + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + client_tuner = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: pr_info("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 0f4e54294bb7..be49589a61d2 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -94,6 +94,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) case CX23885_BOARD_DVBSKY_S950: case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* * The only boards we handle right now. However other boards * using the CX2388x integrated IR controller should be similar @@ -153,6 +154,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) case CX23885_BOARD_DVBSKY_S950: case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* * The IR controller on this board only returns pulse widths. * Any other mode setting will fail to set up the device. @@ -283,6 +285,7 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: /* Integrated CX2388[58] IR controller */ allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Hauppauge RC-5 remote */ diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index a03dcb662953..f8a3deadc77a 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -263,6 +263,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || (dev->board == CX23885_BOARD_MYGICA_X8507) || (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) || @@ -993,7 +994,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111)) + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4)) fe = &dev->ts1.analog_fe; if (fe && fe->ops.tuner_ops.set_analog_params) { @@ -1022,6 +1024,7 @@ int cx23885_set_frequency(struct file *file, void *priv, switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: + case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_HVR1850: ret = cx23885_set_freq_via_ops(dev, f); break; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 2a17209eb4f6..7c7a1030f531 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -107,6 +107,7 @@ #define CX23885_BOARD_VIEWCAST_460E 55 #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57 +#define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit From 16fad6743245df4e385817d74ee6e981d43a71bc Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 19:48:21 -0500 Subject: media: cx23885: Add support for Hauppauge PCIe Starburst2 Add new PCIe DVB-S/S2. A single port Hauppauge HVR-5525 cx23885 + a8293 + m88rs6000t Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 11 +++++++++++ drivers/media/pci/cx23885/cx23885-dvb.c | 18 ++++++++++-------- drivers/media/pci/cx23885/cx23885.h | 1 + 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index e2c12ebba738..5208d6d0669e 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -781,6 +781,10 @@ struct cx23885_board cx23885_boards[] = { .portc = CX23885_MPEG_DVB, .force_bff = 1, }, + [CX23885_BOARD_HAUPPAUGE_STARBURST2] = { + .name = "Hauppauge WinTV-Starburst2", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -1100,6 +1104,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x2a18, .card = CX23885_BOARD_HAUPPAUGE_HVR1265_K4, /* Hauppauge WinTV HVR-1265 (Model 161xx1, Hybrid ATSC/QAM-B) */ + }, { + .subvendor = 0x0070, + .subdevice = 0xf02a, + .card = CX23885_BOARD_HAUPPAUGE_STARBURST2, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1796,6 +1804,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR5525: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: /* * HVR5525 GPIO Details: * GPIO-00 IR_WIDE @@ -2083,6 +2092,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: case CX23885_BOARD_HAUPPAUGE_HVR5525: case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: if (dev->i2c_bus[0].i2c_rc == 0) @@ -2223,6 +2233,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR5525: + case CX23885_BOARD_HAUPPAUGE_STARBURST2: ts1->gen_ctrl_val = 0x5; /* Parallel */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 97bbf10a8481..f2b204ae08e5 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1206,6 +1206,8 @@ static int dvb_register(struct cx23885_tsport *port) struct si2157_config si2157_config; struct ts2020_config ts2020_config; struct m88ds3103_platform_data m88ds3103_pdata; + struct m88rs6000t_config m88rs6000t_config = {}; + struct a8293_platform_data a8293_pdata = {}; struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client_demod = NULL, *client_tuner = NULL; @@ -2229,9 +2231,10 @@ static int dvb_register(struct cx23885_tsport *port) } port->i2c_client_tuner = client_tuner; break; - case CX23885_BOARD_HAUPPAUGE_HVR5525: { - struct m88rs6000t_config m88rs6000t_config; - struct a8293_platform_data a8293_pdata = {}; + case CX23885_BOARD_HAUPPAUGE_STARBURST2: + case CX23885_BOARD_HAUPPAUGE_HVR5525: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; switch (port->nr) { @@ -2240,7 +2243,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach frontend */ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, &hauppauge_hvr5525_m88ds3103_config, - &dev->i2c_bus[0].i2c_adap, &adapter); + &i2c_bus->i2c_adap, &adapter); if (fe0->dvb.frontend == NULL) break; @@ -2251,7 +2254,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x0b; info.platform_data = &a8293_pdata; request_module("a8293"); - client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); if (!client_sec || !client_sec->dev.driver) goto frontend_detach; if (!try_module_get(client_sec->dev.driver->owner)) { @@ -2293,7 +2296,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x64; info.platform_data = &si2168_config; request_module("%s", info.type); - client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); if (!client_demod || !client_demod->dev.driver) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { @@ -2311,7 +2314,7 @@ static int dvb_register(struct cx23885_tsport *port) info.addr = 0x60; info.platform_data = &si2157_config; request_module("%s", info.type); - client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + client_tuner = i2c_new_device(&i2c_bus2->i2c_adap, &info); if (!client_tuner || !client_tuner->dev.driver) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); @@ -2329,7 +2332,6 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - } case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: switch (port->nr) { /* port b - Terrestrial/cable */ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 7c7a1030f531..197fe64da46b 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -108,6 +108,7 @@ #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57 #define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58 +#define CX23885_BOARD_HAUPPAUGE_STARBURST2 59 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit From c00ba2c1230042e2c46f1466c20f395cab0d9b11 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 5 Jan 2018 19:48:22 -0500 Subject: media: cx23885: Add support for new Hauppauge QuadHD (885) Add new QuadHD digital only PCIe boards to driver list. Differentiate them from 888 digital/analog QuadHD models. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 42 ++++++++++++++++++++++--------- drivers/media/pci/cx23885/cx23885-core.c | 8 ++++++ drivers/media/pci/cx23885/cx23885-dvb.c | 6 +++++ drivers/media/pci/cx23885/cx23885.h | 2 ++ 4 files changed, 46 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 5208d6d0669e..831b066cdfe1 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -771,11 +771,21 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885] = { + .name = "Hauppauge WinTV-QuadHD-DVB(885)", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = { .name = "Hauppauge WinTV-QuadHD-ATSC", .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885] = { + .name = "Hauppauge WinTV-QuadHD-ATSC(885)", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = { .name = "Hauppauge WinTV-HVR-1265(161111)", .portc = CX23885_MPEG_DVB, @@ -1311,25 +1321,25 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 161111: /* WinTV-HVR-1265 K4 (PCIe, Analog/ATSC/QAM-B) */ break; - case 166100: + case 166100: /* 888 version, hybrid */ + case 166200: /* 885 version, DVB only */ /* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height, DVB-T/T2/C, DVB-T/T2/C */ break; - case 166101: + case 166101: /* 888 version, hybrid */ + case 166201: /* 885 version, DVB only */ /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, DVB-T/T2/C, DVB-T/T2/C */ break; - case 165100: - /* - * WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height, - * ATSC, ATSC - */ + case 165100: /* 888 version, hybrid */ + case 165200: /* 885 version, digital only */ + /* WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height, + * ATSC/QAM-B, ATSC/QAM-B */ break; - case 165101: - /* - * WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, - * ATSC, ATSC - */ + case 165101: /* 888 version, hybrid */ + case 165201: /* 885 version, digital only */ + /* WinTV-QuadHD (ATSC) Tuner Pair 2 (PCIe, IR, half height, + * ATSC/QAM-B, ATSC/QAM-B */ break; default: pr_warn("%s: warning: unknown hauppauge model #%d\n", @@ -1835,6 +1845,8 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) */ break; case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: /* * GPIO-08 TER1_RESN * GPIO-09 TER2_RESN @@ -2094,7 +2106,9 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_STARBURST2: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -2243,7 +2257,9 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -2301,6 +2317,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8f63df1cb418..8afddd6795aa 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -869,6 +869,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } + if (dev->pci->device == 0x8852) { + /* no DIF on cx23885, so no analog tuner support possible */ + if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) + dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885; + else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) + dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885; + } + /* If the user specific a clk freq override, apply it */ if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index f2b204ae08e5..7bb1febb1cb2 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2333,6 +2333,9 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: + pr_info("%s(): board=%d port=%d\n", __func__, + dev->board, port->nr); switch (port->nr) { /* port b - Terrestrial/cable */ case 1: @@ -2430,6 +2433,9 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: + pr_info("%s(): board=%d port=%d\n", __func__, + dev->board, port->nr); switch (port->nr) { /* port b - Terrestrial/cable */ case 1: diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 197fe64da46b..d54c7ee1ab21 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -109,6 +109,8 @@ #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57 #define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58 #define CX23885_BOARD_HAUPPAUGE_STARBURST2 59 +#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885 60 +#define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885 61 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit From 79d6e6e6581cc5397cb179dd2a442d18e423897a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 6 Jan 2018 11:03:27 -0500 Subject: media: exynos4-is: make array 'cmd' static, shrinks object size Don't populate the const read-only array 'cmd' on the stack but instead make it static. Makes the object code smaller by 38 bytes: Before: text data bss dec hex filename 4950 868 0 5818 16ba fimc-is-regs.o After: text data bss dec hex filename 4824 956 0 5780 1694 fimc-is-regs.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-regs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index cfe4406a83ff..e0e291066037 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -159,7 +159,7 @@ void fimc_is_hw_load_setfile(struct fimc_is *is) int fimc_is_hw_change_mode(struct fimc_is *is) { - const u8 cmd[] = { + static const u8 cmd[] = { HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO, HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, }; -- cgit From b312598dd48ddf22a0d144ca08b898da605a9f1f Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 8 Jan 2018 07:52:34 -0500 Subject: media: dibx000_common: use strlcpy() instead of strncpy() gcc-8 reports drivers/media/dvb-frontends/dibx000_common.c: In function 'i2c_adapter_init': ./include/linux/string.h:245:9: warning: '__builtin_strncpy' specified bound 48 equals destination size [-Wstringop-truncation] We need to use strlcpy() to make sure the dest string is nul-terminated. Signed-off-by: Xiongfeng Wang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dibx000_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c index d981233e458f..70119c79ac2b 100644 --- a/drivers/media/dvb-frontends/dibx000_common.c +++ b/drivers/media/dvb-frontends/dibx000_common.c @@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) { - strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); + strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->algo = algo; i2c_adap->algo_data = NULL; i2c_set_adapdata(i2c_adap, mst); -- cgit From c5bef50e52b2cdc8ee757220aae21083451f5f8d Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 9 Jan 2018 11:38:35 -0500 Subject: media: cx231xx: Add support for Hauppauge HVR-935C HVR-935C is hybrid PAL, DVB-C/T/T2 usb device. CX23102 + Si2168 + Si2157 Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 42 +++++++++++++++++ drivers/media/usb/cx231xx/cx231xx-dvb.c | 75 +++++++++++++++++++++++++++++++ drivers/media/usb/cx231xx/cx231xx.h | 1 + 3 files changed, 118 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index f9ec7fedcd5b..c2efbff9925c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -922,6 +922,45 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_HAUPPAUGE_935C] = { + .name = "Hauppauge WinTV-HVR-935C", + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = I2C_1_MUX_3, + .demod_i2c_master = I2C_1_MUX_3, + .has_dvb = 1, + .demod_addr = 0x64, /* 0xc8 >> 1 */ + .norm = V4L2_STD_PAL, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -953,6 +992,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb123), .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, + {USB_DEVICE(0x2040, 0xb151), + .driver_info = CX231XX_BOARD_HAUPPAUGE_935C}, {USB_DEVICE(0x2040, 0xb130), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb131), @@ -1211,6 +1252,7 @@ void cx231xx_card_setup(struct cx231xx *dev) case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_955Q: + case CX231XX_BOARD_HAUPPAUGE_935C: { struct eeprom { struct tveeprom tvee; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 4ec7da07c8d7..7127dd49201f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1068,6 +1068,81 @@ static int dvb_init(struct cx231xx *dev) &astrometa_t2hybrid_r820t_config); break; } + case CX231XX_BOARD_HAUPPAUGE_935C: + { + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_board_info info = {}; + struct si2157_config si2157_config = {}; + struct si2168_config si2168_config = {}; + + /* attach demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend; + si2168_config.i2c_adapter = &adapter; + si2168_config.ts_clock_inv = true; + + strlcpy(info.type, "si2168", sizeof(info.type)); + info.addr = dev->board.demod_addr; + info.platform_data = &si2168_config; + + request_module(info.type); + client = i2c_new_device(demod_i2c, &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = dev->board.tuner_addr; + info.platform_data = &si2157_config; + request_module("si2157"); + + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to obtain %s tuner.\n", info.type); + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dev->cx231xx_reset_analog_tuner = NULL; + dev->dvb->i2c_client_tuner = client; + break; + } default: dev_err(dev->dev, "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 65b039cf80be..1493192b3d15 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -81,6 +81,7 @@ #define CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD 23 #define CX231XX_BOARD_ASTROMETA_T2HYBRID 24 #define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25 +#define CX231XX_BOARD_HAUPPAUGE_935C 26 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 -- cgit From 19fbf1ba2e609e8bc6dad943de4e1314ca7c436d Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 9 Jan 2018 11:44:26 -0500 Subject: media: cx231xx: Add support for Hauppauge HVR-975 Hauppauge HVR-975 is hybrid NTSC/PAL, QAM/ATSC, and DVB-C/T/T2 usb device. Only ATSC/QAM front end is initially active. Second frontend support is work in progress. CX23102 + LG3306A/Si2168(WiP) + Si2157 Changes since v1: - removed double semicolon Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 42 ++++++++++++++++++ drivers/media/usb/cx231xx/cx231xx-dvb.c | 74 +++++++++++++++++++++++++++++++ drivers/media/usb/cx231xx/cx231xx.h | 1 + 3 files changed, 117 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index c2efbff9925c..8582568f0dcd 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -942,6 +942,45 @@ struct cx231xx_board cx231xx_boards[] = { .demod_addr = 0x64, /* 0xc8 >> 1 */ .norm = V4L2_STD_PAL, + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, + [CX231XX_BOARD_HAUPPAUGE_975] = { + .name = "Hauppauge WinTV-HVR-975", + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = I2C_1_MUX_3, + .demod_i2c_master = I2C_1_MUX_3, + .has_dvb = 1, + .demod_addr = 0x59, /* 0xb2 >> 1 */ + .norm = V4L2_STD_ALL, + .input = {{ .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, @@ -994,6 +1033,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, {USB_DEVICE(0x2040, 0xb151), .driver_info = CX231XX_BOARD_HAUPPAUGE_935C}, + {USB_DEVICE(0x2040, 0xb150), + .driver_info = CX231XX_BOARD_HAUPPAUGE_975}, {USB_DEVICE(0x2040, 0xb130), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb131), @@ -1253,6 +1294,7 @@ void cx231xx_card_setup(struct cx231xx *dev) case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: case CX231XX_BOARD_HAUPPAUGE_955Q: case CX231XX_BOARD_HAUPPAUGE_935C: + case CX231XX_BOARD_HAUPPAUGE_975: { struct eeprom { struct tveeprom tvee; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 7127dd49201f..2d2b7b5349c1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1143,6 +1143,80 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->i2c_client_tuner = client; break; } + case CX231XX_BOARD_HAUPPAUGE_975: + { + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_board_info info = {}; + struct si2157_config si2157_config = {}; + struct lgdt3306a_config lgdt3306a_config = {}; + + /* attach demodulator chip */ + lgdt3306a_config = hauppauge_955q_lgdt3306a_config; + lgdt3306a_config.fe = &dev->dvb->frontend; + lgdt3306a_config.i2c_adapter = &adapter; + + strlcpy(info.type, "lgdt3306a", sizeof(info.type)); + info.addr = dev->board.demod_addr; + info.platform_data = &lgdt3306a_config; + + request_module(info.type); + client = i2c_new_device(demod_i2c, &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = dev->board.tuner_addr; + info.platform_data = &si2157_config; + request_module("si2157"); + + client = i2c_new_device(tuner_i2c, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + dev_err(dev->dev, + "Failed to obtain %s tuner.\n", info.type); + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dev->cx231xx_reset_analog_tuner = NULL; + dev->dvb->i2c_client_tuner = client; + break; + } default: dev_err(dev->dev, "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 1493192b3d15..fa993f76bf59 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -82,6 +82,7 @@ #define CX231XX_BOARD_ASTROMETA_T2HYBRID 24 #define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25 #define CX231XX_BOARD_HAUPPAUGE_935C 26 +#define CX231XX_BOARD_HAUPPAUGE_975 27 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 -- cgit From c20ffbfe085ff3e3082e4987c2126a461bafbc6a Mon Sep 17 00:00:00 2001 From: Evgeny Plehov Date: Tue, 9 Jan 2018 18:33:38 -0500 Subject: media: dvb-usb-cxusb: Geniatech T230C support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f8585ce655e9cdeabc38e8e2580b05735110e4a5. The T230C is handled by the dvb-usb-v2/dvbsky.c driver, which should be preferred over a dvb-usb (v1) driver. Signed-off-by: Stefan Brüns Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 139 +------------------------------------- 1 file changed, 1 insertion(+), 138 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 2abd15c6df81..6387910976b4 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1243,82 +1243,6 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) return 0; } -static int cxusb_mygica_t230c_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap->dev; - struct cxusb_state *st = d->priv; - struct i2c_adapter *adapter; - struct i2c_client *client_demod; - struct i2c_client *client_tuner; - struct i2c_board_info info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* Select required USB configuration */ - if (usb_set_interface(d->udev, 0, 0) < 0) - err("set interface failed"); - - /* Unblock all USB pipes */ - usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - - /* attach frontend */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &adapter; - si2168_config.fe = &adap->fe_adap[0].fe; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - si2168_config.ts_clock_inv = 1; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2168", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2168_config; - request_module(info.type); - client_demod = i2c_new_device(&d->i2c_adap, &info); - if (client_demod == NULL || client_demod->dev.driver == NULL) - return -ENODEV; - - if (!try_module_get(client_demod->dev.driver->owner)) { - i2c_unregister_device(client_demod); - return -ENODEV; - } - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = adap->fe_adap[0].fe; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2141", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || client_tuner->dev.driver == NULL) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - if (!try_module_get(client_tuner->dev.driver->owner)) { - i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - return -ENODEV; - } - - st->i2c_client_demod = client_demod; - st->i2c_client_tuner = client_tuner; - - /* hook fe: need to resync the slave fifo when signal locks. */ - mutex_init(&st->stream_mutex); - st->last_lock = 0; - st->fe_read_status = adap->fe_adap[0].fe->ops.read_status; - adap->fe_adap[0].fe->ops.read_status = cxusb_read_status; - - return 0; -} - /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -1401,7 +1325,6 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties; static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; static struct dvb_usb_device_properties cxusb_mygica_t230_properties; -static struct dvb_usb_device_properties cxusb_mygica_t230c_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1434,8 +1357,6 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230c_properties, - THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -1487,7 +1408,6 @@ enum cxusb_table_index { CONEXANT_D680_DMB, MYGICA_D689, MYGICA_T230, - MYGICA_T230C, NR__cxusb_table_index }; @@ -1555,9 +1475,6 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { [MYGICA_T230] = { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) }, - [MYGICA_T230C] = { - USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230+1) - }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -2252,7 +2169,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { .rc.core = { .rc_interval = 100, - .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, + .rc_codes = RC_MAP_D680_DMB, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, .allowed_protos = RC_PROTO_BIT_UNKNOWN, @@ -2268,60 +2185,6 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { } }; -static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_mygica_t230c_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - } }, - }, - }, - - .power_ctrl = cxusb_d680_dmb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc.core = { - .rc_interval = 100, - .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, - .module_name = KBUILD_MODNAME, - .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_PROTO_BIT_UNKNOWN, - }, - - .num_device_descs = 1, - .devices = { - { - "Mygica T230C DVB-T/T2/C", - { NULL }, - { &cxusb_table[MYGICA_T230C], NULL }, - }, - } -}; - static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, -- cgit From 1bbab525b6f414ace53f56fc0a51d8f15dcbae78 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Tue, 9 Jan 2018 18:33:39 -0500 Subject: media: cxusb: restore RC_MAP for MyGica T230 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f8585ce655e9 ("[media] dvb-usb-cxusb: Geniatech T230C support") sneaked in an unrelated change for the older T230 (not C) model. As the commit was reverted this change was reverted too, although likely correct. Fixes: f8585ce655e9 ("[media] dvb-usb-cxusb: Geniatech T230C support") Signed-off-by: Stefan Brüns Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 6387910976b4..387a074ea6ec 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -2060,7 +2060,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { .rc.core = { .rc_interval = 100, - .rc_codes = RC_MAP_D680_DMB, + .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, .allowed_protos = RC_PROTO_BIT_UNKNOWN, -- cgit From bdaacc32e9b265946d76df3e98a90ae9508df4e4 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 12 Jan 2018 11:19:36 -0500 Subject: media: cx231xx: Add second frontend option Include ability to add a second dvb attach style frontend to cx231xx USB bridge. All current boards set to use frontend[0]. Changes are backwards compatible with current behaviour. [mchehab@s-opensource.com: fix some coding style issues] Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 173 ++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 76 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 2d2b7b5349c1..e81f2a4c81e9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -55,7 +55,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX231XX_DVB_MAX_PACKETS 64 struct cx231xx_dvb { - struct dvb_frontend *frontend; + struct dvb_frontend *frontend[2]; /* feed count management */ struct mutex lock; @@ -386,17 +386,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); cfg.i2c_addr = addr; - if (!dev->dvb->frontend) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n", dev->name); return -EINVAL; } - fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); + fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg); if (!fe) { dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; + dvb_frontend_detach(dev->dvb->frontend[0]); + dev->dvb->frontend[0] = NULL; return -EINVAL; } @@ -408,9 +408,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) { - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->set_analog_params != NULL) { struct analog_parameters params; @@ -421,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) /*params.audmode = ; */ /* Set the analog parameters to set the frequency */ - dops->set_analog_params(dev->dvb->frontend, ¶ms); + dops->set_analog_params(dev->dvb->frontend[0], ¶ms); } } @@ -433,15 +433,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev) { int status = 0; - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->init != NULL && !dev->xc_fw_load_done) { dev_dbg(dev->dev, "Reloading firmware for XC5000\n"); - status = dops->init(dev->dvb->frontend); + status = dops->init(dev->dvb->frontend[0]); if (status == 0) { dev->xc_fw_load_done = 1; dev_dbg(dev->dev, @@ -481,17 +481,29 @@ static int register_dvb(struct cx231xx_dvb *dvb, dvb_register_media_controller(&dvb->adapter, dev->media_dev); /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + if (dvb->frontend[1]) + dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; dvb->adapter.priv = dev; /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]); if (result < 0) { dev_warn(dev->dev, "%s: dvb_register_frontend failed (errno = %d)\n", dev->name, result); - goto fail_frontend; + goto fail_frontend0; + } + + if (dvb->frontend[1]) { + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]); + if (result < 0) { + dev_warn(dev->dev, + "%s: 2nd dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend1; + } } /* register demux stuff */ @@ -569,9 +581,14 @@ fail_fe_hw: fail_dmxdev: dvb_dmx_release(&dvb->demux); fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); +fail_frontend1: + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); +fail_frontend0: + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); fail_adapter: return result; @@ -585,8 +602,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); dvb_dmxdev_release(&dvb->dmxdev); dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); /* remove I2C tuner */ client = dvb->i2c_client_tuner; @@ -635,11 +656,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_CARRAERA: case CX231XX_BOARD_CNXT_RDE_250: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -647,9 +668,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rde250_tunerconfig)) { result = -EINVAL; @@ -660,11 +681,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_SHELBY: case CX231XX_BOARD_CNXT_RDU_250: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &xc5000_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -672,9 +693,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rdu250_tunerconfig)) { result = -EINVAL; @@ -683,11 +704,11 @@ static int dvb_init(struct cx231xx *dev) break; case CX231XX_BOARD_CNXT_RDE_253S: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -695,9 +716,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; @@ -707,11 +728,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &tda18271_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -719,9 +740,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; @@ -734,11 +755,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for tuner / demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(lgdt3305_attach, + dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach LG3305 front end\n"); result = -EINVAL; @@ -746,9 +767,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &hcw_tda18271_config); break; @@ -761,7 +782,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demod */ memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; + si2165_pdata.fe = &dev->dvb->frontend[0]; si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL; si2165_pdata.ref_freq_hz = 16000000; @@ -771,7 +792,7 @@ static int dvb_init(struct cx231xx *dev) info.platform_data = &si2165_pdata; request_module(info.type); client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { + if (!client || !client->dev.driver || !dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach SI2165 front end\n"); result = -EINVAL; @@ -786,12 +807,12 @@ static int dvb_init(struct cx231xx *dev) dvb->i2c_client_demod = client; - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &hcw_tda18271_config); @@ -808,7 +829,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demod */ memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; + si2165_pdata.fe = &dev->dvb->frontend[0]; si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT; si2165_pdata.ref_freq_hz = 24000000; @@ -818,7 +839,7 @@ static int dvb_init(struct cx231xx *dev) info.platform_data = &si2165_pdata; request_module(info.type); client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { + if (!client || !client->dev.driver || !dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach SI2165 front end\n"); result = -EINVAL; @@ -835,14 +856,14 @@ static int dvb_init(struct cx231xx *dev) memset(&info, 0, sizeof(struct i2c_board_info)); - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -857,14 +878,14 @@ static int dvb_init(struct cx231xx *dev) tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } @@ -882,26 +903,26 @@ static int dvb_init(struct cx231xx *dev) memset(&info, 0, sizeof(struct i2c_board_info)); - dev->dvb->frontend = dvb_attach(lgdt3306a_attach, + dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach, &hauppauge_955q_lgdt3306a_config, demod_i2c ); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach LGDT3306A frontend.\n"); result = -EINVAL; goto out_free; } - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -916,14 +937,14 @@ static int dvb_init(struct cx231xx *dev) tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + dvb_frontend_detach(dev->dvb->frontend[0]); result = -ENODEV; goto out_free; } @@ -940,11 +961,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(mb86a20s_attach, + dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach, &pv_mb86a20s_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach mb86a20s demod\n"); result = -EINVAL; @@ -952,9 +973,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], 0x60, tuner_i2c, &pv_tda18271_config); break; @@ -969,7 +990,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */ - si2168_config.fe = &dev->dvb->frontend; + si2168_config.fe = &dev->dvb->frontend[0]; si2168_config.i2c_adapter = &adapter; si2168_config.ts_clock_inv = true; @@ -994,7 +1015,7 @@ static int dvb_init(struct cx231xx *dev) dvb->i2c_client_demod = client; /* attach tuner chip */ - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -1037,7 +1058,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ mn88473_config.i2c_wr_max = 16; mn88473_config.xtal = 25000000; - mn88473_config.fe = &dev->dvb->frontend; + mn88473_config.fe = &dev->dvb->frontend[0]; strlcpy(info.type, "mn88473", sizeof(info.type)); info.addr = dev->board.demod_addr; @@ -1060,10 +1081,10 @@ static int dvb_init(struct cx231xx *dev) dvb->i2c_client_demod = client; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner chip */ - dvb_attach(r820t_attach, dev->dvb->frontend, + dvb_attach(r820t_attach, dev->dvb->frontend[0], tuner_i2c, &astrometa_t2hybrid_r820t_config); break; @@ -1078,7 +1099,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ si2168_config.ts_mode = SI2168_TS_SERIAL; - si2168_config.fe = &dev->dvb->frontend; + si2168_config.fe = &dev->dvb->frontend[0]; si2168_config.i2c_adapter = &adapter; si2168_config.ts_clock_inv = true; @@ -1102,13 +1123,13 @@ static int dvb_init(struct cx231xx *dev) } dvb->i2c_client_demod = client; - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -1153,7 +1174,7 @@ static int dvb_init(struct cx231xx *dev) /* attach demodulator chip */ lgdt3306a_config = hauppauge_955q_lgdt3306a_config; - lgdt3306a_config.fe = &dev->dvb->frontend; + lgdt3306a_config.fe = &dev->dvb->frontend[0]; lgdt3306a_config.i2c_adapter = &adapter; strlcpy(info.type, "lgdt3306a", sizeof(info.type)); @@ -1176,13 +1197,13 @@ static int dvb_init(struct cx231xx *dev) } dvb->i2c_client_demod = client; - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif @@ -1223,7 +1244,7 @@ static int dvb_init(struct cx231xx *dev) dev->name); break; } - if (NULL == dvb->frontend) { + if (!dvb->frontend[0]) { dev_err(dev->dev, "%s/2: frontend initialization failed\n", dev->name); result = -EINVAL; -- cgit From 2af04244342f03a4e82f376eea36ebfef82a30af Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 12 Jan 2018 11:19:37 -0500 Subject: media: cx231xx: Add second i2c demod client Include ability to add a i2c device style frontend to cx231xx USB bridge. All current boards set to use frontend[0]. Changes are backwards compatible with current behaviour. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 45 ++++++++++++++++++--------------- drivers/media/usb/cx231xx/cx231xx.h | 1 + 2 files changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index e81f2a4c81e9..63deca9b5017 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -68,7 +68,7 @@ struct cx231xx_dvb { struct dmx_frontend fe_hw; struct dmx_frontend fe_mem; struct dvb_net net; - struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_demod[2]; struct i2c_client *i2c_client_tuner; }; @@ -616,7 +616,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) i2c_unregister_device(client); } /* remove I2C demod */ - client = dvb->i2c_client_demod; + client = dvb->i2c_client_demod[1]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + client = dvb->i2c_client_demod[0]; if (client) { module_put(client->dev.driver->owner); i2c_unregister_device(client); @@ -805,7 +810,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; @@ -852,7 +857,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; memset(&info, 0, sizeof(struct i2c_board_info)); @@ -1012,7 +1017,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; /* attach tuner chip */ si2157_config.fe = dev->dvb->frontend[0]; @@ -1031,16 +1036,16 @@ static int dvb_init(struct cx231xx *dev) client = i2c_new_device(tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } @@ -1078,7 +1083,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; /* define general-purpose callback pointer */ dvb->frontend[0]->callback = cx231xx_tuner_callback; @@ -1122,7 +1127,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ @@ -1144,8 +1149,8 @@ static int dvb_init(struct cx231xx *dev) client = i2c_new_device(adapter, &info); if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } @@ -1154,8 +1159,8 @@ static int dvb_init(struct cx231xx *dev) dev_err(dev->dev, "Failed to obtain %s tuner.\n", info.type); i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } @@ -1196,7 +1201,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ @@ -1218,8 +1223,8 @@ static int dvb_init(struct cx231xx *dev) client = i2c_new_device(tuner_i2c, &info); if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } @@ -1228,8 +1233,8 @@ static int dvb_init(struct cx231xx *dev) dev_err(dev->dev, "Failed to obtain %s tuner.\n", info.type); i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; goto out_free; } diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index fa993f76bf59..6ffa4bd96484 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -345,6 +345,7 @@ struct cx231xx_board { /* demod related */ int demod_addr; + int demod_addr2; u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */ /* GPIO Pins */ -- cgit From 445877742ce302979fd92bcda1eb372bb708c003 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 12 Jan 2018 11:19:39 -0500 Subject: media: si2168: Add ts bus coontrol, turn off bus on sleep Includes a function to set TS MODE property os si2168. The function either disables the TS output bus, or sets mode to config option. When going to sleep the TS bus is turned off, this makes the driver compatible with multiple frontend usage. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 38 ++++++++++++++++++++++++++++-------- drivers/media/dvb-frontends/si2168.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 539399dac551..429c03aaa902 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -409,6 +409,30 @@ err: return ret; } +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + struct si2168_cmd cmd; + int ret = 0; + + dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + + /* set TS_MODE property */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + if (acquire) + cmd.args[4] |= dev->ts_mode; + else + cmd.args[4] |= SI2168_TS_TRISTATE; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + + return ret; +} + static int si2168_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; @@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe) dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); - /* set ts mode */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - cmd.args[4] |= dev->ts_mode; - if (dev->ts_clock_gapped) - cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); + ret = si2168_ts_bus_ctrl(fe, 1); if (ret) goto err; @@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; + /* tri-state data bus */ + si2168_ts_bus_ctrl(fe, 0); + /* Firmware B 4.0-11 or later loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; @@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = { .init = si2168_init, .sleep = si2168_sleep, + .ts_bus_ctrl = si2168_ts_bus_ctrl, + .set_frontend = si2168_set_frontend, .read_status = si2168_read_status, diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3225d0cc93c7..f48f0fb0ad69 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -38,6 +38,7 @@ struct si2168_config { /* TS mode */ #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 +#define SI2168_TS_TRISTATE 0x00 u8 ts_mode; /* TS clock inverted */ -- cgit From e7f4d7516aa3ed912946fdf3863be8d1489fd836 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 12 Jan 2018 11:19:41 -0500 Subject: media: lgdt3306a: Announce successful creation The driver is near silent, this adds a simple announcement at the end of probe after the chip has been detected and upgrades a debug message to error if probe has failed. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 0ed64604d7af..5b1903358730 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -2249,6 +2249,8 @@ static int lgdt3306a_probe(struct i2c_client *client, *config->i2c_adapter = state->muxc->adapter[0]; *config->fe = fe; + dev_info(&client->dev, "LG Electronics LGDT3306A successfully identified\n"); + return 0; err_kfree: @@ -2256,7 +2258,7 @@ err_kfree: err_fe: kfree(config); fail: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } -- cgit From 3061df060fcaeebd77e183283f70fdc4349eef83 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 12 Jan 2018 11:19:40 -0500 Subject: media: si2168: Announce frontend creation failure The driver outputs on success, but is silent on failure. Give one message that probe failed. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 429c03aaa902..c1a638c8565d 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -810,7 +810,7 @@ static int si2168_probe(struct i2c_client *client, err_kfree: kfree(dev); err: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } -- cgit From a398e043637a4819a0e96467bfecaabf3224dd62 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Jan 2018 16:52:15 -0500 Subject: media: s3c-camif: fix out-of-bounds array access While experimenting with older compiler versions, I ran into a warning that no longer shows up on gcc-4.8 or newer: drivers/media/platform/s3c-camif/camif-capture.c: In function '__camif_subdev_try_format': drivers/media/platform/s3c-camif/camif-capture.c:1265:25: error: array subscript is below array bounds This is an off-by-one bug, leading to an access before the start of the array, while newer compilers silently assume this undefined behavior cannot happen and leave the loop at index 0 if no other entry matches. As Sylvester explains, we actually need to ensure that the value is within the range, so this reworks the loop to be easier to parse correctly, and an additional check to fall back on the first format value for any unexpected input. I found an existing gcc bug for it and added a reduced version of the function there. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69249#c3 Fixes: babde1c243b2 ("[media] V4L: Add driver for S3C24XX/S3C64XX SoC series camera interface") Signed-off-by: Arnd Bergmann Reviewed-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-capture.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 437395a61065..9ab8e7ee2e1e 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, -- cgit From d4c779bc91d1faef76351ccd6d326f729cdfcb1e Mon Sep 17 00:00:00 2001 From: Brad Love Date: Wed, 17 Jan 2018 17:31:58 -0500 Subject: media: si2168: Add spectrum inversion property Some tuners produce inverted spectrum, but the si2168 is not currently set up to accept it. This adds an optional parameter to set the frontend up to receive inverted spectrum. Parameter is optional and only boards who enable inversion will utilize this. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 3 +++ drivers/media/dvb-frontends/si2168.h | 3 +++ drivers/media/dvb-frontends/si2168_priv.h | 1 + 3 files changed, 7 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index c1a638c8565d..282dc92cb102 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -339,6 +339,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; + if (dev->spectral_inversion) + cmd.args[5] |= 1; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); @@ -798,6 +800,7 @@ static int si2168_probe(struct i2c_client *client, dev->ts_mode = config->ts_mode; dev->ts_clock_inv = config->ts_clock_inv; dev->ts_clock_gapped = config->ts_clock_gapped; + dev->spectral_inversion = config->spectral_inversion; dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n", dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index f48f0fb0ad69..d519edd26c21 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -46,6 +46,9 @@ struct si2168_config { /* TS clock gapped */ bool ts_clock_gapped; + + /* Inverted spectrum */ + bool spectral_inversion; }; #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 3c8746a20038..2d362e162ade 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -48,6 +48,7 @@ struct si2168_dev { u8 ts_mode; bool ts_clock_inv; bool ts_clock_gapped; + bool spectral_inversion; }; /* firmware command struct */ -- cgit From 309d4c4cc989312a660c77a45b304710825f1ff7 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Wed, 17 Jan 2018 16:32:36 -0500 Subject: media: em28xx: Enable inversion for Solo/Dual HD DVB models Hauppauge Solo/Dual HD DVB models use a si2157 tuner, which is set to produce inverted spectrum. This configures the si2168 DVB demod for inverted spectrum on both affected models. [mchehab@s-opensource.com: rebased on the top of upstream] Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9bf781f9b93f..a54cb8dc52c9 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1227,6 +1227,7 @@ static int em28178_dvb_init_pctv_292e(struct em28xx *dev) si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + si2168_config.spectral_inversion = true; dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, &dev->i2c_adap[dev->def_i2c_bus], @@ -1331,6 +1332,7 @@ static int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev) si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.spectral_inversion = true; addr = (dev->ts == PRIMARY_TS) ? 0x64 : 0x67; dvb->i2c_client_demod = dvb_module_probe("si2168", NULL, -- cgit From 8f0aa38292f212a74cb37026d160d946602e76f2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 19 Jan 2018 08:34:34 -0500 Subject: media: v4l: omap_vout: vrfb: Use the wrapper for prep_interleaved_dma() Instead of directly accessing to dmadev->device_prep_interleaved_dma() use the dmaengine_prep_interleaved_dma() wrapper instead. Signed-off-by: Peter Ujfalusi Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout_vrfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 123c2b26a933..72c0ac2cbf3d 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -271,7 +271,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, xt->dst_sgl = true; xt->dst_inc = true; - tx = dmadev->device_prep_interleaved_dma(chan, xt, flags); + tx = dmaengine_prep_interleaved_dma(chan, xt, flags); if (tx == NULL) { pr_err("%s: DMA interleaved prep error\n", __func__); return -EINVAL; -- cgit From bd0b5a35aac5315cf4f6d296dee2f23fb28b827d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jan 2018 09:15:25 -0500 Subject: media: sr030pc30: prevent array underflow in try_fmt() Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/sr030pc30.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index 0bf031b7e4fa..2a4882cddc51 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -511,13 +511,16 @@ static int sr030pc30_get_fmt(struct v4l2_subdev *sd, static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - int i = ARRAY_SIZE(sr030pc30_formats); + int i; sr030pc30_try_frame_size(mf); - while (i--) + for (i = 0; i < ARRAY_SIZE(sr030pc30_formats); i++) { if (mf->code == sr030pc30_formats[i].code) break; + } + if (i == ARRAY_SIZE(sr030pc30_formats)) + i = 0; mf->code = sr030pc30_formats[i].code; -- cgit From 948aaf788f876bea7764291f5b391165577a632b Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 26 Jan 2018 15:14:05 -0500 Subject: media: drx-j remove bsp_i2c.h bsp_i2c.h is unused since commit ffe7c4f92183 ("[media] drx-j: Get rid of drx39xyj/bsp_tuner.h") Remove it from tree. Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h | 139 ------------------------- 1 file changed, 139 deletions(-) delete mode 100644 drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h b/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h deleted file mode 100644 index 2b3af247a1f1..000000000000 --- a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - I2C API, implementation depends on board specifics - - Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Trident Microsystems nor Hauppauge Computer Works - nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - This module encapsulates I2C access.In some applications several devices - share one I2C bus. If these devices have the same I2C address some kind - off "switch" must be implemented to ensure error free communication with - one device. In case such a "switch" is used, the device ID can be used - to implement control over this "switch". -*/ - -#ifndef __BSPI2C_H__ -#define __BSPI2C_H__ - -#include "bsp_types.h" - -/* - * This structure contains the I2C address, the device ID and a user_data pointer. - * The user_data pointer can be used for application specific purposes. - */ -struct i2c_device_addr { - u16 i2c_addr; /* The I2C address of the device. */ - u16 i2c_dev_id; /* The device identifier. */ - void *user_data; /* User data pointer */ -}; - - -/* -* \def IS_I2C_10BIT( addr ) -* \brief Determine if I2C address 'addr' is a 10 bits address or not. -* \param addr The I2C address. -* \return int. -* \retval 0 if address is not a 10 bits I2C address. -* \retval 1 if address is a 10 bits I2C address. -*/ -#define IS_I2C_10BIT(addr) \ - (((addr) & 0xF8) == 0xF0) - -/*------------------------------------------------------------------------------ -Exported FUNCTIONS -------------------------------------------------------------------------------*/ - -/* -* \fn drxbsp_i2c_init() -* \brief Initialize I2C communication module. -* \return drx_status_t Return status. -* \retval 0 Initialization successful. -* \retval -EIO Initialization failed. -*/ - drx_status_t drxbsp_i2c_init(void); - -/* -* \fn drxbsp_i2c_term() -* \brief Terminate I2C communication module. -* \return drx_status_t Return status. -* \retval 0 Termination successful. -* \retval -EIO Termination failed. -*/ - drx_status_t drxbsp_i2c_term(void); - -/* -* \fn drx_status_t drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr, -* u16 w_count, -* u8 *wData, -* struct i2c_device_addr *r_dev_addr, -* u16 r_count, -* u8 *r_data) -* \brief Read and/or write count bytes from I2C bus, store them in data[]. -* \param w_dev_addr The device i2c address and the device ID to write to -* \param w_count The number of bytes to write -* \param wData The array to write the data to -* \param r_dev_addr The device i2c address and the device ID to read from -* \param r_count The number of bytes to read -* \param r_data The array to read the data from -* \return drx_status_t Return status. -* \retval 0 Succes. -* \retval -EIO Failure. -* \retval -EINVAL Parameter 'wcount' is not zero but parameter -* 'wdata' contains NULL. -* Idem for 'rcount' and 'rdata'. -* Both w_dev_addr and r_dev_addr are NULL. -* -* This function must implement an atomic write and/or read action on the I2C bus -* No other process may use the I2C bus when this function is executing. -* The critical section of this function runs from and including the I2C -* write, up to and including the I2C read action. -* -* The device ID can be useful if several devices share an I2C address. -* It can be used to control a "switch" on the I2C bus to the correct device. -*/ - drx_status_t drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr, - u16 w_count, - u8 *w_data, - struct i2c_device_addr *r_dev_addr, - u16 r_count, u8 *r_data); - -/* -* \fn drxbsp_i2c_error_text() -* \brief Returns a human readable error. -* Counter part of numerical drx_i2c_error_g. -* -* \return char* Pointer to human readable error text. -*/ - char *drxbsp_i2c_error_text(void); - -/* -* \var drx_i2c_error_g; -* \brief I2C specific error codes, platform dependent. -*/ - extern int drx_i2c_error_g; - -#endif /* __BSPI2C_H__ */ -- cgit From 16532baa6ba4add370bcbf1673d7d2e35526085d Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Sun, 28 Jan 2018 15:06:18 -0500 Subject: media: mantis: remove mantis_vp3028.c/mantis_vp3028.h Thoses files are unused since commit b3b961448f70 ("V4L/DVB (13795): [Mantis/Hopper] Code overhaul, add Hopper devices into the PCI ID list") 8 year after, we could remove it. Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/mantis/mantis_vp3028.c | 38 -------------------------------- drivers/media/pci/mantis/mantis_vp3028.h | 33 --------------------------- 2 files changed, 71 deletions(-) delete mode 100644 drivers/media/pci/mantis/mantis_vp3028.c delete mode 100644 drivers/media/pci/mantis/mantis_vp3028.h (limited to 'drivers/media') diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c deleted file mode 100644 index 4155c838a18a..000000000000 --- a/drivers/media/pci/mantis/mantis_vp3028.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "mantis_common.h" -#include "mantis_vp3028.h" - -struct zl10353_config mantis_vp3028_config = { - .demod_address = 0x0f, -}; - -#define MANTIS_MODEL_NAME "VP-3028" -#define MANTIS_DEV_TYPE "DVB-T" - -struct mantis_hwconfig vp3028_mantis_config = { - .model_name = MANTIS_MODEL_NAME, - .dev_type = MANTIS_DEV_TYPE, - .ts_size = MANTIS_TS_188, - .baud_rate = MANTIS_BAUD_9600, - .parity = MANTIS_PARITY_NONE, - .bytes = 0, -}; diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h deleted file mode 100644 index 34130d29e0aa..000000000000 --- a/drivers/media/pci/mantis/mantis_vp3028.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Mantis VP-3028 driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __MANTIS_VP3028_H -#define __MANTIS_VP3028_H - -#include -#include "mantis_common.h" -#include "zl10353.h" - -#define MANTIS_VP_3028_DVB_T 0x0028 - -extern struct zl10353_config mantis_vp3028_config; -extern struct mantis_hwconfig vp3028_mantis_config; - -#endif /* __MANTIS_VP3028_H */ -- cgit From 2f4a75b70bb113f549cfc38be6a9679178b28ac6 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Sun, 4 Feb 2018 20:21:29 -0500 Subject: media: sec: Remove PLAT_S5P dependency The PLAT_S5P symbol was removed in commit d78c16ccde96 ("ARM: SAMSUNG: Remove remaining legacy code"). Remove the PLAT_S5P dependency from VIDEO_SAMSUNG_S5P_CEC. Discovered with the https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py script. Signed-off-by: Ulf Magnusson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f9cc0582c8a9..5d8fd71fc454 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -591,7 +591,7 @@ config CEC_GPIO config VIDEO_SAMSUNG_S5P_CEC tristate "Samsung S5P CEC driver" - depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on ARCH_EXYNOS || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER ---help--- -- cgit From e2ce49468a14d5c1543bfd60385ff47b8aebfb0c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Feb 2018 15:10:00 -0500 Subject: media: v4l: dvb-frontends: stb0899: fix comparison to bitshift when dealing with a mask Due to a typo, the mask was destroyed by a comparison instead of a bit shift. Signed-off-by: Wolfram Sang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stb0899_reg.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stb0899_reg.h b/drivers/media/dvb-frontends/stb0899_reg.h index ba1ed56304a0..f564269249a6 100644 --- a/drivers/media/dvb-frontends/stb0899_reg.h +++ b/drivers/media/dvb-frontends/stb0899_reg.h @@ -374,22 +374,22 @@ #define STB0899_OFF0_IF_AGC_GAIN 0xf30c #define STB0899_BASE_IF_AGC_GAIN 0x00000000 -#define STB0899_IF_AGC_GAIN (0x3fff < 0) +#define STB0899_IF_AGC_GAIN (0x3fff << 0) #define STB0899_OFFST_IF_AGC_GAIN 0 #define STB0899_WIDTH_IF_AGC_GAIN 14 #define STB0899_OFF0_BB_AGC_GAIN 0xf310 #define STB0899_BASE_BB_AGC_GAIN 0x00000000 -#define STB0899_BB_AGC_GAIN (0x3fff < 0) +#define STB0899_BB_AGC_GAIN (0x3fff << 0) #define STB0899_OFFST_BB_AGC_GAIN 0 #define STB0899_WIDTH_BB_AGC_GAIN 14 #define STB0899_OFF0_DC_OFFSET 0xf314 #define STB0899_BASE_DC_OFFSET 0x00000000 -#define STB0899_I (0xff < 8) +#define STB0899_I (0xff << 8) #define STB0899_OFFST_I 8 #define STB0899_WIDTH_I 8 -#define STB0899_Q (0xff < 0) +#define STB0899_Q (0xff << 0) #define STB0899_OFFST_Q 8 #define STB0899_WIDTH_Q 8 -- cgit From 9403f089bfa0536dbad1a28419aff037dc575c3d Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Thu, 8 Feb 2018 14:53:12 -0500 Subject: media: ddbridge/ci: further deduplicate code/logic in ddb_ci_attach() Deduplicate the checks for a valid ptr in port->en, and also handle the default case to also catch eventually yet unsupported CI hardware. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-ci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 5828111487b0..ed19890710d6 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -325,24 +325,20 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) case DDB_CI_EXTERNAL_SONY: cxd_cfg.bitrate = bitrate; port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) - return -ENODEV; break; - case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); - if (!port->en) - return -ENODEV; break; - case DDB_CI_INTERNAL: ci_attach(port); - if (!port->en) - return -ENODEV; break; + default: + return -ENODEV; } + if (!port->en) + return -ENODEV; dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); return 0; } -- cgit From d19e3a72a6cec187a35aed9abf03fc4730eded76 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Thu, 8 Feb 2018 14:53:15 -0500 Subject: media: ngene: adapt cxd2099 attach to the new i2c_client way Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-core.c | 41 ++++++++++++++++++++++++++++++++---- drivers/media/pci/ngene/ngene.h | 1 + 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 8c92cb7f7e72..80db777cb7ec 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1562,9 +1562,8 @@ static int init_channels(struct ngene *dev) return 0; } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 62000, - .adr = 0x40, .polarity = 0, .clock_mode = 0, }; @@ -1572,18 +1571,52 @@ static struct cxd2099_cfg cxd_cfg = { static void cxd_attach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.en = &ci->en; + + request_module(board_info.type); + + client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!ci->en) + goto err_i2c; - ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); ci->dev = dev; + dev->channel[0].i2c_client[0] = client; + return; + +err_i2c: + i2c_unregister_device(client); +err_ret: + printk(KERN_ERR DEVICE_NAME ": CXD2099AR attach failed\n"); return; } static void cxd_detach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct i2c_client *client; dvb_ca_en50221_release(ci->en); - kfree(ci->en); + + client = dev->channel[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + ci->en = NULL; } diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 02dbd18f92d0..caf8602c7459 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -630,6 +630,7 @@ struct ngene_vopen { struct ngene_channel { struct device device; struct i2c_adapter i2c_adapter; + struct i2c_client *i2c_client[1]; struct ngene *dev; int number; -- cgit From 15f757bb5ab237a123a2d5a8140cece1bc7bb617 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Thu, 8 Feb 2018 14:53:17 -0500 Subject: media: cxd2099: move driver out of staging into dvb-frontends According to the TODO file, this driver only landed in staging because of the way device nodes and data transfers are handled. Besides that this way (use of secX devices) has become sort of standard to date (ie. VDR supports this literally since ages via the ddci plugin, TVHeadend received this functionality lately, and minisatip being currently worked on regarding this), most importantly this I2C client only driver isn't even responsible for setting up device nodes, not for handling data transfer and so on, but only serves as interface for the dvb_ca_en50221 subsystem, just like every other DVB card out in the wild, with hard-wired or such flexible CA interfaces. And, it would even work with cards having the cxd2099 controller hard-wired. Also, this driver received quite some love and even is a proper I2C client driver by now. So, as this driver acts as a EN50221 frontend device, move it to dvb-frontends. There is no need to keep it buried in staging. This commit also updates all affected Kconfig and Makefile's, and adds MEDIA_AUTOSELECT depends to ddbridge and ngene. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 12 + drivers/media/dvb-frontends/Makefile | 1 + drivers/media/dvb-frontends/cxd2099.c | 704 ++++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/cxd2099.h | 42 ++ drivers/media/pci/ddbridge/Kconfig | 1 + drivers/media/pci/ddbridge/Makefile | 3 - drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/Makefile | 3 - 8 files changed, 761 insertions(+), 6 deletions(-) create mode 100644 drivers/media/dvb-frontends/cxd2099.c create mode 100644 drivers/media/dvb-frontends/cxd2099.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index d17722eb4456..ca8c7ed079dd 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -904,6 +904,18 @@ config DVB_HELENE help Say Y when you want to support this frontend. +comment "Common Interface (EN50221) controller drivers" + depends on DVB_CORE + +config DVB_CXD2099 + tristate "CXD2099AR Common Interface driver" + depends on DVB_CORE && I2C + ---help--- + A driver for the CI controller currently found mostly on + Digital Devices DuoFlex CI (single) addon modules. + + Say Y when you want to support these devices. + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 4be59fed4536..abbd76ede540 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -129,3 +129,4 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o obj-$(CONFIG_DVB_HELENE) += helene.o obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o +obj-$(CONFIG_DVB_CXD2099) += cxd2099.o diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c new file mode 100644 index 000000000000..c0a5849b76bb --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2099.c @@ -0,0 +1,704 @@ +/* + * cxd2099.c: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010-2013 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxd2099.h" + +static int buffermode; +module_param(buffermode, int, 0444); +MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)"); + +static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); + +struct cxd { + struct dvb_ca_en50221 en; + + struct cxd2099_cfg cfg; + struct i2c_client *client; + struct regmap *regmap; + + u8 regs[0x23]; + u8 lastaddress; + u8 clk_reg_f; + u8 clk_reg_b; + int mode; + int ready; + int dr; + int write_busy; + int slot_stat; + + u8 amem[1024]; + int amem_read; + + int cammode; + struct mutex lock; /* device access lock */ + + u8 rbuf[1028]; + u8 wbuf[1028]; +}; + +static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) +{ + int status = 0; + + if (ci->lastaddress != adr) + status = regmap_write(ci->regmap, 0, adr); + if (!status) { + ci->lastaddress = adr; + + while (n) { + int len = n; + + if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) + len = ci->cfg.max_i2c; + status = regmap_raw_read(ci->regmap, 1, data, len); + if (status) + return status; + data += len; + n -= len; + } + } + return status; +} + +static int read_reg(struct cxd *ci, u8 reg, u8 *val) +{ + return read_block(ci, reg, val, 1); +} + +static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[2] = {address & 0xff, address >> 8}; + + status = regmap_raw_write(ci->regmap, 2, addr, 2); + if (!status) + status = regmap_raw_read(ci->regmap, 3, data, n); + return status; +} + +static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[2] = {address & 0xff, address >> 8}; + + status = regmap_raw_write(ci->regmap, 2, addr, 2); + if (!status) { + u8 buf[256]; + + memcpy(buf, data, n); + status = regmap_raw_write(ci->regmap, 3, buf, n); + } + return status; +} + +static int read_io(struct cxd *ci, u16 address, unsigned int *val) +{ + int status; + u8 addr[2] = {address & 0xff, address >> 8}; + + status = regmap_raw_write(ci->regmap, 2, addr, 2); + if (!status) + status = regmap_read(ci->regmap, 3, val); + return status; +} + +static int write_io(struct cxd *ci, u16 address, u8 val) +{ + int status; + u8 addr[2] = {address & 0xff, address >> 8}; + + status = regmap_raw_write(ci->regmap, 2, addr, 2); + if (!status) + status = regmap_write(ci->regmap, 3, val); + return status; +} + +static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) +{ + int status = 0; + unsigned int regval; + + if (ci->lastaddress != reg) + status = regmap_write(ci->regmap, 0, reg); + if (!status && reg >= 6 && reg <= 8 && mask != 0xff) { + status = regmap_read(ci->regmap, 1, ®val); + ci->regs[reg] = regval; + } + ci->lastaddress = reg; + ci->regs[reg] = (ci->regs[reg] & (~mask)) | val; + if (!status) + status = regmap_write(ci->regmap, 1, ci->regs[reg]); + if (reg == 0x20) + ci->regs[reg] &= 0x7f; + return status; +} + +static int write_reg(struct cxd *ci, u8 reg, u8 val) +{ + return write_regm(ci, reg, val, 0xff); +} + +static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) +{ + int status = 0; + u8 *buf = ci->wbuf; + + if (ci->lastaddress != adr) + status = regmap_write(ci->regmap, 0, adr); + if (status) + return status; + + ci->lastaddress = adr; + while (n) { + int len = n; + + if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c)) + len = ci->cfg.max_i2c - 1; + memcpy(buf, data, len); + status = regmap_raw_write(ci->regmap, 1, buf, len); + if (status) + return status; + n -= len; + data += len; + } + return status; +} + +static void set_mode(struct cxd *ci, int mode) +{ + if (mode == ci->mode) + return; + + switch (mode) { + case 0x00: /* IO mem */ + write_regm(ci, 0x06, 0x00, 0x07); + break; + case 0x01: /* ATT mem */ + write_regm(ci, 0x06, 0x02, 0x07); + break; + default: + break; + } + ci->mode = mode; +} + +static void cam_mode(struct cxd *ci, int mode) +{ + u8 dummy; + + if (mode == ci->cammode) + return; + + switch (mode) { + case 0x00: + write_regm(ci, 0x20, 0x80, 0x80); + break; + case 0x01: + if (!ci->en.read_data) + return; + ci->write_busy = 0; + dev_info(&ci->client->dev, "enable cam buffer mode\n"); + write_reg(ci, 0x0d, 0x00); + write_reg(ci, 0x0e, 0x01); + write_regm(ci, 0x08, 0x40, 0x40); + read_reg(ci, 0x12, &dummy); + write_regm(ci, 0x08, 0x80, 0x80); + break; + default: + break; + } + ci->cammode = mode; +} + +static int init(struct cxd *ci) +{ + int status; + + mutex_lock(&ci->lock); + ci->mode = -1; + do { + status = write_reg(ci, 0x00, 0x00); + if (status < 0) + break; + status = write_reg(ci, 0x01, 0x00); + if (status < 0) + break; + status = write_reg(ci, 0x02, 0x10); + if (status < 0) + break; + status = write_reg(ci, 0x03, 0x00); + if (status < 0) + break; + status = write_reg(ci, 0x05, 0xFF); + if (status < 0) + break; + status = write_reg(ci, 0x06, 0x1F); + if (status < 0) + break; + status = write_reg(ci, 0x07, 0x1F); + if (status < 0) + break; + status = write_reg(ci, 0x08, 0x28); + if (status < 0) + break; + status = write_reg(ci, 0x14, 0x20); + if (status < 0) + break; + + /* TOSTRT = 8, Mode B (gated clock), falling Edge, + * Serial, POL=HIGH, MSB + */ + status = write_reg(ci, 0x0A, 0xA7); + if (status < 0) + break; + + status = write_reg(ci, 0x0B, 0x33); + if (status < 0) + break; + status = write_reg(ci, 0x0C, 0x33); + if (status < 0) + break; + + status = write_regm(ci, 0x14, 0x00, 0x0F); + if (status < 0) + break; + status = write_reg(ci, 0x15, ci->clk_reg_b); + if (status < 0) + break; + status = write_regm(ci, 0x16, 0x00, 0x0F); + if (status < 0) + break; + status = write_reg(ci, 0x17, ci->clk_reg_f); + if (status < 0) + break; + + if (ci->cfg.clock_mode == 2) { + /* bitrate*2^13/ 72000 */ + u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000; + + if (ci->cfg.polarity) { + status = write_reg(ci, 0x09, 0x6f); + if (status < 0) + break; + } else { + status = write_reg(ci, 0x09, 0x6d); + if (status < 0) + break; + } + status = write_reg(ci, 0x20, 0x08); + if (status < 0) + break; + status = write_reg(ci, 0x21, (reg >> 8) & 0xff); + if (status < 0) + break; + status = write_reg(ci, 0x22, reg & 0xff); + if (status < 0) + break; + } else if (ci->cfg.clock_mode == 1) { + if (ci->cfg.polarity) { + status = write_reg(ci, 0x09, 0x6f); /* D */ + if (status < 0) + break; + } else { + status = write_reg(ci, 0x09, 0x6d); + if (status < 0) + break; + } + status = write_reg(ci, 0x20, 0x68); + if (status < 0) + break; + status = write_reg(ci, 0x21, 0x00); + if (status < 0) + break; + status = write_reg(ci, 0x22, 0x02); + if (status < 0) + break; + } else { + if (ci->cfg.polarity) { + status = write_reg(ci, 0x09, 0x4f); /* C */ + if (status < 0) + break; + } else { + status = write_reg(ci, 0x09, 0x4d); + if (status < 0) + break; + } + status = write_reg(ci, 0x20, 0x28); + if (status < 0) + break; + status = write_reg(ci, 0x21, 0x00); + if (status < 0) + break; + status = write_reg(ci, 0x22, 0x07); + if (status < 0) + break; + } + + status = write_regm(ci, 0x20, 0x80, 0x80); + if (status < 0) + break; + status = write_regm(ci, 0x03, 0x02, 0x02); + if (status < 0) + break; + status = write_reg(ci, 0x01, 0x04); + if (status < 0) + break; + status = write_reg(ci, 0x00, 0x31); + if (status < 0) + break; + + /* Put TS in bypass */ + status = write_regm(ci, 0x09, 0x08, 0x08); + if (status < 0) + break; + ci->cammode = -1; + cam_mode(ci, 0); + } while (0); + mutex_unlock(&ci->lock); + + return 0; +} + +static int read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + struct cxd *ci = ca->data; + u8 val; + + mutex_lock(&ci->lock); + set_mode(ci, 1); + read_pccard(ci, address, &val, 1); + mutex_unlock(&ci->lock); + return val; +} + +static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 1); + write_pccard(ci, address, &value, 1); + mutex_unlock(&ci->lock); + return 0; +} + +static int read_cam_control(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + struct cxd *ci = ca->data; + unsigned int val; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + read_io(ci, address, &val); + mutex_unlock(&ci->lock); + return val; +} + +static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + write_io(ci, address, value); + mutex_unlock(&ci->lock); + return 0; +} + +static int slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + if (ci->cammode) + read_data(ca, slot, ci->rbuf, 0); + + mutex_lock(&ci->lock); + cam_mode(ci, 0); + write_reg(ci, 0x00, 0x21); + write_reg(ci, 0x06, 0x1F); + write_reg(ci, 0x00, 0x31); + write_regm(ci, 0x20, 0x80, 0x80); + write_reg(ci, 0x03, 0x02); + ci->ready = 0; + ci->mode = -1; + { + int i; + + for (i = 0; i < 100; i++) { + usleep_range(10000, 11000); + if (ci->ready) + break; + } + } + mutex_unlock(&ci->lock); + return 0; +} + +static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + dev_dbg(&ci->client->dev, "%s\n", __func__); + if (ci->cammode) + read_data(ca, slot, ci->rbuf, 0); + mutex_lock(&ci->lock); + write_reg(ci, 0x00, 0x21); + write_reg(ci, 0x06, 0x1F); + msleep(300); + + write_regm(ci, 0x09, 0x08, 0x08); + write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */ + write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */ + + ci->mode = -1; + ci->write_busy = 0; + mutex_unlock(&ci->lock); + return 0; +} + +static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + write_regm(ci, 0x09, 0x00, 0x08); + set_mode(ci, 0); + cam_mode(ci, 1); + mutex_unlock(&ci->lock); + return 0; +} + +static int campoll(struct cxd *ci) +{ + u8 istat; + + read_reg(ci, 0x04, &istat); + if (!istat) + return 0; + write_reg(ci, 0x05, istat); + + if (istat & 0x40) + ci->dr = 1; + if (istat & 0x20) + ci->write_busy = 0; + + if (istat & 2) { + u8 slotstat; + + read_reg(ci, 0x01, &slotstat); + if (!(2 & slotstat)) { + if (!ci->slot_stat) { + ci->slot_stat |= + DVB_CA_EN50221_POLL_CAM_PRESENT; + write_regm(ci, 0x03, 0x08, 0x08); + } + + } else { + if (ci->slot_stat) { + ci->slot_stat = 0; + write_regm(ci, 0x03, 0x00, 0x08); + dev_info(&ci->client->dev, "NO CAM\n"); + ci->ready = 0; + } + } + if ((istat & 8) && + ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { + ci->ready = 1; + ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; + } + } + return 0; +} + +static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct cxd *ci = ca->data; + u8 slotstat; + + mutex_lock(&ci->lock); + campoll(ci); + read_reg(ci, 0x01, &slotstat); + mutex_unlock(&ci->lock); + + return ci->slot_stat; +} + +static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + u8 msb, lsb; + u16 len; + + mutex_lock(&ci->lock); + campoll(ci); + mutex_unlock(&ci->lock); + + if (!ci->dr) + return 0; + + mutex_lock(&ci->lock); + read_reg(ci, 0x0f, &msb); + read_reg(ci, 0x10, &lsb); + len = ((u16)msb << 8) | lsb; + if (len > ecount || len < 2) { + /* read it anyway or cxd may hang */ + read_block(ci, 0x12, ci->rbuf, len); + mutex_unlock(&ci->lock); + return -EIO; + } + read_block(ci, 0x12, ebuf, len); + ci->dr = 0; + mutex_unlock(&ci->lock); + return len; +} + +static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + + if (ci->write_busy) + return -EAGAIN; + mutex_lock(&ci->lock); + write_reg(ci, 0x0d, ecount >> 8); + write_reg(ci, 0x0e, ecount & 0xff); + write_block(ci, 0x11, ebuf, ecount); + ci->write_busy = 1; + mutex_unlock(&ci->lock); + return ecount; +} + +static struct dvb_ca_en50221 en_templ = { + .read_attribute_mem = read_attribute_mem, + .write_attribute_mem = write_attribute_mem, + .read_cam_control = read_cam_control, + .write_cam_control = write_cam_control, + .slot_reset = slot_reset, + .slot_shutdown = slot_shutdown, + .slot_ts_enable = slot_ts_enable, + .poll_slot_status = poll_slot_status, + .read_data = read_data, + .write_data = write_data, +}; + +static int cxd2099_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cxd *ci; + struct cxd2099_cfg *cfg = client->dev.platform_data; + static const struct regmap_config rm_cfg = { + .reg_bits = 8, + .val_bits = 8, + }; + unsigned int val; + int ret; + + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) { + ret = -ENOMEM; + goto err; + } + + ci->client = client; + memcpy(&ci->cfg, cfg, sizeof(ci->cfg)); + + ci->regmap = regmap_init_i2c(client, &rm_cfg); + if (IS_ERR(ci->regmap)) { + ret = PTR_ERR(ci->regmap); + goto err_kfree; + } + + ret = regmap_read(ci->regmap, 0x00, &val); + if (ret < 0) { + dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n", + client->addr); + goto err_rmexit; + } + + mutex_init(&ci->lock); + ci->lastaddress = 0xff; + ci->clk_reg_b = 0x4a; + ci->clk_reg_f = 0x1b; + + ci->en = en_templ; + ci->en.data = ci; + init(ci); + dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr); + + *cfg->en = &ci->en; + + if (!buffermode) { + ci->en.read_data = NULL; + ci->en.write_data = NULL; + } else { + dev_info(&client->dev, "Using CXD2099AR buffer mode"); + } + + i2c_set_clientdata(client, ci); + + return 0; + +err_rmexit: + regmap_exit(ci->regmap); +err_kfree: + kfree(ci); +err: + + return ret; +} + +static int cxd2099_remove(struct i2c_client *client) +{ + struct cxd *ci = i2c_get_clientdata(client); + + regmap_exit(ci->regmap); + kfree(ci); + + return 0; +} + +static const struct i2c_device_id cxd2099_id[] = { + {"cxd2099", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cxd2099_id); + +static struct i2c_driver cxd2099_driver = { + .driver = { + .name = "cxd2099", + }, + .probe = cxd2099_probe, + .remove = cxd2099_remove, + .id_table = cxd2099_id, +}; + +module_i2c_driver(cxd2099_driver); + +MODULE_DESCRIPTION("CXD2099AR Common Interface controller driver"); +MODULE_AUTHOR("Ralph Metzler"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h new file mode 100644 index 000000000000..679e87512799 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2099.h @@ -0,0 +1,42 @@ +/* + * cxd2099.h: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010-2011 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CXD2099_H_ +#define _CXD2099_H_ + +#include + +struct cxd2099_cfg { + u32 bitrate; + u8 adr; + u8 polarity; + u8 clock_mode; + + u32 max_i2c; + + /* ptr to DVB CA struct */ + struct dvb_ca_en50221 **en; +}; + +/* TODO: remove when done */ +static inline struct +dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, + struct i2c_adapter *i2c) +{ + dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index f43d0b83fc0c..a422dde2f34a 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -13,6 +13,7 @@ config DVB_DDBRIDGE select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index f58fdec50eab..745b37d07558 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -10,6 +10,3 @@ obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o ccflags-y += -Idrivers/media/dvb-frontends/ ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 637d506b23c5..390ed75fe438 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -8,6 +8,7 @@ config DVB_NGENE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile index e4208f5ed215..ec450ad19281 100644 --- a/drivers/media/pci/ngene/Makefile +++ b/drivers/media/pci/ngene/Makefile @@ -9,6 +9,3 @@ obj-$(CONFIG_DVB_NGENE) += ngene.o ccflags-y += -Idrivers/media/dvb-frontends/ ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ -- cgit From da2cf18ff883b6130b1a6e4a3e9402abcb9f5bc0 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Fri, 9 Feb 2018 13:22:49 -0500 Subject: media: dvb-frontends/stv0910: rework and fix DiSEqC send Rework both DiSEqC send functions (send_master_cmd() and send_burst()) to utilise the new SET_REG() and SET_FIELD() macros. Esp. due to SET_FIELD(), this makes sure that not all bits (with unrelated purposes) are always rewritten, but only those needed for sending DiSEqC commands. In send_burst(), this makes sure that DISEQC_MODE isn't changed from 3 to 2 inbetween when sending SEC_MINI_A. Also, change both functions to write DISEQC_MODE first before setting DIS_PRECHARGE. This makes diseqc control work more reliable for "fullblown" DiSEqC strings in VDR's diseqc.conf in combination with certain multiswitches. Fixes: 448461af0e19 ("media: dvb-frontends/stv0910: implement diseqc_send_burst") Reported-by: Helmut Auer Cc: Ralph Metzler Signed-off-by: Daniel Scheller Tested-by: Helmut Auer Tested-by: Richard Scobie Tested-by: Dietmar Spingler Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0910.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index a2f7c0c1587f..52355c14fd64 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1673,15 +1673,15 @@ static int send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; int i; - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); + SET_FIELD(DIS_PRECHARGE, 1); for (i = 0; i < cmd->msg_len; i++) { wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]); + SET_REG(DISTXFIFO, cmd->msg[i]); } - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; } @@ -1689,19 +1689,20 @@ static int send_master_cmd(struct dvb_frontend *fe, static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; u8 value; if (burst == SEC_MINI_A) { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F); + SET_FIELD(DISEQC_MODE, 3); value = 0x00; } else { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); value = 0xFF; } + + SET_FIELD(DIS_PRECHARGE, 1); wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value); - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_REG(DISTXFIFO, value); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; -- cgit From 1844f49861cbd5dd8c289d3c4c8b4a76a4fe2d37 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Mon, 12 Feb 2018 15:19:04 -0500 Subject: media: si2168: change ts bus control logic Move the ts bus control function moved higher, enabling it after configuring frontend and removeing ts_bus_ctrl callback. While here, also add an error checking and re-add a comment that were removed by commit 445877742ce3 ("media: si2168: Add ts bus coontrol, turn off bus on sleep"). [mchehab@s-opensource.com: I ended by applying the first version, instead of the right one. So, this patch contains the diff and the v2 changelog instead] Fixes: 445877742ce3 ("media: si2168: Add ts bus coontrol, turn off bus on sleep") Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 60 ++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 27 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 282dc92cb102..a91947784842 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -82,6 +82,30 @@ err_mutex_unlock: return ret; } +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + struct si2168_cmd cmd; + int ret = 0; + + dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + + /* set TS_MODE property */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + if (acquire) + cmd.args[4] |= dev->ts_mode; + else + cmd.args[4] |= SI2168_TS_TRISTATE; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + + return ret; +} + static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; @@ -405,36 +429,17 @@ static int si2168_set_frontend(struct dvb_frontend *fe) dev->delivery_system = c->delivery_system; + /* enable ts bus */ + ret = si2168_ts_bus_ctrl(fe, 1); + if (ret) + goto err; + return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } -static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct i2c_client *client = fe->demodulator_priv; - struct si2168_dev *dev = i2c_get_clientdata(client); - struct si2168_cmd cmd; - int ret = 0; - - dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); - - /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - if (acquire) - cmd.args[4] |= dev->ts_mode; - else - cmd.args[4] |= SI2168_TS_TRISTATE; - if (dev->ts_clock_gapped) - cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); - - return ret; -} - static int si2168_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; @@ -566,6 +571,7 @@ static int si2168_init(struct dvb_frontend *fe) dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); + /* set ts mode */ ret = si2168_ts_bus_ctrl(fe, 1); if (ret) goto err; @@ -604,7 +610,9 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; /* tri-state data bus */ - si2168_ts_bus_ctrl(fe, 0); + ret = si2168_ts_bus_ctrl(fe, 0); + if (ret) + goto err; /* Firmware B 4.0-11 or later loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) @@ -703,8 +711,6 @@ static const struct dvb_frontend_ops si2168_ops = { .init = si2168_init, .sleep = si2168_sleep, - .ts_bus_ctrl = si2168_ts_bus_ctrl, - .set_frontend = si2168_set_frontend, .read_status = si2168_read_status, -- cgit From 7b69f2cb91319abdacf37be501db2eae45112a09 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 6 Mar 2018 10:34:44 -0500 Subject: media: ov772x: constify ov772x_frame_intervals The values on this array never changes. Make it const. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 16665af0c712..321105bb3161 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -531,7 +531,7 @@ static const struct ov772x_win_size ov772x_win_sizes[] = { /* * frame rate settings lists */ -static unsigned int ov772x_frame_intervals[] = { 5, 10, 15, 20, 30, 60 }; +static const unsigned int ov772x_frame_intervals[] = { 5, 10, 15, 20, 30, 60 }; /* * general function -- cgit From 9aa4d4ea244481fe98eb181ec5d7a9f7cb86f076 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 22 Feb 2018 15:45:47 -0500 Subject: media: usb: don't initialize vars if not needed Some local variables will be set to an appropriate value before usage. Thus omit explicit initialisations at the beginning of these functions. Signed-off-by: Markus Elfring Acked-by: Alexey Klimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/radio-wl1273.c | 2 +- drivers/media/radio/si470x/radio-si470x-usb.c | 2 +- drivers/media/usb/cx231xx/cx231xx-cards.c | 2 +- drivers/media/usb/cx231xx/cx231xx-dvb.c | 2 +- drivers/media/usb/go7007/snd-go7007.c | 2 +- drivers/media/usb/tm6000/tm6000-cards.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index dc6c4f985911..0f292c6ba338 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -511,7 +511,7 @@ static int usb_amradio_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct amradio_device *radio; - int retval = 0; + int retval; radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 58e944591602..8f9f8dfc3497 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -671,7 +671,7 @@ fail: static int wl1273_fm_suspend(struct wl1273_device *radio) { struct wl1273_core *core = radio->core; - int r = 0; + int r; /* Cannot go from OFF to SUSPENDED */ if (core->mode == WL1273_MODE_RX) diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index c311f9951d80..2277e850bb5e 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -578,7 +578,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, struct si470x_device *radio; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - int i, int_end_size, retval = 0; + int i, int_end_size, retval; unsigned char version_warning = 0; /* private data allocation and initialization */ diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 8582568f0dcd..c5edbd5bdb7e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1217,7 +1217,7 @@ static void cx231xx_config_tuner(struct cx231xx *dev) static int read_eeprom(struct cx231xx *dev, struct i2c_client *client, u8 *eedata, int len) { - int ret = 0; + int ret; u8 start_offset = 0; int len_todo = len; u8 *eedata_cur = eedata; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 63deca9b5017..7c3863ad6f23 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -630,7 +630,7 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) static int dvb_init(struct cx231xx *dev) { - int result = 0; + int result; struct cx231xx_dvb *dvb; struct i2c_adapter *tuner_i2c; struct i2c_adapter *demod_i2c; diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index c618764480c6..f84a2130f033 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -227,7 +227,7 @@ int go7007_snd_init(struct go7007 *go) { static int dev; struct go7007_snd *gosnd; - int ret = 0; + int ret; if (dev >= SNDRV_CARDS) return -ENODEV; diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 4d5f4cc4887e..70939e96b856 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1174,7 +1174,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, { struct usb_device *usbdev; struct tm6000_core *dev; - int i, rc = 0; + int i, rc; int nr = 0; char *speed; -- cgit From 1aebed3289582c4fdbcfd81197bfb25fbbf311b8 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sat, 24 Feb 2018 09:55:57 -0500 Subject: media: dvb_ca_en50221: fix severity of successful CAM init log message A successful CA module initialisation isn't an error. Change the log print to info severity accordingly. Cc: Jasmin Jessich Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_ca_en50221.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 204d0f6c678d..97365a863519 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1254,8 +1254,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, ca->pub->slot_ts_enable(ca->pub, slot); sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); - pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", - ca->dvbdev->adapter->num); + pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + ca->dvbdev->adapter->num); break; case DVB_CA_SLOTSTATE_RUNNING: -- cgit From 37a59823788af2388a9fe9fbd370579d80116178 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:29 -0500 Subject: media: ngene: add two additional PCI IDs Add two more device IDs for cards supported by the ngene driver. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index bb49620540c5..49f78bb31537 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -749,6 +749,8 @@ static const struct ngene_info ngene_info_terratec = { /****************************************************************************/ static const struct pci_device_id ngene_id_tbl[] = { + NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5), NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), -- cgit From 6795bf6264829b6678f646164d5ab5e335a99fb1 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:30 -0500 Subject: media: ngene: convert kernellog printing from printk() to dev_*() macros Convert all printk() and pr_*() kernel log printing to rather use the dev_*() macros. Not only is it discouraged to use printk() (checkpatch even complains about that), but also this helps identifying the exact PCI device for any printed event, and it makes almost all printing shorter in terms of code style since there's no need to use KERN_* DEVICE_NAME any more (dev_*() will take care of this). Since the dprintk macro define isn't used anymore, remove it. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 75 ++++++++++++++++++++--------------- drivers/media/pci/ngene/ngene-core.c | 75 +++++++++++++++++------------------ drivers/media/pci/ngene/ngene-dvb.c | 4 +- 3 files changed, 84 insertions(+), 70 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 49f78bb31537..16666de8cbee 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -23,6 +23,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -48,6 +50,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -63,7 +66,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + dev_err(pdev, "No STV6110X found!\n"); return -ENODEV; } @@ -100,6 +103,7 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct dvb_frontend *fe; @@ -110,7 +114,7 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + dev_err(pdev, "No TDA18271 found!\n"); return -ENODEV; } @@ -128,6 +132,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -144,7 +149,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 : STV090x_DEMODULATOR_1); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + dev_err(pdev, "No STV0900 found!\n"); return -ENODEV; } @@ -154,7 +159,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dev_err(pdev, "No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); chan->fe = NULL; return -ENODEV; @@ -211,6 +216,7 @@ static int port_has_drxk(struct i2c_adapter *i2c, int port) static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxk_config config; memset(&config, 0, sizeof(config)); @@ -220,7 +226,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { - printk(KERN_ERR "No DRXK found!\n"); + dev_err(pdev, "No DRXK found!\n"); return -ENODEV; } chan->fe->sec_priv = chan; @@ -231,6 +237,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, static int cineS2_probe(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; @@ -269,14 +276,14 @@ static int cineS2_probe(struct ngene_channel *chan) } rc = i2c_transfer(i2c, &i2c_msg, 1); if (rc != 1) { - printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + dev_err(pdev, "Could not setup DPNx\n"); return -EIO; } } else if (port_has_drxk(i2c, chan->number^2)) { chan->demod_type = 1; demod_attach_drxk(chan, i2c); } else { - printk(KERN_ERR "No demod found on chan %d\n", chan->number); + dev_err(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; } return 0; @@ -299,9 +306,11 @@ static struct mt2131_config m780_tunerconfig = { */ static int demod_attach_lg330x(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; + chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n"); + dev_err(pdev, "No LGDT330x found!\n"); return -ENODEV; } @@ -313,6 +322,7 @@ static int demod_attach_lg330x(struct ngene_channel *chan) static int demod_attach_drxd(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxd_config *feconf; feconf = chan->dev->card_info->fe_config[chan->number]; @@ -320,7 +330,7 @@ static int demod_attach_drxd(struct ngene_channel *chan) chan->fe = dvb_attach(drxd_attach, feconf, chan, &chan->i2c_adapter, &chan->dev->pci_dev->dev); if (!chan->fe) { - pr_err("No DRXD found!\n"); + dev_err(pdev, "No DRXD found!\n"); return -ENODEV; } return 0; @@ -328,6 +338,7 @@ static int demod_attach_drxd(struct ngene_channel *chan) static int tuner_attach_dtt7520x(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxd_config *feconf; feconf = chan->dev->card_info->fe_config[chan->number]; @@ -335,7 +346,7 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan) if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, &chan->i2c_adapter, feconf->pll_type)) { - pr_err("No pll(%d) found!\n", feconf->pll_type); + dev_err(pdev, "No pll(%d) found!\n", feconf->pll_type); return -ENODEV; } return 0; @@ -371,12 +382,13 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan) static int i2c_write_eeprom(struct i2c_adapter *adapter, u8 adr, u16 reg, u8 data) { + struct device *pdev = adapter->dev.parent; u8 m[3] = {(reg >> 8), (reg & 0xff), data}; struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = sizeof(m)}; if (i2c_transfer(adapter, &msg, 1) != 1) { - pr_err(DEVICE_NAME ": Error writing EEPROM!\n"); + dev_err(pdev, "Error writing EEPROM!\n"); return -EIO; } return 0; @@ -385,6 +397,7 @@ static int i2c_write_eeprom(struct i2c_adapter *adapter, static int i2c_read_eeprom(struct i2c_adapter *adapter, u8 adr, u16 reg, u8 *data, int len) { + struct device *pdev = adapter->dev.parent; u8 msg[2] = {(reg >> 8), (reg & 0xff)}; struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, .buf = msg, .len = 2 }, @@ -392,7 +405,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter, .buf = data, .len = len} }; if (i2c_transfer(adapter, msgs, 2) != 2) { - pr_err(DEVICE_NAME ": Error reading EEPROM\n"); + dev_err(pdev, "Error reading EEPROM\n"); return -EIO; } return 0; @@ -401,6 +414,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter, static int ReadEEProm(struct i2c_adapter *adapter, u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) { + struct device *pdev = adapter->dev.parent; int status = 0; u16 Addr = MICNG_EE_START, Length, tag = 0; u8 EETag[3]; @@ -416,9 +430,8 @@ static int ReadEEProm(struct i2c_adapter *adapter, Addr += sizeof(u16) + 1 + EETag[2]; } if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); + dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); return -1; } Length = EETag[2]; @@ -441,6 +454,7 @@ static int ReadEEProm(struct i2c_adapter *adapter, static int WriteEEProm(struct i2c_adapter *adapter, u16 Tag, u32 Length, u8 *data) { + struct device *pdev = adapter->dev.parent; int status = 0; u16 Addr = MICNG_EE_START; u8 EETag[3]; @@ -458,9 +472,8 @@ static int WriteEEProm(struct i2c_adapter *adapter, Addr += sizeof(u16) + 1 + EETag[2]; } if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { - pr_err(DEVICE_NAME - ": Reached EOEE @ Tag = %04x Length = %3d\n", - tag, EETag[2]); + dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", + tag, EETag[2]); return -1; } @@ -487,13 +500,11 @@ static int WriteEEProm(struct i2c_adapter *adapter, if (status) break; if (Tmp != data[i]) - pr_err(DEVICE_NAME - "eeprom write error\n"); + dev_err(pdev, "eeprom write error\n"); retry -= 1; } if (status) { - pr_err(DEVICE_NAME - ": Timeout polling eeprom\n"); + dev_err(pdev, "Timeout polling eeprom\n"); break; } } @@ -532,19 +543,20 @@ static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) static s16 osc_deviation(void *priv, s16 deviation, int flag) { struct ngene_channel *chan = priv; + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *adap = &chan->i2c_adapter; u16 data = 0; if (flag) { data = (u16) deviation; - pr_info(DEVICE_NAME ": write deviation %d\n", - deviation); + dev_info(pdev, "write deviation %d\n", + deviation); eeprom_write_ushort(adap, 0x1000 + chan->number, data); } else { if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) data = 0; - pr_info(DEVICE_NAME ": read deviation %d\n", - (s16) data); + dev_info(pdev, "read deviation %d\n", + (s16)data); } return (s16) data; @@ -771,7 +783,7 @@ MODULE_DEVICE_TABLE(pci, ngene_id_tbl); static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, enum pci_channel_state state) { - printk(KERN_ERR DEVICE_NAME ": PCI error\n"); + dev_err(&dev->dev, "PCI error\n"); if (state == pci_channel_io_perm_failure) return PCI_ERS_RESULT_DISCONNECT; if (state == pci_channel_io_frozen) @@ -781,13 +793,13 @@ static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) { - printk(KERN_INFO DEVICE_NAME ": slot reset\n"); + dev_info(&dev->dev, "slot reset\n"); return 0; } static void ngene_resume(struct pci_dev *dev) { - printk(KERN_INFO DEVICE_NAME ": resume\n"); + dev_info(&dev->dev, "resume\n"); } static const struct pci_error_handlers ngene_errors = { @@ -807,8 +819,9 @@ static struct pci_driver ngene_pci_driver = { static __init int module_init_ngene(void) { - printk(KERN_INFO - "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + /* pr_*() since we don't have a device to use with dev_*() yet */ + pr_info("nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); + return pci_register_driver(&ngene_pci_driver); } diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 80db777cb7ec..a63f019fb62f 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -51,8 +51,6 @@ MODULE_PARM_DESC(debug, "Print debugging information."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk if (debug) printk - #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) #define ngwritel(dat, adr) writel((dat), dev->iomem + (adr)) #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) @@ -86,6 +84,7 @@ static void event_tasklet(unsigned long data) static void demux_tasklet(unsigned long data) { struct ngene_channel *chan = (struct ngene_channel *)data; + struct device *pdev = &chan->dev->pci_dev->dev; struct SBufferHeader *Cur = chan->nextBuffer; spin_lock_irq(&chan->state_lock); @@ -124,16 +123,15 @@ static void demux_tasklet(unsigned long data) chan->HWState = HWSTATE_RUN; } } else { - printk(KERN_ERR DEVICE_NAME ": OOPS\n"); + dev_err(pdev, "OOPS\n"); if (chan->HWState == HWSTATE_RUN) { Cur->ngeneBuffer.SR.Flags &= ~0x40; break; /* Stop processing stream */ } } if (chan->AudioDTOUpdated) { - printk(KERN_INFO DEVICE_NAME - ": Update AudioDTO = %d\n", - chan->AudioDTOValue); + dev_info(pdev, "Update AudioDTO = %d\n", + chan->AudioDTOValue); Cur->ngeneBuffer.SR.DTOUpdate = chan->AudioDTOValue; chan->AudioDTOUpdated = 0; @@ -173,6 +171,7 @@ static void demux_tasklet(unsigned long data) static irqreturn_t irq_handler(int irq, void *dev_id) { struct ngene *dev = (struct ngene *)dev_id; + struct device *pdev = &dev->pci_dev->dev; u32 icounts = 0; irqreturn_t rc = IRQ_NONE; u32 i = MAX_STREAM; @@ -213,7 +212,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id) *(dev->EventBuffer); dev->EventQueueWriteIndex = nextWriteIndex; } else { - printk(KERN_ERR DEVICE_NAME ": event overflow\n"); + dev_err(pdev, "event overflow\n"); dev->EventQueueOverflowCount += 1; dev->EventQueueOverflowFlag = 1; } @@ -249,23 +248,25 @@ static irqreturn_t irq_handler(int irq, void *dev_id) static void dump_command_io(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; u8 buf[8], *b; ngcpyfrom(buf, HOST_TO_NGENE, 8); - printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); + dev_err(pdev, "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf); ngcpyfrom(buf, NGENE_TO_HOST, 8); - printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); + dev_err(pdev, "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf); b = dev->hosttongene; - printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b); + dev_err(pdev, "dev->hosttongene (%p): %*ph\n", b, 8, b); b = dev->ngenetohost; - printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b); + dev_err(pdev, "dev->ngenetohost (%p): %*ph\n", b, 8, b); } static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) { + struct device *pdev = &dev->pci_dev->dev; int ret; u8 *tmpCmdDoneByte; @@ -313,9 +314,8 @@ static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com) if (!ret) { /*ngwritel(0, FORCE_NMI);*/ - printk(KERN_ERR DEVICE_NAME - ": Command timeout cmd=%02x prev=%02x\n", - com->cmd.hdr.Opcode, dev->prev_cmd); + dev_err(pdev, "Command timeout cmd=%02x prev=%02x\n", + com->cmd.hdr.Opcode, dev->prev_cmd); dump_command_io(dev); return -1; } @@ -553,6 +553,7 @@ static void clear_buffers(struct ngene_channel *chan) static int ngene_command_stream_control(struct ngene *dev, u8 stream, u8 control, u8 mode, u8 flags) { + struct device *pdev = &dev->pci_dev->dev; struct ngene_channel *chan = &dev->channel[stream]; struct ngene_command com; u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300); @@ -572,8 +573,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, com.in_len = sizeof(struct FW_STREAM_CONTROL); com.out_len = 0; - dprintk(KERN_INFO DEVICE_NAME - ": Stream=%02x, Control=%02x, Mode=%02x\n", + dev_dbg(pdev, "Stream=%02x, Control=%02x, Mode=%02x\n", com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control, com.cmd.StreamControl.Mode); @@ -695,23 +695,24 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, void set_transfer(struct ngene_channel *chan, int state) { + struct device *pdev = &chan->dev->pci_dev->dev; u8 control = 0, mode = 0, flags = 0; struct ngene *dev = chan->dev; int ret; /* - printk(KERN_INFO DEVICE_NAME ": st %d\n", state); + dev_info(pdev, "st %d\n", state); msleep(100); */ if (state) { if (chan->running) { - printk(KERN_INFO DEVICE_NAME ": already running\n"); + dev_info(pdev, "already running\n"); return; } } else { if (!chan->running) { - printk(KERN_INFO DEVICE_NAME ": already stopped\n"); + dev_info(pdev, "already stopped\n"); return; } } @@ -722,7 +723,7 @@ void set_transfer(struct ngene_channel *chan, int state) if (state) { spin_lock_irq(&chan->state_lock); - /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + /* dev_info(pdev, "lock=%08x\n", ngreadl(0x9310)); */ dvb_ringbuffer_flush(&dev->tsout_rbuf); control = 0x80; @@ -740,7 +741,7 @@ void set_transfer(struct ngene_channel *chan, int state) chan->pBufferExchange = tsin_exchange; spin_unlock_irq(&chan->state_lock); } - /* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + /* else dev_info(pdev, "lock=%08x\n", ngreadl(0x9310)); */ mutex_lock(&dev->stream_mutex); @@ -751,8 +752,7 @@ void set_transfer(struct ngene_channel *chan, int state) if (!ret) chan->running = state; else - printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n", - state); + dev_err(pdev, "%s %d failed\n", __func__, state); if (!state) { spin_lock_irq(&chan->state_lock); chan->pBufferExchange = NULL; @@ -1195,6 +1195,7 @@ static int ngene_get_buffers(struct ngene *dev) static void ngene_init(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; int i; tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev); @@ -1214,12 +1215,12 @@ static void ngene_init(struct ngene *dev) dev->icounts = ngreadl(NGENE_INT_COUNTS); dev->device_version = ngreadl(DEV_VER) & 0x0f; - printk(KERN_INFO DEVICE_NAME ": Device version %d\n", - dev->device_version); + dev_info(pdev, "Device version %d\n", dev->device_version); } static int ngene_load_firm(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; u32 size; const struct firmware *fw = NULL; u8 *ngene_fw; @@ -1253,21 +1254,18 @@ static int ngene_load_firm(struct ngene *dev) } if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { - printk(KERN_ERR DEVICE_NAME - ": Could not load firmware file %s.\n", fw_name); - printk(KERN_INFO DEVICE_NAME - ": Copy %s to your hotplug directory!\n", fw_name); + dev_err(pdev, "Could not load firmware file %s.\n", fw_name); + dev_info(pdev, "Copy %s to your hotplug directory!\n", + fw_name); return -1; } if (size == 0) size = fw->size; if (size != fw->size) { - printk(KERN_ERR DEVICE_NAME - ": Firmware %s has invalid size!", fw_name); + dev_err(pdev, "Firmware %s has invalid size!", fw_name); err = -1; } else { - printk(KERN_INFO DEVICE_NAME - ": Loading firmware file %s.\n", fw_name); + dev_info(pdev, "Loading firmware file %s.\n", fw_name); ngene_fw = (u8 *) fw->data; err = ngene_command_load_firmware(dev, ngene_fw, size); } @@ -1327,6 +1325,7 @@ static int ngene_buffer_config(struct ngene *dev) static int ngene_start(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; int stat; int i; @@ -1366,8 +1365,7 @@ static int ngene_start(struct ngene *dev) free_irq(dev->pci_dev->irq, dev); stat = pci_enable_msi(dev->pci_dev); if (stat) { - printk(KERN_INFO DEVICE_NAME - ": MSI not available\n"); + dev_info(pdev, "MSI not available\n"); flags = IRQF_SHARED; } else { flags = 0; @@ -1570,6 +1568,7 @@ static const struct cxd2099_cfg cxd_cfgtmpl = { static void cxd_attach(struct ngene *dev) { + struct device *pdev = &dev->pci_dev->dev; struct ngene_ci *ci = &dev->ci; struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; @@ -1600,7 +1599,7 @@ static void cxd_attach(struct ngene *dev) err_i2c: i2c_unregister_device(client); err_ret: - printk(KERN_ERR DEVICE_NAME ": CXD2099AR attach failed\n"); + dev_err(pdev, "CXD2099AR attach failed\n"); return; } @@ -1648,7 +1647,7 @@ void ngene_shutdown(struct pci_dev *pdev) if (!dev || !shutdown_workaround) return; - printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + dev_info(&pdev->dev, "shutdown workaround...\n"); ngene_unlink(dev); pci_disable_device(pdev); } @@ -1688,7 +1687,7 @@ int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) dev->pci_dev = pci_dev; dev->card_info = (struct ngene_info *)id->driver_data; - printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name); + dev_info(&pci_dev->dev, "Found %s\n", dev->card_info->name); pci_set_drvdata(pci_dev, dev); diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 03fc218a45e9..f71fd41c762c 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -152,7 +152,9 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) stripped++; if (ok % 100 == 0 && overflow) - printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped); + dev_warn(&dev->pci_dev->dev, + "%s: ok %u overflow %u dropped %u\n", + __func__, ok, overflow, stripped); #endif buf += 188; len -= 188; -- cgit From 66a4c0c749cf9b3ce363085709219cc325d2a647 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:31 -0500 Subject: media: ngene: use defines to identify the demod_type Make it more clear which demod_type is used for which hardware by having defines for the possible demod_type values. With that, change the demod_type evaluation in tuner_attach_probe() to a switch-case instead of an if() for each possible value. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 11 +++++++---- drivers/media/pci/ngene/ngene.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 16666de8cbee..065b83ee569b 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -123,10 +123,13 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) static int tuner_attach_probe(struct ngene_channel *chan) { - if (chan->demod_type == 0) + switch (chan->demod_type) { + case DEMOD_TYPE_STV090X: return tuner_attach_stv6110(chan); - if (chan->demod_type == 1) + case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); + } + return -EINVAL; } @@ -251,7 +254,7 @@ static int cineS2_probe(struct ngene_channel *chan) i2c = &chan->dev->channel[1].i2c_adapter; if (port_has_stv0900(i2c, chan->number)) { - chan->demod_type = 0; + chan->demod_type = DEMOD_TYPE_STV090X; fe_conf = chan->dev->card_info->fe_config[chan->number]; /* demod found, attach it */ rc = demod_attach_stv0900(chan); @@ -280,7 +283,7 @@ static int cineS2_probe(struct ngene_channel *chan) return -EIO; } } else if (port_has_drxk(i2c, chan->number^2)) { - chan->demod_type = 1; + chan->demod_type = DEMOD_TYPE_DRXK; demod_attach_drxk(chan, i2c); } else { dev_err(pdev, "No demod found on chan %d\n", chan->number); diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index caf8602c7459..9724701a3274 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -51,6 +51,9 @@ #define VIDEO_CAP_MPEG4 512 #endif +#define DEMOD_TYPE_STV090X 0 +#define DEMOD_TYPE_DRXK 1 + enum STREAM { STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ STREAM_VIDEOIN2, -- cgit From 1c2ad82e537d735863030e153769c900edb01d8f Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:32 -0500 Subject: media: ngene: support STV0367 DVB-C/T DuoFlex addons Add support for STV0367+TDA18212 based DuoFlex CT addon modules. For this, add a demod probe function and all necessary demod/tuner attach functions which use existing auxiliary drivers (stv0367 and tda18212) to support this hardware. As tda18212 is an I2C client driver, proper cleanup code is added to the deregistration sequence in ngene-core. To not cause use- after-free situations when there's a CXD2099 I2C client connected, which is rather freed in ngene-core.c:cxd_detach(), add i2c_client_fe to struct ngene_channel to keep track if the i2c_client was allocated by a frontend driver, rather than the CI code paths. Also move the I2C access functions to the top of the file and add the required read_regs() function for the tda18212 ping to work. This adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0367 demod driver and TDA18212 tuner driver to Kconfig aswell. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/Kconfig | 2 + drivers/media/pci/ngene/ngene-cards.c | 194 ++++++++++++++++++++++++++++++---- drivers/media/pci/ngene/ngene-core.c | 12 +++ drivers/media/pci/ngene/ngene.h | 2 + 4 files changed, 191 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 390ed75fe438..c3254f9dc8ad 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -8,6 +8,8 @@ config DVB_NGENE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 065b83ee569b..7ec5f68b1ec7 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -42,8 +42,42 @@ #include "drxk.h" #include "drxd.h" #include "dvb-pll.h" +#include "stv0367.h" +#include "stv0367_priv.h" +#include "tda18212.h" +/****************************************************************************/ +/* I2C transfer functions used for demod/tuner probing***********************/ +/****************************************************************************/ + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} +static int i2c_read_regs(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len} }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} /****************************************************************************/ /* Demod/tuner attachment ***************************************************/ /****************************************************************************/ @@ -85,7 +119,6 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } - static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -121,6 +154,89 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) return 0; } +static int tuner_tda18212_ping(struct ngene_channel *chan, + struct i2c_adapter *i2c, + unsigned short adr) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 tda_id[2]; + u8 subaddr = 0x00; + + dev_dbg(pdev, "stv0367-tda18212 tuner ping\n"); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + + if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) + dev_dbg(pdev, "tda18212 ping 1 fail\n"); + if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) + dev_warn(pdev, "tda18212 ping failed, expect problems\n"); + + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); + + return 0; +} + +static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c; + struct i2c_client *client; + struct tda18212_config config = { + .fe = chan->fe, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, + }; + struct i2c_board_info board_info = { + .type = "tda18212", + .platform_data = &config, + }; + + if (chan->number & 1) + board_info.addr = 0x63; + else + board_info.addr = 0x60; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + /* + * due to a hardware quirk with the I2C gate on the stv0367+tda18212 + * combo, the tda18212 must be probed by reading it's id _twice_ when + * cold started, or it very likely will fail. + */ + if (dmdtype == DEMOD_TYPE_STV0367) + tuner_tda18212_ping(chan, i2c, board_info.addr); + + request_module(board_info.type); + + /* perform tuner init/attach */ + client = i2c_new_device(i2c, &board_info); + if (!client || !client->dev.driver) + goto err; + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + goto err; + } + + chan->i2c_client[0] = client; + chan->i2c_client_fe = 1; + + return 0; +err: + dev_err(pdev, "TDA18212 tuner not found. Device is not fully operational.\n"); + return -ENODEV; +} + static int tuner_attach_probe(struct ngene_channel *chan) { switch (chan->demod_type) { @@ -128,6 +244,8 @@ static int tuner_attach_probe(struct ngene_channel *chan) return tuner_attach_stv6110(chan); case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); + case DEMOD_TYPE_STV0367: + return tuner_attach_tda18212(chan, chan->demod_type); } return -EINVAL; @@ -171,6 +289,43 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static struct stv0367_config ddb_stv0367_config[] = { + { + .demod_address = 0x1f, + .xtal = 27000000, + .if_khz = 0, + .if_iq_mode = FE_TER_NORMAL_IF_TUNER, + .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, + .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, + }, { + .demod_address = 0x1e, + .xtal = 27000000, + .if_khz = 0, + .if_iq_mode = FE_TER_NORMAL_IF_TUNER, + .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, + .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, + }, +}; + +static int demod_attach_stv0367(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + + chan->fe = dvb_attach(stv0367ddb_attach, + &ddb_stv0367_config[(chan->number & 1)], i2c); + + if (!chan->fe) { + dev_err(pdev, "stv0367ddb_attach() failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) { struct ngene_channel *chan = fe->analog_demod_priv; @@ -181,24 +336,6 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) up(&chan->dev->pll_mutex); } -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) -{ - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; -} - -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) -{ - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} - static int port_has_stv0900(struct i2c_adapter *i2c, int port) { u8 val; @@ -216,6 +353,21 @@ static int port_has_drxk(struct i2c_adapter *i2c, int port) return 1; } +static int port_has_stv0367(struct i2c_adapter *i2c) +{ + u8 val; + + if (i2c_read_reg16(i2c, 0x1e, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + if (i2c_read_reg16(i2c, 0x1f, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + return 1; +} + static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { @@ -285,6 +437,10 @@ static int cineS2_probe(struct ngene_channel *chan) } else if (port_has_drxk(i2c, chan->number^2)) { chan->demod_type = DEMOD_TYPE_DRXK; demod_attach_drxk(chan, i2c); + } else if (port_has_stv0367(i2c)) { + chan->demod_type = DEMOD_TYPE_STV0367; + dev_info(pdev, "STV0367 on channel %d\n", chan->number); + demod_attach_stv0367(chan, i2c); } else { dev_err(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index a63f019fb62f..526d0adfa427 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1408,6 +1408,7 @@ static void release_channel(struct ngene_channel *chan) { struct dvb_demux *dvbdemux = &chan->demux; struct ngene *dev = chan->dev; + struct i2c_client *client; if (chan->running) set_transfer(chan, 0); @@ -1424,6 +1425,16 @@ static void release_channel(struct ngene_channel *chan) if (chan->fe) { dvb_unregister_frontend(chan->fe); + + /* release I2C client (tuner) if needed */ + client = chan->i2c_client[0]; + if (chan->i2c_client_fe && client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + chan->i2c_client[0] = NULL; + client = NULL; + } + dvb_frontend_detach(chan->fe); chan->fe = NULL; } @@ -1459,6 +1470,7 @@ static int init_channel(struct ngene_channel *chan) chan->users = 0; chan->type = io; chan->mode = chan->type; /* for now only one mode */ + chan->i2c_client_fe = 0; /* be sure this is set to zero */ if (io & NGENE_IO_TSIN) { chan->fe = NULL; diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 9724701a3274..1b88a9aa7aac 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -53,6 +53,7 @@ #define DEMOD_TYPE_STV090X 0 #define DEMOD_TYPE_DRXK 1 +#define DEMOD_TYPE_STV0367 2 enum STREAM { STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ @@ -634,6 +635,7 @@ struct ngene_channel { struct device device; struct i2c_adapter i2c_adapter; struct i2c_client *i2c_client[1]; + int i2c_client_fe; struct ngene *dev; int number; -- cgit From 7d5397d47f90f0a89c60f163177862a22d5c9685 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:33 -0500 Subject: media: ngene: add XO2 module support Detect and initialise modules equipped with XO2 interfaces (Lattice MachXO2). This requires a few more I2C transfer functions which this adds as well. Defines for the different possible (available) module types are added to ngene.h. The support for the actual tuners contained on these addon modules is kept separate from this commit and is being added with the next commits. The xo2names array is temporarily marked __maybe_unused to silence a corresponding compiler warning at this stage. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 144 +++++++++++++++++++++++++++++++++- drivers/media/pci/ngene/ngene.h | 12 +++ 2 files changed, 155 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7ec5f68b1ec7..05b8e56999ec 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -50,6 +50,32 @@ /* I2C transfer functions used for demod/tuner probing***********************/ /****************************************************************************/ +static int i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + {.addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, + u8 reg, u8 val) +{ + u8 msg[2] = {reg, val}; + + return i2c_write(adap, adr, msg, 2); +} + static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) { struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, @@ -78,6 +104,12 @@ static int i2c_read_regs(struct i2c_adapter *adapter, return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; } + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} + /****************************************************************************/ /* Demod/tuner attachment ***************************************************/ /****************************************************************************/ @@ -390,12 +422,98 @@ static int demod_attach_drxk(struct ngene_channel *chan, return 0; } +/****************************************************************************/ +/* XO2 related lists and functions ******************************************/ +/****************************************************************************/ + +static char __maybe_unused *xo2names[] = { + "DUAL DVB-S2", + "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", + "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", + "DUAL DVB-C/C2/T/T2/I", +}; + +static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 addr = 0x10; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, addr, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number); + return -1; + } + + i2c_read_reg(i2c, addr, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, addr, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, addr, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, addr, 0x08, 0x07); + + /* + * speed: 0=55,1=75,2=90,3=104 MBit/s + * Note: The ngene hardware must be run at 75 MBit/s compared + * to more modern ddbridge hardware which runs at 90 MBit/s, + * else there will be issues with the data transport and non- + * working secondary/slave demods/tuners. + */ + i2c_write_reg(i2c, addr, 0x09, 1); + + i2c_write_reg(i2c, addr, 0x0a, 0x01); + i2c_write_reg(i2c, addr, 0x0b, 0x01); + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, addr, 0x08, 0x87); + + return 0; +} + +static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + u8 addr = 0x10; + + *type = NGENE_XO2_TYPE_NONE; + + if (i2c_io(i2c, addr, probe, 1, data, 4)) + return 0; + if (data[0] == 'D' && data[1] == 'F') { + *id = data[2]; + *type = NGENE_XO2_TYPE_DUOFLEX; + return 1; + } + if (data[0] == 'C' && data[1] == 'I') { + *id = data[2]; + *type = NGENE_XO2_TYPE_CI; + return 1; + } + return 0; +} + +/****************************************************************************/ +/* Probing and port/channel handling ****************************************/ +/****************************************************************************/ + static int cineS2_probe(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; + u8 xo2_type, xo2_id; struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; @@ -405,7 +523,31 @@ static int cineS2_probe(struct ngene_channel *chan) else i2c = &chan->dev->channel[1].i2c_adapter; - if (port_has_stv0900(i2c, chan->number)) { + if (port_has_xo2(i2c, &xo2_type, &xo2_id)) { + xo2_id >>= 2; + dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n", + chan->number, xo2_type, xo2_id); + + switch (xo2_type) { + case NGENE_XO2_TYPE_DUOFLEX: + if (chan->number & 1) + dev_dbg(pdev, + "skipping XO2 init on odd channel %d", + chan->number); + else + init_xo2(chan, i2c); + + /* TODO: implement support for XO2 module types */ + dev_warn(pdev, "XO2 not supported\n"); + return -ENODEV; + case NGENE_XO2_TYPE_CI: + dev_info(pdev, "DuoFlex CI modules not supported\n"); + return -ENODEV; + default: + dev_info(pdev, "Unsupported XO2 module type\n"); + return -ENODEV; + } + } else if (port_has_stv0900(i2c, chan->number)) { chan->demod_type = DEMOD_TYPE_STV090X; fe_conf = chan->dev->card_info->fe_config[chan->number]; /* demod found, attach it */ diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 1b88a9aa7aac..72195f6552b3 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -55,6 +55,18 @@ #define DEMOD_TYPE_DRXK 1 #define DEMOD_TYPE_STV0367 2 +#define DEMOD_TYPE_XO2 32 +#define DEMOD_TYPE_STV0910 (DEMOD_TYPE_XO2 + 0) +#define DEMOD_TYPE_SONY_CT2 (DEMOD_TYPE_XO2 + 1) +#define DEMOD_TYPE_SONY_ISDBT (DEMOD_TYPE_XO2 + 2) +#define DEMOD_TYPE_SONY_C2T2 (DEMOD_TYPE_XO2 + 3) +#define DEMOD_TYPE_ST_ATSC (DEMOD_TYPE_XO2 + 4) +#define DEMOD_TYPE_SONY_C2T2I (DEMOD_TYPE_XO2 + 5) + +#define NGENE_XO2_TYPE_NONE 0 +#define NGENE_XO2_TYPE_DUOFLEX 1 +#define NGENE_XO2_TYPE_CI 2 + enum STREAM { STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */ STREAM_VIDEOIN2, -- cgit From 42b6515fd55d5c4dbeb8183ad18b289182e80456 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:34 -0500 Subject: media: ngene: add support for Sony CXD28xx-based DuoFlex modules Recognize (probe) and support (attach) all Sony CXD28xx based DuoFlex addon modules/cards, namely the DuoFlex CT2 (CXD2837), ISDB-T (CXD2838), C2T2 (CXD2843) and C2T2I (CXD2854). Since all these modules are equipped with a MachXO2 interface, that support is required for the hardware to work. This functionality utilises the auxiliary cxd2841er and tda18212 drivers. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the CXD2841ER demod driver to Kconfig. The __maybe_unused annotation can now be removed from the xo2names array. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/ngene-cards.c | 63 ++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index c3254f9dc8ad..f717567f54a5 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -9,6 +9,7 @@ config DVB_NGENE select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 05b8e56999ec..cdc8db14c606 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -45,6 +45,7 @@ #include "stv0367.h" #include "stv0367_priv.h" #include "tda18212.h" +#include "cxd2841er.h" /****************************************************************************/ /* I2C transfer functions used for demod/tuner probing***********************/ @@ -277,6 +278,10 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); case DEMOD_TYPE_STV0367: + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); } @@ -358,6 +363,34 @@ static int demod_attach_stv0367(struct ngene_channel *chan, return 0; } +static int demod_attach_cxd28xx(struct ngene_channel *chan, + struct i2c_adapter *i2c, int osc24) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct cxd2841er_config cfg; + + /* the cxd2841er driver expects 8bit/shifted I2C addresses */ + cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1; + + cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500; + cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE | + CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG | + CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL; + + /* attach frontend */ + chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + + if (!chan->fe) { + dev_err(pdev, "CXD28XX attach failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) { struct ngene_channel *chan = fe->analog_demod_priv; @@ -426,7 +459,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, /* XO2 related lists and functions ******************************************/ /****************************************************************************/ -static char __maybe_unused *xo2names[] = { +static char *xo2names[] = { "DUAL DVB-S2", "DUAL DVB-C/T/T2", "DUAL DVB-ISDBT", @@ -513,7 +546,8 @@ static int cineS2_probe(struct ngene_channel *chan) struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; - u8 xo2_type, xo2_id; + u8 xo2_type, xo2_id, xo2_demodtype; + u8 sony_osc24 = 0; struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; @@ -537,9 +571,28 @@ static int cineS2_probe(struct ngene_channel *chan) else init_xo2(chan, i2c); - /* TODO: implement support for XO2 module types */ - dev_warn(pdev, "XO2 not supported\n"); - return -ENODEV; + xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id; + + switch (xo2_demodtype) { + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: + dev_info(pdev, "%s (XO2) on channel %d\n", + xo2names[xo2_id], chan->number); + chan->demod_type = xo2_demodtype; + if (xo2_demodtype == DEMOD_TYPE_SONY_C2T2I) + sony_osc24 = 1; + + demod_attach_cxd28xx(chan, i2c, sony_osc24); + break; + default: + dev_warn(pdev, + "Unsupported XO2 module on channel %d\n", + chan->number); + return -ENODEV; + } + break; case NGENE_XO2_TYPE_CI: dev_info(pdev, "DuoFlex CI modules not supported\n"); return -ENODEV; -- cgit From 3262831b4a9a6c0441c94a7d1c378751f462ac92 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:35 -0500 Subject: media: ngene: add support for DuoFlex S2 V4 addon modules Add support for the STV0910/STV6111/LNBH25 based DuoFlex S2 V4 DVB-S2 addon modules by recognizing them from their XO2 type value and using the auxiliary stv0910, stv6111 and lnbh25 driver to form a complete DVB frontend. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0910, STV6111 and LNBH25 demod/tuner/LNB-IC drivers to Kconfig. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/Kconfig | 3 ++ drivers/media/pci/ngene/ngene-cards.c | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index f717567f54a5..e06d019996f3 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -11,6 +11,9 @@ config DVB_NGENE select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index cdc8db14c606..00b100660784 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -46,6 +46,9 @@ #include "stv0367_priv.h" #include "tda18212.h" #include "cxd2841er.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" /****************************************************************************/ /* I2C transfer functions used for demod/tuner probing***********************/ @@ -152,6 +155,30 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } +static int tuner_attach_stv6111(struct ngene_channel *chan) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); + if (!fe) { + dev_err(pdev, "stv6111_attach() failed!\n"); + return -ENODEV; + } + } + return 0; +} + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -283,6 +310,8 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_SONY_C2T2: case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); + case DEMOD_TYPE_STV0910: + return tuner_attach_stv6111(chan); } return -EINVAL; @@ -326,6 +355,54 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 30000000, +}; + +static struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1)); + if (!chan->fe) { + cfg.adr = 0x6c; + chan->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (chan->number & 1)); + } + if (!chan->fe) { + dev_err(pdev, "stv0910_attach() failed!\n"); + return -ENODEV; + } + + /* + * attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit + * i2c addresses + */ + lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + dev_err(pdev, "lnbh25_attach() failed!\n"); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + return -ENODEV; + } + } + + return 0; +} + static struct stv0367_config ddb_stv0367_config[] = { { .demod_address = 0x1f, @@ -586,6 +663,12 @@ static int cineS2_probe(struct ngene_channel *chan) demod_attach_cxd28xx(chan, i2c, sony_osc24); break; + case DEMOD_TYPE_STV0910: + dev_info(pdev, "%s (XO2) on channel %d\n", + xo2names[xo2_id], chan->number); + chan->demod_type = xo2_demodtype; + demod_attach_stv0910(chan, i2c); + break; default: dev_warn(pdev, "Unsupported XO2 module on channel %d\n", -- cgit From ee93340e98bc9026dedf6e7483f9f092d1765582 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:36 -0500 Subject: media: ngene: deduplicate I2C adapter evaluation The I2C adapter evaluation (based on chan->number) is duplicated at several places (tuner_attach_() functions, demod_attach_stv0900() and cineS2_probe()). Clean this up by wrapping that construct in a separate function which all users of that can pass the ngene_channel pointer and get the correct I2C adapter from. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 41 +++++++++++++---------------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 00b100660784..dff55c7c9f86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -118,17 +118,25 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) /* Demod/tuner attachment ***************************************************/ /****************************************************************************/ +static struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan) +{ + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + return &chan->dev->channel[0].i2c_adapter; + + return &chan->dev->channel[1].i2c_adapter; +} + static int tuner_attach_stv6110(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; struct stv6110x_config *tunerconf = (struct stv6110x_config *) chan->dev->card_info->tuner_config[chan->number]; const struct stv6110x_devctl *ctl; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ if (chan->number < 2) i2c = &chan->dev->channel[0].i2c_adapter; else @@ -158,16 +166,10 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) static int tuner_attach_stv6111(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); if (!fe) { fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); @@ -197,10 +199,9 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; - i2c = &chan->dev->channel[0].i2c_adapter; if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); @@ -240,7 +241,7 @@ static int tuner_tda18212_ping(struct ngene_channel *chan, static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct i2c_client *client; struct tda18212_config config = { .fe = chan->fe, @@ -262,12 +263,6 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) else board_info.addr = 0x60; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when @@ -320,7 +315,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -620,7 +615,7 @@ static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) static int cineS2_probe(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *fe_conf; u8 buf[3]; u8 xo2_type, xo2_id, xo2_demodtype; @@ -628,12 +623,6 @@ static int cineS2_probe(struct ngene_channel *chan) struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - if (port_has_xo2(i2c, &xo2_type, &xo2_id)) { xo2_id >>= 2; dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n", -- cgit From e39b8e945eb749d3bef21b38309f84de8f7a3007 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:37 -0500 Subject: media: ngene: check for CXD2099AR presence before attaching Currently, if there's no CXD2099AR attached to any expansion connector of the ngene hardware, it will complain with this on every module load: cxd2099 1-0040: No CXD2099AR detected at 0x40 cxd2099: probe of 1-0040 failed with error -5 ngene 0000:02:00.0: CXD2099AR attach failed This happens due to the logic assuming such hardware is always there and blindly tries to attach the cxd2099 I2C driver. Rather add a probe function (in ngene-cards.c with a prototype in ngene.h) to check for the existence of such hardware before probing, and don't try further if no CXD2099 was found. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 19 +++++++++++++++++++ drivers/media/pci/ngene/ngene-core.c | 14 ++++++++++++++ drivers/media/pci/ngene/ngene.h | 3 +++ 3 files changed, 36 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index dff55c7c9f86..d603d0af703e 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -505,6 +505,25 @@ static int port_has_stv0367(struct i2c_adapter *i2c) return 1; } +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type) +{ + u8 val; + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(i2c, msgs, 2); + if (val != 2) + return 0; + + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; + return 1; +} + static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 526d0adfa427..f69a8fc1ec2a 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1589,6 +1589,20 @@ static void cxd_attach(struct ngene *dev) .addr = 0x40, .platform_data = &cxd_cfg, }; + int ret; + u8 type; + + /* check for CXD2099AR presence before attaching */ + ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type); + if (!ret) { + dev_dbg(pdev, "No CXD2099AR found\n"); + return; + } + + if (type != 1) { + dev_warn(pdev, "CXD2099AR is uninitialized!\n"); + return; + } cxd_cfg.en = &ci->en; diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 72195f6552b3..66d8eaa28549 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -909,6 +909,9 @@ int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); void set_transfer(struct ngene_channel *chan, int state); void FillTSBuffer(void *Buffer, int Length, u32 Flags); +/* Provided by ngene-cards.c */ +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type); + /* Provided by ngene-i2c.c */ int ngene_i2c_init(struct ngene *dev, int dev_nr); -- cgit From 96c7bc8c7e9ddbc3887e6f9dc3079d5ab896a3a3 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 07:31:38 -0500 Subject: media: ngene: don't treat non-existing demods as error When probing the I2C busses in cineS2_probe(), it's no error when there's no hardware connected to the probed expansion connector, so print this informal message with info severity. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index d603d0af703e..37e9f0eb6d20 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -728,7 +728,7 @@ static int cineS2_probe(struct ngene_channel *chan) dev_info(pdev, "STV0367 on channel %d\n", chan->number); demod_attach_stv0367(chan, i2c); } else { - dev_err(pdev, "No demod found on chan %d\n", chan->number); + dev_info(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; } return 0; -- cgit From 6294513dbe61ba0ab1d9201cd3b283fe1cfc7617 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 25 Feb 2018 12:06:56 -0500 Subject: media: ngene: add proper polling to the dvbdev_ci file ops Implement the poll callback for the dvbdev_ci file ops. The ts_poll() function queries the DVB ring buffers for available data and space, and reports this as appropriate. Also, set the dvb_device readers, writers and users to proper values (one reader, one writer, two users). This fixes the raw CI TS transport in conjunction with TVheadend's DDCI functionality. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-dvb.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index f71fd41c762c..65c79f1b36f7 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -84,18 +84,41 @@ static ssize_t ts_read(struct file *file, char __user *buf, return count; } +static __poll_t ts_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf; + struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf; + __poll_t mask = 0; + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= EPOLLIN | EPOLLRDNORM; + if (dvb_ringbuffer_free(wbuf) >= 188) + mask |= EPOLLOUT | EPOLLWRNORM; + + return mask; +} + static const struct file_operations ci_fops = { .owner = THIS_MODULE, .read = ts_read, .write = ts_write, .open = dvb_generic_open, .release = dvb_generic_release, + .poll = ts_poll, + .mmap = NULL, }; struct dvb_device ngene_dvbdev_ci = { - .readers = -1, - .writers = -1, - .users = -1, + .priv = NULL, + .readers = 1, + .writers = 1, + .users = 2, .fops = &ci_fops, }; -- cgit From 99b010b66f0d60173f1c83d33d9ec1d14c62db26 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:34 -0500 Subject: media: tw9910: Re-organize in-code comments A lot of comments that would fit a single line were spread on two or more lines. Also fix capitalization and punctuation where appropriate. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index cc5d383fc6b8..3d89a144d23e 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -388,7 +388,7 @@ static int tw9910_set_hsync(struct i2c_client *client) if (ret < 0) return ret; - /* So far only revisions 0 and 1 have been seen */ + /* So far only revisions 0 and 1 have been seen. */ /* bit 2 - 0 */ if (priv->revision == 1) ret = tw9910_mask_set(client, HSLOWCTL, 0x77, @@ -653,21 +653,15 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) int ret = -EINVAL; u8 val; - /* - * select suitable norm - */ + /* Select suitable norm. */ priv->scale = tw9910_select_norm(priv->norm, *width, *height); if (!priv->scale) goto tw9910_set_fmt_error; - /* - * reset hardware - */ + /* Reset hardware. */ tw9910_reset(client); - /* - * set bus width - */ + /* Set bus width. */ val = 0x00; if (priv->info->buswidth == 16) val = LEN; @@ -676,9 +670,7 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) if (ret < 0) goto tw9910_set_fmt_error; - /* - * select MPOUT behavior - */ + /* Select MPOUT behavior. */ switch (priv->info->mpout) { case TW9910_MPO_VLOSS: val = RTSEL_VLOSS; break; @@ -704,16 +696,12 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) if (ret < 0) goto tw9910_set_fmt_error; - /* - * set scale - */ + /* Set scale. */ ret = tw9910_set_scale(client, priv->scale); if (ret < 0) goto tw9910_set_fmt_error; - /* - * set hsync - */ + /* Set hsync. */ ret = tw9910_set_hsync(client); if (ret < 0) goto tw9910_set_fmt_error; @@ -740,7 +728,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd, if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; - /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */ + /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported. */ if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS) return -EINVAL; @@ -791,9 +779,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, WARN_ON(mf->field != V4L2_FIELD_ANY && mf->field != V4L2_FIELD_INTERLACED_BT); - /* - * check color format - */ + /* Check color format. */ if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8) return -EINVAL; @@ -829,9 +815,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, mf->code = MEDIA_BUS_FMT_UYVY8_2X8; mf->colorspace = V4L2_COLORSPACE_SMPTE170M; - /* - * select suitable norm - */ + /* Select suitable norm. */ scale = tw9910_select_norm(priv->norm, mf->width, mf->height); if (!scale) return -EINVAL; @@ -851,9 +835,7 @@ static int tw9910_video_probe(struct i2c_client *client) s32 id; int ret; - /* - * tw9910 only use 8 or 16 bit bus width - */ + /* TW9910 only use 8 or 16 bit bus width. */ if (priv->info->buswidth != 16 && priv->info->buswidth != 8) { dev_err(&client->dev, "bus width error\n"); return -ENODEV; @@ -864,8 +846,8 @@ static int tw9910_video_probe(struct i2c_client *client) return ret; /* - * check and show Product ID - * So far only revisions 0 and 1 have been seen + * Check and show Product ID. + * So far only revisions 0 and 1 have been seen. */ id = i2c_smbus_read_byte_data(client, ID); priv->revision = GET_REV(id); -- cgit From d6fdad5541922edd0f40c1cc0a86990b94229069 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 1 Mar 2018 06:50:22 -0500 Subject: media: tw9910: Whitespace alignment Update multiline statements to open parenthesis. Update a ?: to a single line. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 3d89a144d23e..ceaad7dd05c2 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -445,7 +445,7 @@ static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, for (i = 0; i < size; i++) { tmp = abs(width - scale[i].width) + - abs(height - scale[i].height); + abs(height - scale[i].height); if (tmp < diff) { diff = tmp; ret = scale + i; @@ -534,9 +534,9 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) if (!ret) ret = i2c_smbus_write_byte_data(client, CROP_HI, ((vdelay >> 2) & 0xc0) | - ((vact >> 4) & 0x30) | - ((hdelay >> 6) & 0x0c) | - ((hact >> 8) & 0x03)); + ((vact >> 4) & 0x30) | + ((hdelay >> 6) & 0x0c) | + ((hact >> 8) & 0x03)); if (!ret) ret = i2c_smbus_write_byte_data(client, VDELAY_LO, vdelay & 0xff); @@ -642,8 +642,7 @@ static int tw9910_s_power(struct v4l2_subdev *sd, int on) struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); - return on ? tw9910_power_on(priv) : - tw9910_power_off(priv); + return on ? tw9910_power_on(priv) : tw9910_power_off(priv); } static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) @@ -721,7 +720,7 @@ tw9910_set_fmt_error: static int tw9910_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_selection *sel) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); @@ -746,7 +745,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd, static int tw9910_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -795,7 +794,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, static int tw9910_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -882,7 +881,7 @@ static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + struct v4l2_subdev_mbus_code_enum *code) { if (code->pad || code->index) return -EINVAL; -- cgit From cb5fd12afd9af8d40b330e45665d46dca6feeef2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 1 Mar 2018 07:01:22 -0500 Subject: media: tw9910: Miscellaneous neatening Yet more whitespace and style neatening o Add blank lines before returns o Reverse a logic test and return early on error o Move formats to same line as dev_ calls o Remove an unnecessary period from a logging message Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index ceaad7dd05c2..2d5cdb944330 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -740,6 +740,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd, sel->r.width = 768; sel->r.height = 576; } + return 0; } @@ -785,11 +786,13 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ret = tw9910_set_frame(sd, &width, &height); - if (!ret) { - mf->width = width; - mf->height = height; - } - return ret; + if (ret) + return ret; + + mf->width = width; + mf->height = height; + + return 0; } static int tw9910_set_fmt(struct v4l2_subdev *sd, @@ -807,7 +810,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (mf->field == V4L2_FIELD_ANY) { mf->field = V4L2_FIELD_INTERLACED_BT; } else if (mf->field != V4L2_FIELD_INTERLACED_BT) { - dev_err(&client->dev, "Field type %d invalid.\n", mf->field); + dev_err(&client->dev, "Field type %d invalid\n", mf->field); return -EINVAL; } @@ -824,7 +827,9 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd, if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return tw9910_s_fmt(sd, mf); + cfg->try_fmt = *mf; + return 0; } @@ -853,21 +858,21 @@ static int tw9910_video_probe(struct i2c_client *client) id = GET_ID(id); if (id != 0x0b || priv->revision > 0x01) { - dev_err(&client->dev, - "Product ID error %x:%x\n", + dev_err(&client->dev, "Product ID error %x:%x\n", id, priv->revision); ret = -ENODEV; goto done; } - dev_info(&client->dev, - "tw9910 Product ID %0x:%0x\n", id, priv->revision); + dev_info(&client->dev, "tw9910 Product ID %0x:%0x\n", + id, priv->revision); priv->norm = V4L2_STD_NTSC; priv->scale = &tw9910_ntsc_scales[0]; done: tw9910_s_power(&priv->subdev, 0); + return ret; } @@ -887,12 +892,14 @@ static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; code->code = MEDIA_BUS_FMT_UYVY8_2X8; + return 0; } static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) { *norm = V4L2_STD_NTSC | V4L2_STD_PAL; + return 0; } -- cgit From 5d1787e75ee23af00bd7c7d28a07c5671a1543c1 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:35 -0500 Subject: media: tw9910: Mixed style fixes Two minor style fixes, align function parameter and remove un-necessary spaces. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 2d5cdb944330..7c7f3438781c 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -533,9 +533,9 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) } if (!ret) ret = i2c_smbus_write_byte_data(client, CROP_HI, - ((vdelay >> 2) & 0xc0) | - ((vact >> 4) & 0x30) | - ((hdelay >> 6) & 0x0c) | + ((vdelay >> 2) & 0xc0) | + ((vact >> 4) & 0x30) | + ((hdelay >> 6) & 0x0c) | ((hact >> 8) & 0x03)); if (!ret) ret = i2c_smbus_write_byte_data(client, VDELAY_LO, @@ -954,7 +954,7 @@ static int tw9910_probe(struct i2c_client *client, if (!priv) return -ENOMEM; - priv->info = info; + priv->info = info; v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); -- cgit From 7470230a43c5a60a8c9d8d89000f401197ea6d64 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:36 -0500 Subject: media: tw9910: Sort includes alphabetically Sort include directives alphabetically to ease maintenance. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 7c7f3438781c..1fbed4432e36 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -16,13 +16,13 @@ */ #include +#include #include +#include #include +#include #include -#include #include -#include -#include #include #include -- cgit From 7bd8c4f2e8006972c8d4b17f5c5b632334912980 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:37 -0500 Subject: media: tw9910: Replace msleep(1) with usleep_range msleep() can sleep up to 20ms. As suggested by Documentation/timers/timers_howto.txt replace it with usleep_range() with up to 5ms delay. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 1fbed4432e36..a54548cc4285 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -401,7 +401,7 @@ static int tw9910_set_hsync(struct i2c_client *client) static void tw9910_reset(struct i2c_client *client) { tw9910_mask_set(client, ACNTL1, SRESET, SRESET); - msleep(1); + usleep_range(1000, 5000); } static int tw9910_power(struct i2c_client *client, int enable) -- cgit From eee34d8b784a4203863908f3ab67aa0830f18c8c Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:38 -0500 Subject: media: ov772x: Align function parameters Align all function parameters to first open brace when declaring functions. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 321105bb3161..768ffe81daca 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1064,7 +1064,7 @@ ov772x_set_fmt_error: static int ov772x_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_selection *sel) { struct ov772x_priv *priv = to_ov772x(sd); @@ -1087,7 +1087,7 @@ static int ov772x_get_selection(struct v4l2_subdev *sd, static int ov772x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; struct ov772x_priv *priv = to_ov772x(sd); @@ -1106,7 +1106,7 @@ static int ov772x_get_fmt(struct v4l2_subdev *sd, static int ov772x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_format *format) { struct ov772x_priv *priv = to_ov772x(sd); struct v4l2_mbus_framefmt *mf = &format->format; @@ -1219,7 +1219,7 @@ static int ov772x_enum_frame_interval(struct v4l2_subdev *sd, static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + struct v4l2_subdev_mbus_code_enum *code) { if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) return -EINVAL; -- cgit From 2a2f21e38aa6d11ffbcdde22defc7b06f3d1fe53 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:39 -0500 Subject: media: ov772x: Re-organize in-code comments A lot of comments that would fit a single line were spread on two or more lines. Also fix capitalization and punctuation where appropriate. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 768ffe81daca..59f3eb38d580 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -910,17 +910,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, int ret; u8 val; - /* - * reset hardware - */ + /* Reset hardware. */ ov772x_reset(client); - /* - * Edge Ctrl - */ + /* Edge Ctrl. */ if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { /* - * Manual Edge Control Mode + * Manual Edge Control Mode. * * Edge auto strength bit is set by default. * Remove it when manual mode. @@ -944,9 +940,9 @@ static int ov772x_set_params(struct ov772x_priv *priv, } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) { /* - * Auto Edge Control Mode + * Auto Edge Control Mode. * - * set upper and lower limit + * Set upper and lower limit. */ ret = ov772x_mask_set(client, EDGE_UPPER, OV772X_EDGE_UPPER_MASK, @@ -961,7 +957,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, goto ov772x_set_fmt_error; } - /* Format and window size */ + /* Format and window size. */ ret = ov772x_write(client, HSTART, win->rect.left >> 2); if (ret < 0) goto ov772x_set_fmt_error; @@ -993,9 +989,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, if (ret < 0) goto ov772x_set_fmt_error; - /* - * set DSP_CTRL3 - */ + /* Set DSP_CTRL3. */ val = cfmt->dsp3; if (val) { ret = ov772x_mask_set(client, @@ -1011,9 +1005,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, goto ov772x_set_fmt_error; } - /* - * set COM3 - */ + /* Set COM3. */ val = cfmt->com3; if (priv->info->flags & OV772X_FLAG_VFLIP) val |= VFLIP_IMG; @@ -1041,9 +1033,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, if (ret < 0) goto ov772x_set_fmt_error; - /* - * set COM8 - */ + /* Set COM8. */ if (priv->band_filter) { ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); if (!ret) @@ -1153,9 +1143,7 @@ static int ov772x_video_probe(struct ov772x_priv *priv) if (ret < 0) return ret; - /* - * check and show product ID and manufacturer ID - */ + /* Check and show product ID and manufacturer ID. */ pid = ov772x_read(client, PID); ver = ov772x_read(client, VER); -- cgit From e0853a4324ad48ea5dd40720227270e7e0464006 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:40 -0500 Subject: media: ov772x: Empty line before end-of-function return Add an empty line before return at the end of functions. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 59f3eb38d580..093a8040cfd2 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1129,6 +1129,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd, priv->win = win; priv->cfmt = cfmt; + return 0; } @@ -1172,6 +1173,7 @@ static int ov772x_video_probe(struct ov772x_priv *priv) done: ov772x_s_power(&priv->subdev, 0); + return ret; } @@ -1213,6 +1215,7 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; code->code = ov772x_cfmts[code->index].code; + return 0; } @@ -1327,6 +1330,7 @@ static int ov772x_remove(struct i2c_client *client) gpiod_put(priv->pwdn_gpio); v4l2_device_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); + return 0; } -- cgit From d9c70bbd39a5b076e1eaa88d53530d0219f7630e Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:42 -0500 Subject: media: ov772x: Replace msleep(1) with usleep_range msleep() can sleep up to 20ms. As suggested by Documentation/timers/timers_howto.txt replace it with usleep_range() with up to 5ms delay. Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 093a8040cfd2..7fdf54e57ce0 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -574,7 +574,7 @@ static int ov772x_reset(struct i2c_client *client) if (ret < 0) return ret; - msleep(1); + usleep_range(1000, 5000); return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); } -- cgit From 27a48feac025f121414e6953912312c395f6a7f9 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 2 Mar 2018 09:46:43 -0500 Subject: media: ov772x: Unregister async subdevice As the media subdevice is registered with 'v4l2_async_register_subdev()' unregister it at module removal time with 'v4l2_async_unregister_subdev()' Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 7fdf54e57ce0..b62860c89439 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1328,7 +1328,7 @@ static int ov772x_remove(struct i2c_client *client) clk_put(priv->clk); if (priv->pwdn_gpio) gpiod_put(priv->pwdn_gpio); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; -- cgit From e5eaf6f88b9deac71f6985fa5f84dcd68087a64c Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Tue, 6 Mar 2018 11:39:10 -0500 Subject: media: ddbridge: adapt cxd2099 attach to new i2c_client way Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-ci.c | 62 +++++++++++++++++++++++++++++--- drivers/media/pci/ddbridge/ddbridge.h | 1 + 2 files changed, 58 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index ed19890710d6..6585ef54ac22 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port) memcpy(&ci->en, &en_templ, sizeof(en_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; } @@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port) memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; ci->port->creg = 0; @@ -311,20 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port) write_creg(ci, 0x08, 0x08); } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 72000, - .adr = 0x40, .polarity = 1, .clock_mode = 1, .max_i2c = 512, }; +static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) +{ + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.bitrate = bitrate; + cxd_cfg.en = &port->en; + + request_module(board_info.type); + + client = i2c_new_device(&port->i2c->adap, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!port->en) + goto err_i2c; + + port->dvb[0].i2c_client[0] = client; + port->en_freedata = 0; + return 0; + +err_i2c: + i2c_unregister_device(client); +err_ret: + dev_err(port->dev->dev, "CXD2099AR attach failed\n"); + return -ENODEV; +} + int ddb_ci_attach(struct ddb_port *port, u32 bitrate) { + int ret; + switch (port->type) { case DDB_CI_EXTERNAL_SONY: - cxd_cfg.bitrate = bitrate; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + ret = ci_cxd2099_attach(port, bitrate); + if (ret) + return -ENODEV; break; case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: @@ -345,11 +385,23 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { + struct i2c_client *client; + if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - kfree(port->en->data); + + client = port->dvb[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* free alloc'ed memory if needed */ + if (port->en_freedata) + kfree(port->en->data); + port->en = NULL; } } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 095457737bc1..f223dc6c9963 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -276,6 +276,7 @@ struct ddb_port { struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + u8 en_freedata; struct ddb_dvb dvb[2]; u32 gap; u32 obr; -- cgit From 643f06fbe01730359b525b382f85dae906d6f2df Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Tue, 6 Mar 2018 11:39:11 -0500 Subject: media: ngene: add I2C_FUNC_I2C to the I2C interface functionality Report I2C_FUNC_I2C in .functionality() as well. The I2C interface can handle this fine and even is required for all I2C client drivers that utilise the regmap API which are used from within the ngene driver. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index 3004947f300b..092d46c2a3a9 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -147,7 +147,7 @@ done: static u32 ngene_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm ngene_i2c_algo = { -- cgit From 7bb02ee380c7463746bd71be5e6e69ef751fd809 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Tue, 6 Mar 2018 11:39:12 -0500 Subject: media: dvb-frontends/cxd2099: remove remainders from old attach way As all drivers using the cxd2099 are converted to handle attach/detach the generic I2C client way, the static inline cxd2099_attach isn't required anymore. Thus cleanup cxd2099.h from the remainders, the adr struct member also isn't used anymore. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2099.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h index 679e87512799..8fa45a4c615a 100644 --- a/drivers/media/dvb-frontends/cxd2099.h +++ b/drivers/media/dvb-frontends/cxd2099.h @@ -20,7 +20,6 @@ struct cxd2099_cfg { u32 bitrate; - u8 adr; u8 polarity; u8 clock_mode; @@ -30,13 +29,4 @@ struct cxd2099_cfg { struct dvb_ca_en50221 **en; }; -/* TODO: remove when done */ -static inline struct -dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, - struct i2c_adapter *i2c) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - #endif -- cgit From 309131594016651ab44753ea447a36987e8f4c23 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Tue, 27 Feb 2018 12:32:52 -0500 Subject: media: platform: renesas-ceu: Fix CSTRST_CPON mask The CSTRST_CPON mask was wrongly assigned to BIT(1) instead of BIT(0). Fix that by changing the mask opportunely. Reported-by: Dylan Laduranty Signed-off-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas-ceu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index bd64cad542df..903c05c67d91 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -95,7 +95,7 @@ /* CEU operating flag bit. */ #define CEU_CAPCR_CTNCP BIT(16) -#define CEU_CSTRST_CPTON BIT(1) +#define CEU_CSTRST_CPTON BIT(0) /* Platform specific IRQ source flags. */ #define CEU_CETCR_ALL_IRQS_RZ 0x397f313 -- cgit From 997ef6b2627c54f5404c2f444e52c7140d1b6d01 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Feb 2018 18:19:37 -0500 Subject: media: renesas-ceu: mark PM functions as __maybe_unused The PM runtime operations are unused when CONFIG_PM is disabled, leading to a harmless warning: drivers/media/platform/renesas-ceu.c:1003:12: error: 'ceu_runtime_suspend' defined but not used [-Werror=unused-function] static int ceu_runtime_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~ drivers/media/platform/renesas-ceu.c:987:12: error: 'ceu_runtime_resume' defined but not used [-Werror=unused-function] static int ceu_runtime_resume(struct device *dev) ^~~~~~~~~~~~~~~~~~ This adds a __maybe_unused annotation to shut up the warning. Fixes: 32e5a70dc8f4 ("media: platform: Add Renesas CEU driver") Signed-off-by: Arnd Bergmann Reviewed-by: Simon Horman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas-ceu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index 903c05c67d91..6599dba5ab84 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -984,7 +984,7 @@ static int ceu_init_mbus_fmt(struct ceu_device *ceudev) /* * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. */ -static int ceu_runtime_resume(struct device *dev) +static int __maybe_unused ceu_runtime_resume(struct device *dev) { struct ceu_device *ceudev = dev_get_drvdata(dev); struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; @@ -1000,7 +1000,7 @@ static int ceu_runtime_resume(struct device *dev) * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. * Turn sensor power off. */ -static int ceu_runtime_suspend(struct device *dev) +static int __maybe_unused ceu_runtime_suspend(struct device *dev) { struct ceu_device *ceudev = dev_get_drvdata(dev); struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; -- cgit From 67f2219ce1d11a0e160f6aa0b463aee1614f0b9c Mon Sep 17 00:00:00 2001 From: Shunqian Zheng Date: Thu, 1 Mar 2018 03:44:16 -0500 Subject: media: ov2685: Not delay latch for gain Update the register 0x3503 to use 'no delay latch' for gain. This makes sensor to output the first frame as normal rather than a very dark one. Signed-off-by: Shunqian Zheng Reviewed-by: Tomasz Figa Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2685.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 9ac702e3ae95..83c55e8288e7 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -119,7 +119,7 @@ static struct regval ov2685_1600x1200_regs[] = { {0x3087, 0x00}, {0x3501, 0x4e}, {0x3502, 0xe0}, - {0x3503, 0x07}, + {0x3503, 0x27}, {0x350b, 0x36}, {0x3600, 0xb4}, {0x3603, 0x35}, -- cgit From f68e68d2923069fd9b21aa1e7ed445cda2f6db05 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 1 Mar 2018 05:07:14 -0500 Subject: media: ov5695: Off by one in ov5695_enum_frame_sizes() The ">" should be ">=" so that we don't read one element beyond the end of the array. Fixes: 8a77009be4be ("media: ov5695: add support for OV5695 sensor") Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5695.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index a4985a4715f5..9be38a0a2046 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -884,7 +884,7 @@ static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->index > ARRAY_SIZE(supported_modes)) + if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) -- cgit From 564246fd3ff41afd3234c18ae28bc4ad9d815f79 Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Sat, 3 Mar 2018 13:20:56 -0500 Subject: media: siano: Fix coherent memory allocation failure on arm64 On some architectures such as arm64, siano chip based TV-tuner USB devices are not recognized correctly due to coherent memory allocation failure with the following error: [ 663.556135] usbcore: deregistering interface driver smsusb [ 683.624809] smsusb:smsusb_probe: board id=18, interface number 0 [ 683.633530] smsusb:smsusb_init_device: smscore_register_device(...) failed, rc -12 [ 683.641501] smsusb:smsusb_probe: Device initialized with return code -12 [ 683.652978] smsusb: probe of 1-1:1.0 failed with error -12 This is caused by dma_alloc_coherent(NULL, ...) returning NULL in smscoreapi.c. To fix this error, allocate the buffer memory for the USB devices via kmalloc() and let the USB core do the DMA mapping and free. Signed-off-by: Tomoki Sekiyama Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 33 ++++++++++++++++++++++----------- drivers/media/common/siano/smscoreapi.h | 2 ++ drivers/media/usb/siano/smsusb.c | 4 ++-- 3 files changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index c5c827e11b64..b5dcc6d1fe90 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, cb->p = buffer; cb->offset_in_common = buffer - (u8 *) common_buffer; - cb->phys = common_buffer_phys + cb->offset_in_common; + if (common_buffer_phys) + cb->phys = common_buffer_phys + cb->offset_in_common; return cb; } @@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params, /* alloc common buffer */ dev->common_buffer_size = params->buffer_size * params->num_buffers; - dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, - &dev->common_buffer_phys, - GFP_KERNEL | GFP_DMA); - if (!dev->common_buffer) { + if (params->usb_device) + buffer = kzalloc(dev->common_buffer_size, GFP_KERNEL); + else + buffer = dma_alloc_coherent(params->device, + dev->common_buffer_size, + &dev->common_buffer_phys, + GFP_KERNEL | GFP_DMA); + if (!buffer) { smscore_unregister_device(dev); return -ENOMEM; } + dev->common_buffer = buffer; /* prepare dma buffers */ - for (buffer = dev->common_buffer; - dev->num_buffers < params->num_buffers; + for (; dev->num_buffers < params->num_buffers; dev->num_buffers++, buffer += params->buffer_size) { struct smscore_buffer_t *cb; @@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params, dev->board_id = SMS_BOARD_UNKNOWN; dev->context = params->context; dev->device = params->device; + dev->usb_device = params->usb_device; dev->setmode_handler = params->setmode_handler; dev->detectmode_handler = params->detectmode_handler; dev->sendrequest_handler = params->sendrequest_handler; @@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev) pr_debug("freed %d buffers\n", num_buffers); - if (coredev->common_buffer) - dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, coredev->common_buffer_phys); - + if (coredev->common_buffer) { + if (coredev->usb_device) + kfree(coredev->common_buffer); + else + dma_free_coherent(coredev->device, + coredev->common_buffer_size, + coredev->common_buffer, + coredev->common_buffer_phys); + } kfree(coredev->fw_buf); list_del(&coredev->entry); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 4cc39e4a8318..134c69f7ea7b 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -134,6 +134,7 @@ struct smscore_buffer_t { struct smsdevice_params_t { struct device *device; + struct usb_device *usb_device; int buffer_size; int num_buffers; @@ -176,6 +177,7 @@ struct smscore_device_t { void *context; struct device *device; + struct usb_device *usb_device; char devpath[32]; unsigned long device_flags; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index f13e4b01b5a5..6d436e9e454f 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -179,8 +179,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, smsusb_onresponse, surb ); - surb->urb.transfer_dma = surb->cb->phys; - surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + surb->urb.transfer_flags |= URB_FREE_BUFFER; return usb_submit_urb(&surb->urb, GFP_ATOMIC); } @@ -446,6 +445,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) dev->in_ep, dev->out_ep); params.device = &dev->udev->dev; + params.usb_device = dev->udev; params.buffer_size = dev->buffer_size; params.num_buffers = MAX_BUFFERS; params.sendrequest_handler = smsusb_sendrequest; -- cgit From e5fc6767ea4705b1b50de2eb73a99481f5cc1e96 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Tue, 6 Mar 2018 12:46:36 -0500 Subject: media: ngene: move the tsin_exchange() stripcopy block into a function Move the copy logic that will skip previously inserted TS NULL frames when moving data to the DVB ring buffers into an own function. This is done to not duplicate code all over the place with the following TS offset shift fixup patch. While we're touching this part of the code, get rid of the DEBUG_CI_XFER debug-ifdeffery. This could be toggleable either by a Kconfig or a module param, but in the end this will accidentally be enabled and cause lots of kernel log messages, and such devel debug shouldn't be there anyway. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-dvb.c | 39 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 65c79f1b36f7..93a07a370cfd 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -139,12 +139,15 @@ static void swap_buffer(u32 *p, u32 len) /* start of filler packet */ static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; -/* #define DEBUG_CI_XFER */ -#ifdef DEBUG_CI_XFER -static u32 ok; -static u32 overflow; -static u32 stripped; -#endif +static inline void tsin_copy_stripped(struct ngene *dev, void *buf) +{ + if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); + } + } +} void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { @@ -157,28 +160,8 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) if (dev->ci.en && chan->number == 2) { while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif - } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif - } -#ifdef DEBUG_CI_XFER - else - stripped++; - - if (ok % 100 == 0 && overflow) - dev_warn(&dev->pci_dev->dev, - "%s: ok %u overflow %u dropped %u\n", - __func__, ok, overflow, stripped); -#endif + tsin_copy_stripped(dev, buf); + buf += 188; len -= 188; } -- cgit From 60d0bbec5965590d72b1a2091ec7a2cc589cb8e0 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Tue, 6 Mar 2018 12:46:37 -0500 Subject: media: ngene: compensate for TS buffer offset shifts A possible hardware bug was discovered when using CA addon hardware attached to the ngene hardware, in that the TS input buffer much likely will shift and thus become unaligned to 188 byte blocks (a full TS frame) when things like CA module initialisation (which happens via differing communication paths) take place. This causes the TS NULL removal in tsin_exchange() to fail to detect this previously inserted data and thus causes userspace applications to receive data they didn't sent beforehand and ultimately cause troubles. On driver load with an inserted CAM, buffers are fine at first (note that the driver has to keep the communication running from/to the card by inserting TS NULL frames, this is done in tsout_exchange() via FillTSBuffer() - that data is simply sent back by the hardware): offset | 0 1 2 3 4 5 .... 188 189 190 191 192 193 .... 376 data | 47 1f ff 10 6f 6f .... 47 1f ff 10 6f 6f .... 47 After a few seconds, the CA module is recognised and initialised, which is signalled by dvb_ca_en50221: dvb_ca adapter X: DVB CAM detected and initialised successfully This is where the first shift happens (this is always four bytes), buffer becomes like this: offset | 0 1 2 3 4 5 .... 188 189 190 191 192 193 .... 376 data | 6f 6f 6f 6f 47 1f .... 6f 6f 6f 6f 47 1f .... 6f Next, VDR, TVHeadend or any other CI aware application is started, buffers will shift by even more bytes. It is believed this is due to the hardware not handling control and data bytes properly distinct, and control data having an influence on the actual data stream, which we cannot properly detect at the driver level. Workaround this hardware quirk by adding a detection for the TS sync byte 0x47 before each TS frame copy, scan for a new SYNC byte and a TS NULL packet if buffers become unaligned, take note of that offset and apply that when copying data to the DVB ring buffers. The last <188 bytes from the hardware buffers are stored in a temp buffer (tsin_buffer), for which the remainder will be in the beginning of the next hardware buffer (next iteration of tsin_exchange()). That remainder will be appended to the temp buffer and finally sent to the DVB ring buffer. The resulting TS stream is perfectly fine, and the TS NULL packets inserted by the driver which are sent back are properly removed. The resulting offset is being clamped to 188 byte segments (one TS packet). Though this can result in a repeated TS packet if the overall offset grows beyond this (and it will grow only on CA initialisation), this is still way better than unaligned TS frames and data sent to userspace that just isn't supposed to be there. This compensation can be toggled by the ci_tsfix modparam, which defaults to 1 (enabled). In the case of problems, this can be turned off by setting the parameter to 0 to restore the old behaviour. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-dvb.c | 91 ++++++++++++++++++++++++++++++++++++- drivers/media/pci/ngene/ngene.h | 3 ++ 2 files changed, 93 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 93a07a370cfd..fee89b9ed9c1 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #include "ngene.h" +static int ci_tsfix = 1; +module_param(ci_tsfix, int, 0444); +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); /****************************************************************************/ /* COMMAND API interface ****************************************************/ @@ -139,6 +142,24 @@ static void swap_buffer(u32 *p, u32 len) /* start of filler packet */ static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; +static int tsin_find_offset(void *buf, u32 len) +{ + int i, l; + + l = len - sizeof(fill_ts); + if (l <= 0) + return -1; + + for (i = 0; i < l; i++) { + if (((char *)buf)[i] == 0x47) { + if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) + return i % 188; + } + } + + return -1; +} + static inline void tsin_copy_stripped(struct ngene *dev, void *buf) { if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { @@ -153,18 +174,86 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; struct ngene *dev = chan->dev; - + int tsoff; if (flags & DF_SWAP32) swap_buffer(buf, len); if (dev->ci.en && chan->number == 2) { + /* blindly copy buffers if ci_tsfix is disabled */ + if (!ci_tsfix) { + while (len >= 188) { + tsin_copy_stripped(dev, buf); + + buf += 188; + len -= 188; + } + return NULL; + } + + /* ci_tsfix = 1 */ + + /* + * since the remainder of the TS packet which got cut off + * in the previous tsin_exchange() run is at the beginning + * of the new TS buffer, append this to the temp buffer and + * send it to the DVB ringbuffer afterwards. + */ + if (chan->tsin_offset) { + memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)], + buf, chan->tsin_offset); + tsin_copy_stripped(dev, &chan->tsin_buffer); + + buf += chan->tsin_offset; + len -= chan->tsin_offset; + } + + /* + * copy TS packets to the DVB ringbuffer and detect new offset + * shifts by checking for a valid TS SYNC byte + */ while (len >= 188) { + if (*((char *)buf) != 0x47) { + /* + * no SYNC header, find new offset shift + * (max. 188 bytes, tsoff will be mod 188) + */ + tsoff = tsin_find_offset(buf, len); + if (tsoff > 0) { + chan->tsin_offset += tsoff; + chan->tsin_offset %= 188; + + buf += tsoff; + len -= tsoff; + + dev_info(&dev->pci_dev->dev, + "%s(): tsin_offset shift by %d on channel %d\n", + __func__, tsoff, + chan->number); + + /* + * offset corrected. re-check remaining + * len for a full TS frame, break and + * skip to fragment handling if < 188. + */ + if (len < 188) + break; + } + } + tsin_copy_stripped(dev, buf); buf += 188; len -= 188; } + + /* + * if a fragment is left, copy to temp buffer. The remainder + * will be appended in the next tsin_exchange() iteration. + */ + if (len > 0 && len < 188) + memcpy(&chan->tsin_buffer, buf, len); + return NULL; } diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 66d8eaa28549..01d9f1b58fcb 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -732,6 +732,9 @@ struct ngene_channel { #endif int running; + + int tsin_offset; + u8 tsin_buffer[188]; }; -- cgit From f6618cc8b447834a8102ae6988ae45cc7835a519 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:14:55 -0500 Subject: media: lgdt3306a: remove symbol count mismatch fix This symbol mismatch is handled by NULL'ing out the release callback if the driver is loaded as an i2c device. This patch reverts: - commit 94448e21cf08 ("media: lgdt3306a: Fix a double kfree on i2c device remove") - commit 835d66173a38 ("media: lgdt3306a: Fix module count mismatch on usb unplug") The symbol count mismatch is handled by: - commit 5b3a8e906973 ("media: lgdt3306a: Set fe ops.release to NULL if probed") Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 5b1903358730..7eb4e1469d20 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1814,13 +1814,7 @@ static void lgdt3306a_release(struct dvb_frontend *fe) struct lgdt3306a_state *state = fe->demodulator_priv; dbg_info("\n"); - - /* - * If state->muxc is not NULL, then we are an i2c device - * and lgdt3306a_remove will clean up state - */ - if (!state->muxc) - kfree(state); + kfree(state); } static const struct dvb_frontend_ops lgdt3306a_ops; @@ -2221,7 +2215,7 @@ static int lgdt3306a_probe(struct i2c_client *client, sizeof(struct lgdt3306a_config)); config->i2c_addr = client->addr; - fe = dvb_attach(lgdt3306a_attach, config, client->adapter); + fe = lgdt3306a_attach(config, client->adapter); if (fe == NULL) { ret = -ENODEV; goto err_fe; -- cgit From 6b234c98f7ccc5e7d46626980b582c666cfc6bf6 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:14:56 -0500 Subject: media: em28xx: Change hex to lower case Coding style fix. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index bb1b650e7680..36d341fb65dd 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -643,7 +643,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? EM2874_R5D_TS1_PKT_SIZE : EM2874_R5E_TS2_PKT_SIZE, - 0xFF); + 0xff); } else { /* ISOC Maximum Transfer Size = 188 * 5 */ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ? -- cgit From b94e47055bad45a005cc62b07a5fc79bf36e3e96 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:14:57 -0500 Subject: media: cx231xx: Use frontend i2c adapter with tuner Utilize the i2c mux adapter returned by the frontend. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 7c3863ad6f23..680c175be28d 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1221,7 +1221,7 @@ static int dvb_init(struct cx231xx *dev) info.platform_data = &si2157_config; request_module("si2157"); - client = i2c_new_device(tuner_i2c, &info); + client = i2c_new_device(adapter, &info); if (client == NULL || client->dev.driver == NULL) { module_put(dvb->i2c_client_demod[0]->dev.driver->owner); i2c_unregister_device(dvb->i2c_client_demod[0]); -- cgit From 93e5b2066a2741b3b96b5685e6207287909192fa Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:14:58 -0500 Subject: media: cx23885: Add tuner type and analog inputs to 1265 Add missing composite and s-video inputs. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 831b066cdfe1..5a640980f967 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -788,8 +788,24 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = { .name = "Hauppauge WinTV-HVR-1265(161111)", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, }, [CX23885_BOARD_HAUPPAUGE_STARBURST2] = { .name = "Hauppauge WinTV-Starburst2", -- cgit From f83423094deaa12d0f9a6a82e05ea8ec66b78ef5 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:14:59 -0500 Subject: media: cx231xx: Set mfe_shared if second frontend found If frontend[1] exists, then enable the dvb adapter mfe lock system. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 680c175be28d..3a5ed2a8209b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -504,6 +504,9 @@ static int register_dvb(struct cx231xx_dvb *dvb, dev->name, result); goto fail_frontend1; } + + /* MFE lock */ + dvb->adapter.mfe_shared = 1; } /* register demux stuff */ -- cgit From 1dd2ce0e866c5ced6ba66360e24ed3b141112e26 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:00 -0500 Subject: media: cx231xx: Use constant instead of hard code for max Nit regarding hard coded value. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 3a5ed2a8209b..d945ae51851b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -53,9 +53,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX231XX_DVB_NUM_BUFS 5 #define CX231XX_DVB_MAX_PACKETSIZE 564 #define CX231XX_DVB_MAX_PACKETS 64 +#define CX231XX_DVB_MAX_FRONTENDS 2 struct cx231xx_dvb { - struct dvb_frontend *frontend[2]; + struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS]; /* feed count management */ struct mutex lock; -- cgit From a2c52cd73f78711590cab76f546d75eb712702ca Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:01 -0500 Subject: media: cx231xx: Add second i2c demod to Hauppauge 975 Hauppauge HVR-975 is a hybrid, dual frontend, single tuner USB device. It contains lgdt3306a and si2168 frontends and one si2157 tuner. The lgdt3306a frontend is currently enabled. This creates the second demodulator and attaches it to the tuner. Enables lgdt3306a|si2168 + si2157 Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 1 + drivers/media/usb/cx231xx/cx231xx-dvb.c | 52 +++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index c5edbd5bdb7e..c76b2101193c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -979,6 +979,7 @@ struct cx231xx_board cx231xx_boards[] = { .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, .demod_addr = 0x59, /* 0xb2 >> 1 */ + .demod_addr2 = 0x64, /* 0xc8 >> 1 */ .norm = V4L2_STD_ALL, .input = {{ diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index d945ae51851b..713029420fcf 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1177,14 +1177,17 @@ static int dvb_init(struct cx231xx *dev) { struct i2c_client *client; struct i2c_adapter *adapter; + struct i2c_adapter *adapter2; struct i2c_board_info info = {}; struct si2157_config si2157_config = {}; struct lgdt3306a_config lgdt3306a_config = {}; + struct si2168_config si2168_config = {}; - /* attach demodulator chip */ + /* attach first demodulator chip */ lgdt3306a_config = hauppauge_955q_lgdt3306a_config; lgdt3306a_config.fe = &dev->dvb->frontend[0]; lgdt3306a_config.i2c_adapter = &adapter; + lgdt3306a_config.deny_i2c_rptr = 0; strlcpy(info.type, "lgdt3306a", sizeof(info.type)); info.addr = dev->board.demod_addr; @@ -1206,10 +1209,43 @@ static int dvb_init(struct cx231xx *dev) } dvb->i2c_client_demod[0] = client; - dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; + + /* attach second demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend[1]; + si2168_config.i2c_adapter = &adapter2; + si2168_config.ts_clock_inv = true; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", sizeof(info.type)); + info.addr = dev->board.demod_addr2; + info.platform_data = &si2168_config; + + request_module(info.type); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + dev_err(dev->dev, + "Failed to attach %s frontend.\n", info.type); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod[0]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[0]); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod[1] = client; + dvb->frontend[1]->id = 1; /* define general-purpose callback pointer */ dvb->frontend[0]->callback = cx231xx_tuner_callback; + dvb->frontend[1]->callback = cx231xx_tuner_callback; /* attach tuner */ si2157_config.fe = dev->dvb->frontend[0]; @@ -1227,6 +1263,8 @@ static int dvb_init(struct cx231xx *dev) client = i2c_new_device(adapter, &info); if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod[1]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[1]); module_put(dvb->i2c_client_demod[0]->dev.driver->owner); i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; @@ -1237,6 +1275,8 @@ static int dvb_init(struct cx231xx *dev) dev_err(dev->dev, "Failed to obtain %s tuner.\n", info.type); i2c_unregister_device(client); + module_put(dvb->i2c_client_demod[1]->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod[1]); module_put(dvb->i2c_client_demod[0]->dev.driver->owner); i2c_unregister_device(dvb->i2c_client_demod[0]); result = -ENODEV; @@ -1244,7 +1284,13 @@ static int dvb_init(struct cx231xx *dev) } dev->cx231xx_reset_analog_tuner = NULL; - dev->dvb->i2c_client_tuner = client; + dvb->i2c_client_tuner = client; + + dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv; + + memcpy(&dvb->frontend[1]->ops.tuner_ops, + &dvb->frontend[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); break; } default: -- cgit From 9cbf518efaa8eae88f5a216c2ea58987a5344989 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:02 -0500 Subject: media: cx23885: Fix gpio on Hauppauge QuadHD PCIe cards The GPIO settings for quadHD boards are wrong. Fix them. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 5a640980f967..41f5669b2b43 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1828,8 +1828,6 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx23885_gpio_set(dev, GPIO_2); break; case CX23885_BOARD_HAUPPAUGE_HVR5525: - case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: - case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: case CX23885_BOARD_HAUPPAUGE_STARBURST2: /* * HVR5525 GPIO Details: @@ -1861,7 +1859,9 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) */ break; case CX23885_BOARD_HAUPPAUGE_HVR1265_K4: + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885: + case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885: /* * GPIO-08 TER1_RESN -- cgit From 3ee9bc12342cf546313d300808ff47d7dbb8e7db Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:34 -0500 Subject: media: cx25840: Use subdev host data for PLL override The cx25840 driver currently configures 885, 887, and 888 using default divisors for each chip. This check to see if the cx23885 driver has passed the cx25840 a non-default clock rate for a specific chip. If a cx23885 board has left clk_freq at 0, the clock default values will be used to configure the PLLs. This patch only has effect on 888 boards who set clk_freq to 25M. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 98be63ae8590..b168bf3635b6 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -463,8 +463,13 @@ static void cx23885_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u32 clk_freq = 0; struct workqueue_struct *q; + /* cx23885 sets hostdata to clk_freq pointer */ + if (v4l2_get_subdev_hostdata(&state->sd)) + clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd)); + /* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from @@ -500,8 +505,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - /* HVR1850 or 50MHz xtal */ - cx25840_write(client, 0x2, 0x71); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25Mhz xtal */ + ; /* nothing to do */ + } else { + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + } cx25840_write4(client, 0x11c, 0x01d1744c); cx25840_write4(client, 0x118, 0x00000416); cx25840_write4(client, 0x404, 0x0010253e); @@ -544,9 +554,15 @@ static void cx23885_initialize(struct i2c_client *client) /* HVR1850 */ switch (state->id) { case CX23888_AV: - /* 888/HVR1250 specific */ - cx25840_write4(client, 0x10c, 0x13333333); - cx25840_write4(client, 0x108, 0x00000515); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25MHz xtal */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + cx25840_write4(client, 0x108, 0x00000512); + } else { + /* 888/HVR1250 or 50MHz xtal */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + } break; default: cx25840_write4(client, 0x10c, 0x002be2c9); @@ -576,7 +592,7 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - /* HVR1850 or 50MHz xtal */ + /* HVR1850 or 50MHz xtal or 25MHz xtal */ cx25840_write4(client, 0x114, 0x017dbf48); cx25840_write4(client, 0x110, 0x000a030e); break; -- cgit From 5da1a68227feffd65bb7f20733afbe5134da6386 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:35 -0500 Subject: media: cx23885: change 887/888 default to 888 Proper cx2388x chip type is detected in cx25840 probe, the clock rate is untouched however in probe. The cx25840 only checks for non default clock values for 888 and provides custom settings for 25MHz 888. This change ensures that cx23888 chips with default 50MHz crystals will not get configured as if they have 25MHz crystals. A cx23887 board will continue to be configured for 25MHz crystal as there is no custom clock support included for it. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8afddd6795aa..2c76a0235a58 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -839,10 +839,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* Configure the internal memory */ if (dev->pci->device == 0x8880) { - /* Could be 887 or 888, assume a default */ - dev->bridge = CX23885_BRIDGE_887; + /* Could be 887 or 888, assume an 888 default */ + dev->bridge = CX23885_BRIDGE_888; /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 25000000; + dev->clk_freq = 50000000; dev->sram_channels = cx23887_sram_channels; } else if (dev->pci->device == 0x8852) { -- cgit From 5ceade1d97fc6687e050c44c257382c192f56276 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:36 -0500 Subject: media: cx23885: Set subdev host data to clk_freq pointer Currently clk_freq is ignored entirely, because the cx235840 driver configures the xtal at the chip defaults. This is an issue if a board is produced with a non-default frequency crystal. If clk_freq is not zero the cx25840 will attempt to use the setting provided, or fall back to defaults otherwise. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 41f5669b2b43..3a1c55187b2a 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -2362,6 +2362,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { + /* set host data for clk_freq configuration */ + v4l2_set_subdev_hostdata(dev->sd_cx25840, + &dev->clk_freq); + dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); } -- cgit From 779c79d4b833ec646b0aed878da38edb45bbe156 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:37 -0500 Subject: media: cx23885: Override 888 ImpactVCBe crystal frequency Hauppauge produced a revision of ImpactVCBe using an 888, with a 25MHz crystal, instead of using the default third overtone 50Mhz crystal. This overrides that frequency so that the cx25840 is properly configured. Without the proper crystal setup the cx25840 cannot load the firmware or decode video. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 2c76a0235a58..ff369e90b848 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -881,6 +881,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].clk_freq > 0) dev->clk_freq = cx23885_boards[dev->board].clk_freq; + if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE && + dev->pci->subsystem_device == 0x7137) { + /* Hauppauge ImpactVCBe device ID 0x7137 is populated + * with an 888, and a 25Mhz crystal, instead of the + * usual third overtone 50Mhz. The default clock rate must + * be overridden so the cx25840 is properly configured + */ + dev->clk_freq = 25000000; + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); -- cgit From 1980bfa67f19d628df30b9b5b76bca37c2a76dde Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 04:11:50 -0500 Subject: media: dvbdev: fix building on ia64 Not sure why, but, on ia64, with Linaro's gcc 7.3 compiler, using #ifdef (CONFIG_I2C) is not OK. So, replace it by IS_ENABLED(CONFIG_I2C), in order to fix the builds there. Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index a840133feacb..cf747d753a79 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -942,7 +942,7 @@ out: return err; } -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) struct i2c_client *dvb_module_probe(const char *module_name, const char *name, struct i2c_adapter *adap, -- cgit From bd24fcddf6b822a6646b00cfc76a21f3f7bbc7e7 Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:46:10 -0500 Subject: media: cxd2880-spi: Add support for CXD2880 SPI interface This is the SPI adapter part of the driver for the Sony CXD2880 DVB-T2/T tuner + demodulator. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/cxd2880-spi.c | 670 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 670 insertions(+) create mode 100644 drivers/media/spi/cxd2880-spi.c (limited to 'drivers/media') diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c new file mode 100644 index 000000000000..857e4c0d7a92 --- /dev/null +++ b/drivers/media/spi/cxd2880-spi.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880-spi.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI adapter + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include +#include + +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_frontend.h" +#include "cxd2880.h" + +#define CXD2880_MAX_FILTER_SIZE 32 +#define BURST_WRITE_MAX 128 +#define MAX_TRANS_PKT 300 + +struct cxd2880_ts_buf_info { + u8 read_ready:1; + u8 almost_full:1; + u8 almost_empty:1; + u8 overflow:1; + u8 underflow:1; + u16 pkt_num; +}; + +struct cxd2880_pid_config { + u8 is_enable; + u16 pid; +}; + +struct cxd2880_pid_filter_config { + u8 is_negative; + struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE]; +}; + +struct cxd2880_dvb_spi { + struct dvb_frontend dvb_fe; + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend dmx_fe; + struct task_struct *cxd2880_ts_read_thread; + struct spi_device *spi; + struct mutex spi_mutex; /* For SPI access exclusive control */ + int feed_count; + int all_pid_feed_count; + u8 *ts_buf; + struct cxd2880_pid_filter_config filter_config; +}; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size) +{ + struct spi_message msg; + struct spi_transfer tx; + + if (!spi || !data) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + memset(&tx, 0, sizeof(tx)); + tx.tx_buf = data; + tx.len = size; + + spi_message_init(&msg); + spi_message_add_tail(&tx, &msg); + + return spi_sync(spi, &msg); +} + +static int cxd2880_write_reg(struct spi_device *spi, + u8 sub_address, const u8 *data, u32 size) +{ + u8 send_data[BURST_WRITE_MAX + 4]; + const u8 *write_data_top = NULL; + int ret = 0; + + if (!spi || !data) { + pr_err("invalid arg\n"); + return -EINVAL; + } + if (size > BURST_WRITE_MAX) { + pr_err("data size > WRITE_MAX\n"); + return -EINVAL; + } + + if (sub_address + size > 0x100) { + pr_err("out of range\n"); + return -EINVAL; + } + + send_data[0] = 0x0e; + write_data_top = data; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = (u8)size; + + memcpy(&send_data[3], write_data_top, send_data[2]); + + ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3); + if (ret) { + pr_err("write spi failed %d\n", ret); + break; + } + sub_address += send_data[2]; + write_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +static int cxd2880_spi_read_ts(struct spi_device *spi, + u8 *read_data, + u32 packet_num) +{ + int ret; + u8 data[3]; + struct spi_message message; + struct spi_transfer transfer[2]; + + if (!spi || !read_data || !packet_num) { + pr_err("invalid arg\n"); + return -EINVAL; + } + if (packet_num > 0xffff) { + pr_err("packet num > 0xffff\n"); + return -EINVAL; + } + + data[0] = 0x10; + data[1] = packet_num >> 8; + data[2] = packet_num; + + spi_message_init(&message); + memset(transfer, 0, sizeof(transfer)); + + transfer[0].len = 3; + transfer[0].tx_buf = data; + spi_message_add_tail(&transfer[0], &message); + transfer[1].len = packet_num * 188; + transfer[1].rx_buf = read_data; + spi_message_add_tail(&transfer[1], &message); + + ret = spi_sync(spi, &message); + if (ret) + pr_err("spi_write_then_read failed\n"); + + return ret; +} + +static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi, + struct cxd2880_ts_buf_info *info) +{ + u8 send_data = 0x20; + u8 recv_data[2]; + int ret; + + if (!spi || !info) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + ret = spi_write_then_read(spi, &send_data, 1, + recv_data, sizeof(recv_data)); + if (ret) + pr_err("spi_write_then_read failed\n"); + + info->read_ready = (recv_data[0] & 0x80) ? 1 : 0; + info->almost_full = (recv_data[0] & 0x40) ? 1 : 0; + info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0; + info->overflow = (recv_data[0] & 0x10) ? 1 : 0; + info->underflow = (recv_data[0] & 0x08) ? 1 : 0; + info->pkt_num = ((recv_data[0] & 0x07) << 8) | recv_data[1]; + + return ret; +} + +static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi) +{ + u8 data = 0x03; + int ret; + + ret = cxd2880_write_spi(spi, &data, 1); + + if (ret) + pr_err("write spi failed\n"); + + return ret; +} + +static int cxd2880_set_pid_filter(struct spi_device *spi, + struct cxd2880_pid_filter_config *cfg) +{ + u8 data[65]; + int i; + u16 pid = 0; + int ret; + + if (!spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + data[0] = 0x00; + ret = cxd2880_write_reg(spi, 0x00, &data[0], 1); + if (ret) + return ret; + if (!cfg) { + data[0] = 0x02; + ret = cxd2880_write_reg(spi, 0x50, &data[0], 1); + } else { + data[0] = cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + pid = cfg->pid_config[i].pid; + if (cfg->pid_config[i].is_enable) { + data[1 + (i * 2)] = (pid >> 8) | 0x20; + data[2 + (i * 2)] = pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; + } + } + ret = cxd2880_write_reg(spi, 0x50, data, 65); + } + + return ret; +} + +static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi, + struct cxd2880_pid_filter_config *cfg, + bool is_all_pid_filter) +{ + int ret; + + if (!dvb_spi || !cfg) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + mutex_lock(&dvb_spi->spi_mutex); + if (is_all_pid_filter) { + struct cxd2880_pid_filter_config tmpcfg; + + memset(&tmpcfg, 0, sizeof(tmpcfg)); + tmpcfg.is_negative = 1; + tmpcfg.pid_config[0].is_enable = 1; + tmpcfg.pid_config[0].pid = 0x1fff; + + ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg); + } else { + ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg); + } + mutex_unlock(&dvb_spi->spi_mutex); + + if (ret) + pr_err("set_pid_filter failed\n"); + + return ret; +} + +static int cxd2880_ts_read(void *arg) +{ + struct cxd2880_dvb_spi *dvb_spi = NULL; + struct cxd2880_ts_buf_info info; + ktime_t start; + u32 i; + int ret; + + dvb_spi = arg; + if (!dvb_spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi); + if (ret) { + pr_err("set_clear_ts_buffer failed\n"); + return ret; + } + + start = ktime_get(); + while (!kthread_should_stop()) { + ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi, + &info); + if (ret) { + pr_err("spi_read_ts_buffer_info error\n"); + return ret; + } + + if (info.pkt_num > MAX_TRANS_PKT) { + for (i = 0; i < info.pkt_num / MAX_TRANS_PKT; i++) { + cxd2880_spi_read_ts(dvb_spi->spi, + dvb_spi->ts_buf, + MAX_TRANS_PKT); + dvb_dmx_swfilter(&dvb_spi->demux, + dvb_spi->ts_buf, + MAX_TRANS_PKT * 188); + } + start = ktime_get(); + } else if ((info.pkt_num > 0) && + (ktime_to_ms(ktime_sub(ktime_get(), start)) >= 500)) { + cxd2880_spi_read_ts(dvb_spi->spi, + dvb_spi->ts_buf, + info.pkt_num); + dvb_dmx_swfilter(&dvb_spi->demux, + dvb_spi->ts_buf, + info.pkt_num * 188); + start = ktime_get(); + } else { + usleep_range(10000, 11000); + } + } + + return 0; +} + +static int cxd2880_start_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + int i = 0; + struct dvb_demux *demux = NULL; + struct cxd2880_dvb_spi *dvb_spi = NULL; + + if (!feed) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + demux = feed->demux; + if (!demux) { + pr_err("feed->demux is NULL\n"); + return -EINVAL; + } + dvb_spi = demux->priv; + + if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) { + pr_err("Exceeded maximum PID count (32)."); + pr_err("Selected PID cannot be enabled.\n"); + return -EINVAL; + } + + if (feed->pid == 0x2000) { + if (dvb_spi->all_pid_feed_count == 0) { + ret = cxd2880_update_pid_filter(dvb_spi, + &dvb_spi->filter_config, + true); + if (ret) { + pr_err("update pid filter failed\n"); + return ret; + } + } + dvb_spi->all_pid_feed_count++; + + pr_debug("all PID feed (count = %d)\n", + dvb_spi->all_pid_feed_count); + } else { + struct cxd2880_pid_filter_config cfgtmp; + + cfgtmp = dvb_spi->filter_config; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + if (cfgtmp.pid_config[i].is_enable == 0) { + cfgtmp.pid_config[i].is_enable = 1; + cfgtmp.pid_config[i].pid = feed->pid; + pr_debug("store PID %d to #%d\n", + feed->pid, i); + break; + } + } + if (i == CXD2880_MAX_FILTER_SIZE) { + pr_err("PID filter is full. Assumed bug.\n"); + return -EINVAL; + } + if (!dvb_spi->all_pid_feed_count) + ret = cxd2880_update_pid_filter(dvb_spi, + &cfgtmp, + false); + if (ret) + return ret; + + dvb_spi->filter_config = cfgtmp; + } + + if (dvb_spi->feed_count == 0) { + dvb_spi->ts_buf = + kmalloc(MAX_TRANS_PKT * 188, + GFP_KERNEL | GFP_DMA); + if (!dvb_spi->ts_buf) { + pr_err("ts buffer allocate failed\n"); + memset(&dvb_spi->filter_config, 0, + sizeof(dvb_spi->filter_config)); + dvb_spi->all_pid_feed_count = 0; + return -ENOMEM; + } + dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read, + dvb_spi, + "cxd2880_ts_read"); + if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) { + pr_err("kthread_run failed/\n"); + kfree(dvb_spi->ts_buf); + dvb_spi->ts_buf = NULL; + memset(&dvb_spi->filter_config, 0, + sizeof(dvb_spi->filter_config)); + dvb_spi->all_pid_feed_count = 0; + return PTR_ERR(dvb_spi->cxd2880_ts_read_thread); + } + } + + dvb_spi->feed_count++; + + pr_debug("start feed (count %d)\n", dvb_spi->feed_count); + return 0; +} + +static int cxd2880_stop_feed(struct dvb_demux_feed *feed) +{ + int i = 0; + int ret; + struct dvb_demux *demux = NULL; + struct cxd2880_dvb_spi *dvb_spi = NULL; + + if (!feed) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + demux = feed->demux; + if (!demux) { + pr_err("feed->demux is NULL\n"); + return -EINVAL; + } + dvb_spi = demux->priv; + + if (!dvb_spi->feed_count) { + pr_err("no feed is started\n"); + return -EINVAL; + } + + if (feed->pid == 0x2000) { + /* + * Special PID case. + * Number of 0x2000 feed request was stored + * in dvb_spi->all_pid_feed_count. + */ + if (dvb_spi->all_pid_feed_count <= 0) { + pr_err("PID %d not found.\n", feed->pid); + return -EINVAL; + } + dvb_spi->all_pid_feed_count--; + } else { + struct cxd2880_pid_filter_config cfgtmp; + + cfgtmp = dvb_spi->filter_config; + + for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) { + if (feed->pid == cfgtmp.pid_config[i].pid && + cfgtmp.pid_config[i].is_enable != 0) { + cfgtmp.pid_config[i].is_enable = 0; + cfgtmp.pid_config[i].pid = 0; + pr_debug("removed PID %d from #%d\n", + feed->pid, i); + break; + } + } + dvb_spi->filter_config = cfgtmp; + + if (i == CXD2880_MAX_FILTER_SIZE) { + pr_err("PID %d not found\n", feed->pid); + return -EINVAL; + } + } + + ret = cxd2880_update_pid_filter(dvb_spi, + &dvb_spi->filter_config, + dvb_spi->all_pid_feed_count > 0); + dvb_spi->feed_count--; + + if (dvb_spi->feed_count == 0) { + int ret_stop = 0; + + ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread); + if (ret_stop) { + pr_err("'kthread_stop failed. (%d)\n", ret_stop); + ret = ret_stop; + } + kfree(dvb_spi->ts_buf); + dvb_spi->ts_buf = NULL; + } + + pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count); + + return ret; +} + +static const struct of_device_id cxd2880_spi_of_match[] = { + { .compatible = "sony,cxd2880" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match); + +static int +cxd2880_spi_probe(struct spi_device *spi) +{ + int ret; + struct cxd2880_dvb_spi *dvb_spi = NULL; + struct cxd2880_config config; + + if (!spi) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL); + if (!dvb_spi) + return -ENOMEM; + + dvb_spi->spi = spi; + mutex_init(&dvb_spi->spi_mutex); + dev_set_drvdata(&spi->dev, dvb_spi); + config.spi = spi; + config.spi_mutex = &dvb_spi->spi_mutex; + + ret = dvb_register_adapter(&dvb_spi->adapter, + "CXD2880", + THIS_MODULE, + &spi->dev, + adapter_nr); + if (ret < 0) { + pr_err("dvb_register_adapter() failed\n"); + goto fail_adapter; + } + + if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) { + pr_err("cxd2880_attach failed\n"); + goto fail_attach; + } + + ret = dvb_register_frontend(&dvb_spi->adapter, + &dvb_spi->dvb_fe); + if (ret < 0) { + pr_err("dvb_register_frontend() failed\n"); + goto fail_frontend; + } + + dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING; + dvb_spi->demux.priv = dvb_spi; + dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->demux.start_feed = cxd2880_start_feed; + dvb_spi->demux.stop_feed = cxd2880_stop_feed; + + ret = dvb_dmx_init(&dvb_spi->demux); + if (ret < 0) { + pr_err("dvb_dmx_init() failed\n"); + goto fail_dmx; + } + + dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE; + dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx; + dvb_spi->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&dvb_spi->dmxdev, + &dvb_spi->adapter); + if (ret < 0) { + pr_err("dvb_dmxdev_init() failed\n"); + goto fail_dmxdev; + } + + dvb_spi->dmx_fe.source = DMX_FRONTEND_0; + ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + if (ret < 0) { + pr_err("add_frontend() failed\n"); + goto fail_dmx_fe; + } + + ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + if (ret < 0) { + pr_err("dvb_register_frontend() failed\n"); + goto fail_fe_conn; + } + + pr_info("Sony CXD2880 has successfully attached.\n"); + + return 0; + +fail_fe_conn: + dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); +fail_dmx_fe: + dvb_dmxdev_release(&dvb_spi->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb_spi->demux); +fail_dmx: + dvb_unregister_frontend(&dvb_spi->dvb_fe); +fail_frontend: + dvb_frontend_detach(&dvb_spi->dvb_fe); +fail_attach: + dvb_unregister_adapter(&dvb_spi->adapter); +fail_adapter: + kfree(dvb_spi); + return ret; +} + +static int +cxd2880_spi_remove(struct spi_device *spi) +{ + struct cxd2880_dvb_spi *dvb_spi; + + if (!spi) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + dvb_spi = dev_get_drvdata(&spi->dev); + + if (!dvb_spi) { + pr_err("failed\n"); + return -EINVAL; + } + dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, + &dvb_spi->dmx_fe); + dvb_dmxdev_release(&dvb_spi->dmxdev); + dvb_dmx_release(&dvb_spi->demux); + dvb_unregister_frontend(&dvb_spi->dvb_fe); + dvb_frontend_detach(&dvb_spi->dvb_fe); + dvb_unregister_adapter(&dvb_spi->adapter); + + kfree(dvb_spi); + pr_info("cxd2880_spi remove ok.\n"); + + return 0; +} + +static const struct spi_device_id cxd2880_spi_id[] = { + { "cxd2880", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, cxd2880_spi_id); + +static struct spi_driver cxd2880_spi_driver = { + .driver = { + .name = "cxd2880", + .of_match_table = cxd2880_spi_of_match, + }, + .id_table = cxd2880_spi_id, + .probe = cxd2880_spi_probe, + .remove = cxd2880_spi_remove, +}; +module_spi_driver(cxd2880_spi_driver); + +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter"); +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); +MODULE_LICENSE("GPL v2"); -- cgit From 1a3ef038d09e66489f95c5cd67d815670f9cabdc Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:47:38 -0500 Subject: media: cxd2880: Add common files for the driver These are common files for the driver for the Sony CXD2880 DVB-T2/T tuner + demodulator. These contains helper functions for the driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880.h | 29 ++++++++++ .../media/dvb-frontends/cxd2880/cxd2880_common.c | 21 +++++++ .../media/dvb-frontends/cxd2880/cxd2880_common.h | 19 +++++++ drivers/media/dvb-frontends/cxd2880/cxd2880_io.c | 66 ++++++++++++++++++++++ drivers/media/dvb-frontends/cxd2880/cxd2880_io.h | 54 ++++++++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h new file mode 100644 index 000000000000..4ea3510aab66 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_H +#define CXD2880_H + +struct cxd2880_config { + struct spi_device *spi; + struct mutex *spi_mutex; /* For SPI access exclusive control */ +}; + +#if IS_REACHABLE(CONFIG_DVB_CXD2880) +extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg); +#else +static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_CXD2880 */ + +#endif /* CXD2880_H */ diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c new file mode 100644 index 000000000000..d6f5af6609c1 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_common.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_common.h" + +int cxd2880_convert2s_complement(u32 value, u32 bitlen) +{ + if (!bitlen || bitlen >= 32) + return (int)value; + + if (value & (u32)(1 << (bitlen - 1))) + return (int)(GENMASK(31, bitlen) | value); + else + return (int)(GENMASK(bitlen - 1, 0) & value); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h new file mode 100644 index 000000000000..b05bce71ab35 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_common.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_COMMON_H +#define CXD2880_COMMON_H + +#include +#include +#include +#include + +int cxd2880_convert2s_complement(u32 value, u32 bitlen); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c new file mode 100644 index 000000000000..9d932bccfa6c --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_io.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * register I/O interface functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_io.h" + +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data) +{ + if (!io) + return -EINVAL; + + return io->write_regs(io, tgt, sub_address, &data, 1); +} + +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask) +{ + int ret; + + if (!io) + return -EINVAL; + + if (mask == 0x00) + return 0; + + if (mask != 0xff) { + u8 rdata = 0x00; + + ret = io->read_regs(io, tgt, sub_address, &rdata, 1); + if (ret) + return ret; + + data = (data & mask) | (rdata & (mask ^ 0xff)); + } + + return io->write_reg(io, tgt, sub_address, data); +} + +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size) +{ + int ret; + int i; + + if (!io) + return -EINVAL; + + for (i = 0; i < size ; i++) { + ret = io->write_reg(io, tgt, reg_value[i].addr, + reg_value[i].value); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h new file mode 100644 index 000000000000..ba550278881d --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_io.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * register I/O interface definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_IO_H +#define CXD2880_IO_H + +#include "cxd2880_common.h" + +enum cxd2880_io_tgt { + CXD2880_IO_TGT_SYS, + CXD2880_IO_TGT_DMD +}; + +struct cxd2880_reg_value { + u8 addr; + u8 value; +}; + +struct cxd2880_io { + int (*read_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 *data, u32 size); + int (*write_regs)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + const u8 *data, u32 size); + int (*write_reg)(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, u8 sub_address, + u8 data); + void *if_object; + u8 i2c_address_sys; + u8 i2c_address_demod; + u8 slave_select; + void *user; +}; + +int cxd2880_io_common_write_one_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data); + +int cxd2880_io_set_reg_bits(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 data, u8 mask); + +int cxd2880_io_write_multi_regs(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + const struct cxd2880_reg_value reg_value[], + u8 size); +#endif -- cgit From 4e67e6cb06cd9a43cfdd080308aeefec0dc14f2f Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:48:58 -0500 Subject: media: cxd2880: Add spi device IO routines Add functions for initializing, reading and writing to the SPI device for the Sony CXD2880 DVB-T2/T tuner + demodulator. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- .../dvb-frontends/cxd2880/cxd2880_devio_spi.c | 129 +++++++++++++++++++++ .../dvb-frontends/cxd2880/cxd2880_devio_spi.h | 23 ++++ drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h | 34 ++++++ .../dvb-frontends/cxd2880/cxd2880_spi_device.c | 113 ++++++++++++++++++ .../dvb-frontends/cxd2880/cxd2880_spi_device.h | 26 +++++ 5 files changed, 325 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c new file mode 100644 index 000000000000..d2e37c95d748 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_devio_spi.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * I/O interface via SPI + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_devio_spi.h" + +#define BURST_WRITE_MAX 128 + +static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, u8 *data, + u32 size) +{ + int ret; + struct cxd2880_spi *spi = NULL; + u8 send_data[6]; + u8 *read_data_top = data; + + if (!io || !io->if_object || !data) + return -EINVAL; + + if (sub_address + size > 0x100) + return -EINVAL; + + spi = io->if_object; + + if (tgt == CXD2880_IO_TGT_SYS) + send_data[0] = 0x0b; + else + send_data[0] = 0x0a; + + send_data[3] = 0; + send_data[4] = 0; + send_data[5] = 0; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = size; + + ret = + spi->write_read(spi, send_data, sizeof(send_data), + read_data_top, send_data[2]); + if (ret) + return ret; + + sub_address += send_data[2]; + read_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, + enum cxd2880_io_tgt tgt, + u8 sub_address, + const u8 *data, u32 size) +{ + int ret; + struct cxd2880_spi *spi = NULL; + u8 send_data[BURST_WRITE_MAX + 4]; + const u8 *write_data_top = data; + + if (!io || !io->if_object || !data) + return -EINVAL; + + if (size > BURST_WRITE_MAX) + return -EINVAL; + + if (sub_address + size > 0x100) + return -EINVAL; + + spi = io->if_object; + + if (tgt == CXD2880_IO_TGT_SYS) + send_data[0] = 0x0f; + else + send_data[0] = 0x0e; + + while (size > 0) { + send_data[1] = sub_address; + if (size > 255) + send_data[2] = 255; + else + send_data[2] = size; + + memcpy(&send_data[3], write_data_top, send_data[2]); + + if (tgt == CXD2880_IO_TGT_SYS) { + send_data[3 + send_data[2]] = 0x00; + ret = spi->write(spi, send_data, send_data[2] + 4); + } else { + ret = spi->write(spi, send_data, send_data[2] + 3); + } + if (ret) + return ret; + + sub_address += send_data[2]; + write_data_top += send_data[2]; + size -= send_data[2]; + } + + return ret; +} + +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, u8 slave_select) +{ + if (!io || !spi) + return -EINVAL; + + io->read_regs = cxd2880_io_spi_read_reg; + io->write_regs = cxd2880_io_spi_write_reg; + io->write_reg = cxd2880_io_common_write_one_reg; + io->if_object = spi; + io->i2c_address_sys = 0; + io->i2c_address_demod = 0; + io->slave_select = slave_select; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h new file mode 100644 index 000000000000..27f7cb12fad4 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_devio_spi.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * I/O interface via SPI + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DEVIO_SPI_H +#define CXD2880_DEVIO_SPI_H + +#include "cxd2880_common.h" +#include "cxd2880_io.h" +#include "cxd2880_spi.h" + +#include "cxd2880_tnrdmd.h" + +int cxd2880_io_spi_create(struct cxd2880_io *io, + struct cxd2880_spi *spi, + u8 slave_select); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h new file mode 100644 index 000000000000..2be207461847 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_spi.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_SPI_H +#define CXD2880_SPI_H + +#include "cxd2880_common.h" + +enum cxd2880_spi_mode { + CXD2880_SPI_MODE_0, + CXD2880_SPI_MODE_1, + CXD2880_SPI_MODE_2, + CXD2880_SPI_MODE_3 +}; + +struct cxd2880_spi { + int (*read)(struct cxd2880_spi *spi, u8 *data, + u32 size); + int (*write)(struct cxd2880_spi *spi, const u8 *data, + u32 size); + int (*write_read)(struct cxd2880_spi *spi, + const u8 *tx_data, u32 tx_size, + u8 *rx_data, u32 rx_size); + u32 flags; + void *user; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c new file mode 100644 index 000000000000..b8cbaa8d7aff --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_spi_device.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include + +#include "cxd2880_spi_device.h" + +static int cxd2880_spi_device_write(struct cxd2880_spi *spi, + const u8 *data, u32 size) +{ + struct cxd2880_spi_device *spi_device = NULL; + struct spi_message msg; + struct spi_transfer tx; + int result = 0; + + if (!spi || !spi->user || !data || size == 0) + return -EINVAL; + + spi_device = spi->user; + + memset(&tx, 0, sizeof(tx)); + tx.tx_buf = data; + tx.len = size; + + spi_message_init(&msg); + spi_message_add_tail(&tx, &msg); + result = spi_sync(spi_device->spi, &msg); + + if (result < 0) + return -EIO; + + return 0; +} + +static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi, + const u8 *tx_data, + u32 tx_size, + u8 *rx_data, + u32 rx_size) +{ + struct cxd2880_spi_device *spi_device = NULL; + int result = 0; + + if (!spi || !spi->user || !tx_data || + !tx_size || !rx_data || !rx_size) + return -EINVAL; + + spi_device = spi->user; + + result = spi_write_then_read(spi_device->spi, tx_data, + tx_size, rx_data, rx_size); + if (result < 0) + return -EIO; + + return 0; +} + +int +cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, + enum cxd2880_spi_mode mode, + u32 speed_hz) +{ + int result = 0; + struct spi_device *spi = spi_device->spi; + + switch (mode) { + case CXD2880_SPI_MODE_0: + spi->mode = SPI_MODE_0; + break; + case CXD2880_SPI_MODE_1: + spi->mode = SPI_MODE_1; + break; + case CXD2880_SPI_MODE_2: + spi->mode = SPI_MODE_2; + break; + case CXD2880_SPI_MODE_3: + spi->mode = SPI_MODE_3; + break; + default: + return -EINVAL; + } + + spi->max_speed_hz = speed_hz; + spi->bits_per_word = 8; + result = spi_setup(spi); + if (result != 0) { + pr_err("spi_setup failed %d\n", result); + return -EINVAL; + } + + return 0; +} + +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device) +{ + if (!spi || !spi_device) + return -EINVAL; + + spi->read = NULL; + spi->write = cxd2880_spi_device_write; + spi->write_read = cxd2880_spi_device_write_read; + spi->flags = 0; + spi->user = spi_device; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h new file mode 100644 index 000000000000..05e3a03de3a3 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_spi_device.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * SPI access interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_SPI_DEVICE_H +#define CXD2880_SPI_DEVICE_H + +#include "cxd2880_spi.h" + +struct cxd2880_spi_device { + struct spi_device *spi; +}; + +int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, + enum cxd2880_spi_mode mode, + u32 speedHz); + +int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, + struct cxd2880_spi_device *spi_device); + +#endif /* CXD2880_SPI_DEVICE_H */ -- cgit From e5835488c26bec43eb3dea96279b92c573c6f968 Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:50:20 -0500 Subject: media: cxd2880: Add tuner part of the driver This part of the driver has the main routines to handle the tuner and demodulator functionality. The tnrdmd_mon.* files have monitor functions for the driver. This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h | 29 + .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 3519 ++++++++++++++++++++ .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h | 365 ++ .../cxd2880/cxd2880_tnrdmd_driver_version.h | 12 + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c | 150 + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h | 29 + 6 files changed, 4104 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h new file mode 100644 index 000000000000..820f4757a520 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dtv.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DTV related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DTV_H +#define CXD2880_DTV_H + +enum cxd2880_dtv_sys { + CXD2880_DTV_SYS_UNKNOWN, + CXD2880_DTV_SYS_DVBT, + CXD2880_DTV_SYS_DVBT2, + CXD2880_DTV_SYS_ANY +}; + +enum cxd2880_dtv_bandwidth { + CXD2880_DTV_BW_UNKNOWN = 0, + CXD2880_DTV_BW_1_7_MHZ = 1, + CXD2880_DTV_BW_5_MHZ = 5, + CXD2880_DTV_BW_6_MHZ = 6, + CXD2880_DTV_BW_7_MHZ = 7, + CXD2880_DTV_BW_8_MHZ = 8 +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c new file mode 100644 index 000000000000..b9ef134aed79 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -0,0 +1,3519 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common control functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "dvb_frontend.h" +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt2.h" + +static const struct cxd2880_reg_value p_init1_seq[] = { + {0x11, 0x16}, {0x00, 0x10}, +}; + +static const struct cxd2880_reg_value rf_init1_seq1[] = { + {0x4f, 0x18}, {0x61, 0x00}, {0x71, 0x00}, {0x9d, 0x01}, + {0x7d, 0x02}, {0x8f, 0x01}, {0x8b, 0xc6}, {0x9a, 0x03}, + {0x1c, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init1_seq2[] = { + {0xb9, 0x07}, {0x33, 0x01}, {0xc1, 0x01}, {0xc4, 0x1e}, +}; + +static const struct cxd2880_reg_value rf_init1_seq3[] = { + {0x00, 0x10}, {0x51, 0x01}, {0xc5, 0x07}, {0x00, 0x11}, + {0x70, 0xe9}, {0x76, 0x0a}, {0x78, 0x32}, {0x7a, 0x46}, + {0x7c, 0x86}, {0x7e, 0xa4}, {0x00, 0x10}, {0xe1, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq4[] = { + {0x15, 0x00}, {0x00, 0x16} +}; + +static const struct cxd2880_reg_value rf_init1_seq5[] = { + {0x00, 0x00}, {0x25, 0x00} +}; + +static const struct cxd2880_reg_value rf_init1_seq6[] = { + {0x02, 0x00}, {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, + {0x8f, 0x16}, {0x67, 0x60}, {0x6a, 0x0f}, {0x6c, 0x17} +}; + +static const struct cxd2880_reg_value rf_init1_seq7[] = { + {0x00, 0xe2}, {0x41, 0xa0}, {0x4b, 0x68}, {0x00, 0x00}, + {0x21, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq8[] = { + {0x00, 0x10}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init1_seq9[] = { + {0x00, 0x10}, {0x14, 0x01}, {0x00, 0x00}, {0x26, 0x00}, +}; + +static const struct cxd2880_reg_value rf_init2_seq1[] = { + {0x00, 0x14}, {0x1b, 0x01}, +}; + +static const struct cxd2880_reg_value rf_init2_seq2[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, {0xd3, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune1_seq1[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune1_seq2[] = { + {0x62, 0x00}, {0x00, 0x15}, +}; + +static const struct cxd2880_reg_value x_tune2_seq1[] = { + {0x00, 0x1a}, {0x29, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq2[] = { + {0x62, 0x01}, {0x00, 0x11}, {0x2d, 0x00}, {0x2f, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune2_seq3[] = { + {0x00, 0x00}, {0x10, 0x00}, {0x21, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune2_seq4[] = { + {0x00, 0xe1}, {0x8a, 0x87}, +}; + +static const struct cxd2880_reg_value x_tune2_seq5[] = { + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value x_tune3_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0xa0}, + {0x00, 0x00}, {0x21, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_tune4_seq[] = { + {0x00, 0x00}, {0xfe, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep1_seq[] = { + {0x00, 0x00}, {0x57, 0x03}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq1[] = { + {0x00, 0x2d}, {0xb1, 0x01}, +}; + +static const struct cxd2880_reg_value x_sleep2_seq2[] = { + {0x00, 0x10}, {0xf4, 0x00}, {0xf3, 0x00}, {0xf2, 0x00}, + {0xf1, 0x00}, {0xf0, 0x00}, {0xef, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep3_seq[] = { + {0x00, 0x00}, {0xfd, 0x00}, +}; + +static const struct cxd2880_reg_value x_sleep4_seq[] = { + {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0x00}, + {0x00, 0x00}, {0x21, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, + {0x26, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value spll_reset_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x22, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq4[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value spll_reset_seq5[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq1[] = { + {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq2[] = { + {0x00, 0x00}, {0x10, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq3[] = { + {0x00, 0x00}, {0x27, 0x00}, {0x25, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq4[] = { + {0x00, 0x00}, {0x2a, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq5[] = { + {0x00, 0x00}, {0x25, 0x00}, +}; + +static const struct cxd2880_reg_value t_power_x_seq6[] = { + {0x00, 0x00}, {0x27, 0x01}, +}; + +static const struct cxd2880_reg_value t_power_x_seq7[] = { + {0x00, 0x00}, {0x10, 0x01}, +}; + +static const struct cxd2880_reg_value set_ts_pin_seq[] = { + {0x50, 0x3f}, {0x52, 0x1f}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq1[] = { + {0x00, 0x00}, {0x52, 0x00}, +}; + +static const struct cxd2880_reg_value set_ts_output_seq2[] = { + {0x00, 0x00}, {0xc3, 0x00}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq3[] = { + {0x00, 0x00}, {0xc3, 0x01}, + +}; + +static const struct cxd2880_reg_value set_ts_output_seq4[] = { + {0x00, 0x00}, {0x52, 0x1f}, + +}; + +static int p_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_TS: + data = 0x00; + break; + case CXD2880_TNRDMD_TSOUT_IF_SPI: + data = 0x01; + break; + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + data = 0x02; + break; + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + p_init1_seq, + ARRAY_SIZE(p_init1_seq)); + if (ret) + return ret; + + switch (tnr_dmd->chip_id) { + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: + data = 0x1a; + break; + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11: + data = 0x16; + break; + default: + return -ENOTTY; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data); + if (ret) + return ret; + + if (tnr_dmd->create_param.en_internal_ldo) + data = 0x01; + else + data = 0x00; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + switch (tnr_dmd->chip_id) { + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X: + data = 0x01; + break; + case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11: + data = 0x00; + break; + default: + return -ENOTTY; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x69, data); +} + +static int p_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[6] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = tnr_dmd->create_param.xosc_cap; + data[1] = tnr_dmd->create_param.xosc_i; + switch (tnr_dmd->create_param.xtal_share_type) { + case CXD2880_TNRDMD_XTAL_SHARE_NONE: + data[2] = 0x01; + data[3] = 0x00; + break; + case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: + data[2] = 0x00; + data[3] = 0x00; + break; + case CXD2880_TNRDMD_XTAL_SHARE_MASTER: + data[2] = 0x01; + data[3] = 0x01; + break; + case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: + data[2] = 0x00; + data[3] = 0x01; + break; + default: + return -EINVAL; + } + data[4] = 0x06; + data[5] = 0x00; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 6); +} + +static int p_init3(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + switch (tnr_dmd->diver_mode) { + case CXD2880_TNRDMD_DIVERMODE_SINGLE: + data[0] = 0x00; + break; + case CXD2880_TNRDMD_DIVERMODE_MAIN: + data[0] = 0x03; + break; + case CXD2880_TNRDMD_DIVERMODE_SUB: + data[0] = 0x02; + break; + default: + return -EINVAL; + } + + data[1] = 0x01; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1f, data, 2); +} + +static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[8] = { 0 }; + static const u8 rf_init1_cdata1[40] = { + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x04, 0x04, 0x04 + }; + + static const u8 rf_init1_cdata2[5] = {0xff, 0x00, 0x00, 0x00, 0x00}; + static const u8 rf_init1_cdata3[80] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09, + 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, + 0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0a, 0x03, 0xe0 + }; + + static const u8 rf_init1_cdata4[8] = { + 0x20, 0x20, 0x30, 0x41, 0x50, 0x5f, 0x6f, 0x80 + }; + + static const u8 rf_init1_cdata5[50] = { + 0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, + 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, + 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00, + 0x0e + }; + + u8 addr = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x01; + data[1] = 0x00; + data[2] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x21, data, 3); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + data[0] = 0x01; + data[1] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x17, data, 2); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1a, 0x06); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq1, + ARRAY_SIZE(rf_init1_seq1)); + if (ret) + return ret; + + data[0] = 0x00; + if (tnr_dmd->create_param.is_cxd2881gg && + tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) + data[1] = 0x00; + else + data[1] = 0x1f; + data[2] = 0x0a; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xb5, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq2, + ARRAY_SIZE(rf_init1_seq2)); + if (ret) + return ret; + + if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) { + data[0] = 0x34; + data[1] = 0x2c; + } else { + data[0] = 0x2f; + data[1] = 0x25; + } + data[2] = 0x15; + data[3] = 0x19; + data[4] = 0x1b; + data[5] = 0x15; + data[6] = 0x19; + data[7] = 0x1b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xd9, data, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + data[0] = 0x6c; + data[1] = 0x10; + data[2] = 0xa6; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 3); + if (ret) + return ret; + data[0] = 0x16; + data[1] = 0xa8; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x50, data, 2); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x22; + data[2] = 0x00; + data[3] = 0x88; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x62, data, 4); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x74, 0x75); + if (ret) + return ret; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x7f, rf_init1_cdata1, 40); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x16); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x71; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x23, 0x89); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, rf_init1_cdata2, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3a, rf_init1_cdata3, 80); + if (ret) + return ret; + + data[0] = 0x03; + data[1] = 0xe0; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbc, data, 2); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq3, + ARRAY_SIZE(rf_init1_seq3)); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + data[0] = 0x06; + data[1] = 0x07; + data[2] = 0x1a; + } else { + data[0] = 0x00; + data[1] = 0x08; + data[2] = 0x19; + } + data[3] = 0x0e; + data[4] = 0x09; + data[5] = 0x0e; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x12); + if (ret) + return ret; + for (addr = 0x10; addr < 0x9f; addr += 6) { + if (tnr_dmd->lna_thrs_tbl_air) { + u8 idx = 0; + + idx = (addr - 0x10) / 6; + data[0] = + tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on; + data[1] = + tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; + } + + data[0] = 0x00; + data[1] = 0x08; + if (tnr_dmd->create_param.stationary_use) + data[2] = 0x1a; + else + data[2] = 0x19; + data[3] = 0x0e; + data[4] = 0x09; + data[5] = 0x0e; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x13); + if (ret) + return ret; + for (addr = 0x10; addr < 0xcf; addr += 6) { + if (tnr_dmd->lna_thrs_tbl_cable) { + u8 idx = 0; + + idx = (addr - 0x10) / 6; + data[0] = + tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on; + data[1] = + tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + addr, data, 6); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xbd, data, 2); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc4, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xc9, rf_init1_cdata4, 8); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x14); + if (ret) + return ret; + data[0] = 0x15; + data[1] = 0x18; + data[2] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq4, + ARRAY_SIZE(rf_init1_seq4)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, rf_init1_cdata5, 50); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq5, + ARRAY_SIZE(rf_init1_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq6, + ARRAY_SIZE(rf_init1_seq6)); + if (ret) + return ret; + + data[0] = 0x00; + data[1] = 0xfe; + data[2] = 0xee; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6e, data, 3); + if (ret) + return ret; + data[0] = 0xa1; + data[1] = 0x8b; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8d, data, 2); + if (ret) + return ret; + data[0] = 0x08; + data[1] = 0x09; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x77, data, 2); + if (ret) + return ret; + + if (tnr_dmd->create_param.stationary_use) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, 0xaa); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init1_seq7, + ARRAY_SIZE(rf_init1_seq7)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq8, + ARRAY_SIZE(rf_init1_seq8)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init1_seq9, + ARRAY_SIZE(rf_init1_seq9)); +} + +static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[5] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + data[0] = 0x40; + data[1] = 0x40; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xea, data, 2); + if (ret) + return ret; + + usleep_range(1000, 2000); + + data[0] = 0x00; + if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) + data[1] = 0x00; + else + data[1] = 0x01; + data[2] = 0x01; + data[3] = 0x03; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data, 4); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + rf_init2_seq1, + ARRAY_SIZE(rf_init2_seq1)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + rf_init2_seq2, + ARRAY_SIZE(rf_init2_seq2)); +} + +static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, u32 freq_khz, + enum cxd2880_dtv_bandwidth bandwidth, + u8 is_cable, int shift_frequency_khz) +{ + u8 data[11] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune1_seq1, + ARRAY_SIZE(x_tune1_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[2] = 0x0e; + data[4] = 0x03; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; + + data[0] = 0x1f; + data[1] = 0x80; + data[2] = 0x18; + data[3] = 0x00; + data[4] = 0x07; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xe7, data, 5); + if (ret) + return ret; + + usleep_range(1000, 2000); + + data[0] = 0x72; + data[1] = 0x81; + data[3] = 0x1d; + data[4] = 0x6f; + data[5] = 0x7e; + data[7] = 0x1c; + switch (sys) { + case CXD2880_DTV_SYS_DVBT: + data[2] = 0x94; + data[6] = 0x91; + break; + case CXD2880_DTV_SYS_DVBT2: + data[2] = 0x96; + data[6] = 0x93; + break; + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x44, data, 8); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune1_seq2, + ARRAY_SIZE(x_tune1_seq2)); + if (ret) + return ret; + + data[0] = 0x03; + data[1] = 0xe2; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x1e, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + data[0] = is_cable ? 0x01 : 0x00; + data[1] = 0x00; + data[2] = 0x6b; + data[3] = 0x4d; + + switch (bandwidth) { + case CXD2880_DTV_BW_1_7_MHZ: + data[4] = 0x03; + break; + case CXD2880_DTV_BW_5_MHZ: + case CXD2880_DTV_BW_6_MHZ: + data[4] = 0x00; + break; + case CXD2880_DTV_BW_7_MHZ: + data[4] = 0x01; + break; + case CXD2880_DTV_BW_8_MHZ: + data[4] = 0x02; + break; + default: + return -EINVAL; + } + + data[5] = 0x00; + + freq_khz += shift_frequency_khz; + + data[6] = (freq_khz >> 16) & 0x0f; + data[7] = (freq_khz >> 8) & 0xff; + data[8] = freq_khz & 0xff; + data[9] = 0xff; + data[10] = 0xfe; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, data, 11); +} + +static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_bandwidth bandwidth, + enum cxd2880_tnrdmd_clockmode clk_mode, + int shift_frequency_khz) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x11); + if (ret) + return ret; + + data[0] = 0x01; + data[1] = 0x0e; + data[2] = 0x01; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2d, data, 3); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq1, + ARRAY_SIZE(x_tune2_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2c, data, 1); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x60, data[0]); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_tune2_seq2, + ARRAY_SIZE(x_tune2_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq3, + ARRAY_SIZE(x_tune2_seq3)); + if (ret) + return ret; + + if (shift_frequency_khz != 0) { + int shift_freq = 0; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0xe1); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; + + shift_freq = shift_frequency_khz * 1000; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = (shift_freq + 183 / 2) / 183; + else + shift_freq = (shift_freq - 183 / 2) / 183; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = (shift_freq + 178 / 2) / 178; + else + shift_freq = (shift_freq - 178 / 2) / 178; + break; + } + + shift_freq += + cxd2880_convert2s_complement((data[0] << 8) | data[1], 16); + + if (shift_freq > 32767) + shift_freq = 32767; + else if (shift_freq < -32768) + shift_freq = -32768; + + data[0] = (shift_freq >> 8) & 0xff; + data[1] = shift_freq & 0xff; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data, 1); + if (ret) + return ret; + + shift_freq = -shift_frequency_khz; + + if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 17578 / 2) / 17578; + else + shift_freq = + (shift_freq * 1000 - + 17578 / 2) / 17578; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 17090 / 2) / 17090; + else + shift_freq = + (shift_freq * 1000 - + 17090 / 2) / 17090; + break; + } + } else { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + default: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 35156 / 2) / 35156; + else + shift_freq = + (shift_freq * 1000 - + 35156 / 2) / 35156; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + if (shift_freq >= 0) + shift_freq = + (shift_freq * 1000 + + 34180 / 2) / 34180; + else + shift_freq = + (shift_freq * 1000 - + 34180 / 2) / 34180; + break; + } + } + + shift_freq += cxd2880_convert2s_complement(data[0], 8); + + if (shift_freq > 127) + shift_freq = 127; + else if (shift_freq < -128) + shift_freq = -128; + + data[0] = shift_freq & 0xff; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x69, data[0]); + if (ret) + return ret; + } + + if (tnr_dmd->create_param.stationary_use) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq4, + ARRAY_SIZE(x_tune2_seq4)); + if (ret) + return ret; + } + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune2_seq5, + ARRAY_SIZE(x_tune2_seq5)); +} + +static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) +{ + u8 data[6] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune3_seq, + ARRAY_SIZE(x_tune3_seq)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) + memset(data, 0x01, sizeof(data)); + else + memset(data, 0x00, sizeof(data)); + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xef, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; + if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl) + data[0] = 0x00; + else + data[0] = 0x01; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, data[0]); +} + +static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x01); + if (ret) + return ret; + data[0] = 0x0b; + data[1] = 0xff; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x14; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x57, 0x02); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); + if (ret) + return ret; + + return cxd2880_io_write_multi_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_DMD, + x_tune4_seq, + ARRAY_SIZE(x_tune4_seq)); +} + +static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep1_seq, + ARRAY_SIZE(x_sleep1_seq)); + if (ret) + return ret; + + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + data[2] = 0x03; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 3); + if (ret) + return ret; + data[0] = 0x00; + data[1] = 0x00; + ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, + CXD2880_IO_TGT_SYS, + 0x53, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + data[0] = 0x1f; + data[1] = 0xff; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x55, data, 2); +} + +static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep2_seq1, + ARRAY_SIZE(x_sleep2_seq1)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb2, &data, 1); + if (ret) + return ret; + + if ((data & 0x01) == 0x00) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + x_sleep2_seq2, + ARRAY_SIZE(x_sleep2_seq2)); +} + +static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep3_seq, + ARRAY_SIZE(x_sleep3_seq)); +} + +static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + x_sleep4_seq, + ARRAY_SIZE(x_sleep4_seq)); +} + +static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_clockmode clockmode) +{ + u8 data[4] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq1, + ARRAY_SIZE(spll_reset_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq2, + ARRAY_SIZE(spll_reset_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq3, + ARRAY_SIZE(spll_reset_seq3)); + if (ret) + return ret; + + switch (clockmode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data[0] = 0x00; + break; + + case CXD2880_TNRDMD_CLOCKMODE_B: + data[0] = 0x01; + break; + + case CXD2880_TNRDMD_CLOCKMODE_C: + data[0] = 0x02; + break; + + default: + return -EINVAL; + } + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x30, data[0]); + if (ret) + return ret; + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x22, 0x00); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x10, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0x00) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + spll_reset_seq4, + ARRAY_SIZE(spll_reset_seq4)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + spll_reset_seq5, + ARRAY_SIZE(spll_reset_seq5)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x26, data, 4); +} + +static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) +{ + u8 data[3] = { 0 }; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq1, + ARRAY_SIZE(t_power_x_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq2, + ARRAY_SIZE(t_power_x_seq2)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq3, + ARRAY_SIZE(t_power_x_seq3)); + if (ret) + return ret; + + if (on) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, 0x01); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x12, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq4, + ARRAY_SIZE(t_power_x_seq4)); + if (ret) + return ret; + } else { + data[0] = 0x03; + data[1] = 0x00; + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2a, data, 2); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x13, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq5, + ARRAY_SIZE(t_power_x_seq5)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, data, 1); + if (ret) + return ret; + if ((data[0] & 0x01) == 0) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + t_power_x_seq6, + ARRAY_SIZE(t_power_x_seq6)); + if (ret) + return ret; + + usleep_range(1000, 2000); + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + t_power_x_seq7, + ARRAY_SIZE(t_power_x_seq7)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + memset(data, 0x00, sizeof(data)); + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x27, data, 3); +} + +struct cxd2880_tnrdmd_ts_clk_cfg { + u8 srl_clk_mode; + u8 srl_duty_mode; + u8 ts_clk_period; +}; + +static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys) +{ + int ret; + u8 backwards_compatible = 0; + struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg; + u8 ts_rate_ctrl_off = 0; + u8 ts_in_off = 0; + u8 ts_clk_manaul_on = 0; + u8 data = 0; + + static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = { + { + {3, 1, 8,}, + {0, 2, 16,} + }, { + {1, 1, 8,}, + {2, 2, 16,} + } + }; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + if (tnr_dmd->is_ts_backwards_compatible_mode) { + backwards_compatible = 1; + ts_rate_ctrl_off = 1; + ts_in_off = 1; + } else { + backwards_compatible = 0; + ts_rate_ctrl_off = 0; + ts_in_off = 0; + } + + if (tnr_dmd->ts_byte_clk_manual_setting) { + ts_clk_manaul_on = 1; + ts_rate_ctrl_off = 0; + } + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd3, ts_rate_ctrl_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, ts_in_off, 0x01); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xda, ts_clk_manaul_on, 0x01); + if (ret) + return ret; + + ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] + [tnr_dmd->srl_ts_clk_frq]; + + if (tnr_dmd->ts_byte_clk_manual_setting) + ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc4, ts_clk_cfg.srl_clk_mode, 0x03); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd1, ts_clk_cfg.srl_duty_mode, 0x03); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, 0xd9, + ts_clk_cfg.ts_clk_period); + if (ret) + return ret; + + data = backwards_compatible ? 0x00 : 0x01; + + if (sys == CXD2880_DTV_SYS_DVBT) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = + cxd2880_io_set_reg_bits(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x66, data, 0x01); + } + + return ret; +} + +static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) +{ + int i; + int ret; + u8 data[65]; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + if (!pid_ftr_cfg) + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, 0x02); + + data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00; + + for (i = 0; i < 32; i++) { + if (pid_ftr_cfg->pid_cfg[i].is_en) { + data[1 + (i * 2)] = (pid_ftr_cfg->pid_cfg[i].pid >> 8) | 0x20; + data[2 + (i * 2)] = pid_ftr_cfg->pid_cfg[i].pid & 0xff; + } else { + data[1 + (i * 2)] = 0x00; + data[2 + (i * 2)] = 0x00; + } + } + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x50, data, 65); +} + +static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + u8 i; + + if (!tnr_dmd) + return -EINVAL; + + for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + tnr_dmd->cfg_mem[i].tgt, + 0x00, tnr_dmd->cfg_mem[i].bank); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + tnr_dmd->cfg_mem[i].tgt, + tnr_dmd->cfg_mem[i].address, + tnr_dmd->cfg_mem[i].value, + tnr_dmd->cfg_mem[i].bit_mask); + if (ret) + return ret; + } + + return 0; +} + +static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, u8 value, u8 bit_mask) +{ + u8 i; + u8 value_stored = 0; + + if (!tnr_dmd) + return -EINVAL; + + for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) { + if (value_stored == 0 && + tnr_dmd->cfg_mem[i].tgt == tgt && + tnr_dmd->cfg_mem[i].bank == bank && + tnr_dmd->cfg_mem[i].address == address) { + tnr_dmd->cfg_mem[i].value &= ~bit_mask; + tnr_dmd->cfg_mem[i].value |= (value & bit_mask); + + tnr_dmd->cfg_mem[i].bit_mask |= bit_mask; + + value_stored = 1; + } + } + + if (value_stored) + return 0; + + if (tnr_dmd->cfg_mem_last_entry < CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) { + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank = bank; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address = address; + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value = (value & bit_mask); + tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask = bit_mask; + tnr_dmd->cfg_mem_last_entry++; + } else { + return -ENOMEM; + } + + return 0; +} + +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param) +{ + if (!tnr_dmd || !io || !create_param) + return -EINVAL; + + memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd)); + + tnr_dmd->io = io; + tnr_dmd->create_param = *create_param; + + tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE; + tnr_dmd->diver_sub = NULL; + + tnr_dmd->srl_ts_clk_mod_cnts = 1; + tnr_dmd->en_fef_intmtnt_base = 1; + tnr_dmd->en_fef_intmtnt_lite = 1; + tnr_dmd->rf_lvl_cmpstn = NULL; + tnr_dmd->lna_thrs_tbl_air = NULL; + tnr_dmd->lna_thrs_tbl_cable = NULL; + atomic_set(&tnr_dmd->cancel, 0); + + return 0; +} + +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param) +{ + struct cxd2880_tnrdmd_create_param *main_param, *sub_param; + + if (!tnr_dmd_main || !io_main || !tnr_dmd_sub || !io_sub || + !create_param) + return -EINVAL; + + memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); + memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd)); + + main_param = &tnr_dmd_main->create_param; + sub_param = &tnr_dmd_sub->create_param; + + tnr_dmd_main->io = io_main; + tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN; + tnr_dmd_main->diver_sub = tnr_dmd_sub; + tnr_dmd_main->create_param.en_internal_ldo = + create_param->en_internal_ldo; + + main_param->ts_output_if = create_param->ts_output_if; + main_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_MASTER; + main_param->xosc_cap = create_param->xosc_cap_main; + main_param->xosc_i = create_param->xosc_i_main; + main_param->is_cxd2881gg = create_param->is_cxd2881gg; + main_param->stationary_use = create_param->stationary_use; + + tnr_dmd_sub->io = io_sub; + tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB; + tnr_dmd_sub->diver_sub = NULL; + + sub_param->en_internal_ldo = create_param->en_internal_ldo; + sub_param->ts_output_if = create_param->ts_output_if; + sub_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_SLAVE; + sub_param->xosc_cap = 0; + sub_param->xosc_i = create_param->xosc_i_sub; + sub_param->is_cxd2881gg = create_param->is_cxd2881gg; + sub_param->stationary_use = create_param->stationary_use; + + tnr_dmd_main->srl_ts_clk_mod_cnts = 1; + tnr_dmd_main->en_fef_intmtnt_base = 1; + tnr_dmd_main->en_fef_intmtnt_lite = 1; + tnr_dmd_main->rf_lvl_cmpstn = NULL; + tnr_dmd_main->lna_thrs_tbl_air = NULL; + tnr_dmd_main->lna_thrs_tbl_cable = NULL; + + tnr_dmd_sub->srl_ts_clk_mod_cnts = 1; + tnr_dmd_sub->en_fef_intmtnt_base = 1; + tnr_dmd_sub->en_fef_intmtnt_lite = 1; + tnr_dmd_sub->rf_lvl_cmpstn = NULL; + tnr_dmd_sub->lna_thrs_tbl_air = NULL; + tnr_dmd_sub->lna_thrs_tbl_cable = NULL; + + return 0; +} + +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd || tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN; + tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN; + tnr_dmd->frequency_khz = 0; + tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; + tnr_dmd->scan_mode = 0; + atomic_set(&tnr_dmd->cancel, 0); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN; + tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN; + tnr_dmd->diver_sub->frequency_khz = 0; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; + tnr_dmd->diver_sub->scan_mode = 0; + atomic_set(&tnr_dmd->diver_sub->cancel, 0); + } + + ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id); + if (ret) + return ret; + + if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id)) + return -ENOTTY; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub, + &tnr_dmd->diver_sub->chip_id); + if (ret) + return ret; + + if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id)) + return -ENOTTY; + } + + ret = p_init1(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init1(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + usleep_range(1000, 2000); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = p_init2(tnr_dmd); + if (ret) + return ret; + + usleep_range(5000, 6000); + + ret = p_init3(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = p_init3(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = rf_init1(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = rf_init1(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 cpu_task_completed; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + ret = cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (!cpu_task_completed) + return -EINVAL; + + ret = rf_init2(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = rf_init2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = load_cfg_mem(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = load_cfg_mem(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; + + return ret; +} + +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed) +{ + u16 cpu_status = 0; + int ret; + + if (!tnr_dmd || !task_completed) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (cpu_status == 0) + *task_completed = 1; + else + *task_completed = 0; + + return ret; + } + if (cpu_status != 0) { + *task_completed = 0; + return ret; + } + + ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status); + if (ret) + return ret; + + if (cpu_status == 0) + *task_completed = 1; + else + *task_completed = 0; + + return ret; +} + +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir) +{ + u8 data; + enum cxd2880_tnrdmd_clockmode new_clk_mode = + CXD2880_TNRDMD_CLOCKMODE_A; + int shift_frequency_khz; + u8 cpu_task_completed; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (frequency_khz < 4000) + return -EINVAL; + + ret = cxd2880_tnrdmd_sleep(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, + 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x2b, + &data, + 1); + if (ret) + return ret; + + switch (sys) { + case CXD2880_DTV_SYS_DVBT: + if (data == 0x00) { + ret = t_power_x(tnr_dmd, 1); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 1); + if (ret) + return ret; + } + } + break; + + case CXD2880_DTV_SYS_DVBT2: + if (data == 0x01) { + ret = t_power_x(tnr_dmd, 0); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = t_power_x(tnr_dmd->diver_sub, 0); + if (ret) + return ret; + } + } + break; + + default: + return -EINVAL; + } + + ret = spll_reset(tnr_dmd, new_clk_mode); + if (ret) + return ret; + + tnr_dmd->clk_mode = new_clk_mode; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode); + if (ret) + return ret; + + tnr_dmd->diver_sub->clk_mode = new_clk_mode; + } + + ret = load_cfg_mem(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = load_cfg_mem(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + if (one_seg_opt) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 350; + } else { + if (one_seg_opt_shft_dir) + shift_frequency_khz = 350; + else + shift_frequency_khz = -350; + + if (tnr_dmd->create_param.xtal_share_type == + CXD2880_TNRDMD_XTAL_SHARE_SLAVE) + shift_frequency_khz *= -1; + } + } else { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + shift_frequency_khz = 150; + } else { + switch (tnr_dmd->create_param.xtal_share_type) { + case CXD2880_TNRDMD_XTAL_SHARE_NONE: + case CXD2880_TNRDMD_XTAL_SHARE_EXTREF: + default: + shift_frequency_khz = 0; + break; + case CXD2880_TNRDMD_XTAL_SHARE_MASTER: + shift_frequency_khz = 150; + break; + case CXD2880_TNRDMD_XTAL_SHARE_SLAVE: + shift_frequency_khz = -150; + break; + } + } + } + + ret = + x_tune1(tnr_dmd, sys, frequency_khz, bandwidth, + tnr_dmd->is_cable_input, shift_frequency_khz); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune1(tnr_dmd->diver_sub, sys, frequency_khz, + bandwidth, tnr_dmd->is_cable_input, + -shift_frequency_khz); + if (ret) + return ret; + } + + usleep_range(10000, 11000); + + ret = + cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (!cpu_task_completed) + return -EINVAL; + + ret = + x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, + shift_frequency_khz); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune2(tnr_dmd->diver_sub, bandwidth, + tnr_dmd->diver_sub->clk_mode, + -shift_frequency_khz); + if (ret) + return ret; + } + + if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) { + ret = set_ts_clk_mode_and_freq(tnr_dmd, sys); + } else { + struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg; + + if (tnr_dmd->pid_ftr_cfg_en) + pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg; + else + pid_ftr_cfg = NULL; + + ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg); + } + + return ret; +} + +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl); + if (ret) + return ret; + ret = x_tune4(tnr_dmd); + if (ret) + return ret; + } + + return cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); +} + +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) + return 0; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep1(tnr_dmd); + if (ret) + return ret; + } + + ret = x_sleep2(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep2(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + switch (tnr_dmd->sys) { + case CXD2880_DTV_SYS_DVBT: + ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; + + case CXD2880_DTV_SYS_DVBT2: + ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + ret = x_sleep3(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep3(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + ret = x_sleep4(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = x_sleep4(tnr_dmd->diver_sub); + if (ret) + return ret; + } + + tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->frequency_khz = 0; + tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP; + tnr_dmd->diver_sub->frequency_khz = 0; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN; + tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN; + } + + return 0; +} + +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value) +{ + int ret; + u8 data[2] = { 0 }; + u8 need_sub_setting = 0; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (id) { + case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc4, + value ? 0x00 : 0x10, + 0x10); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x00 : 0x02, + 0x02); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x00 : 0x04, + 0x04); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xcb, + value ? 0x00 : 0x01, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc5, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_CONT: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc6, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSVALID_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc8, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_MASK: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0x1f) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xc9, value, + 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x91, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_CURRENT: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x51, value, + 0x3f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x50, + value ? 0x80 : 0x00, + 0x80); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSPIN_PULLUP: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x50, value, + 0x3f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TSCLK_FREQ: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 1) + return -EINVAL; + + tnr_dmd->srl_ts_clk_frq = + (enum cxd2880_tnrdmd_serial_ts_clk)value; + break; + + case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 0xff) + return -EINVAL; + + tnr_dmd->ts_byte_clk_manual_setting = value; + + break; + + case CXD2880_TNRDMD_CFG_TS_PACKET_GAP: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (value < 0 || value > 7) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0xd6, value, + 0x07); + if (ret) + return ret; + + break; + + case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE: + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0; + + break; + + case CXD2880_TNRDMD_CFG_PWM_VALUE: + if (value < 0 || value > 0x1000) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x22, + value ? 0x01 : 0x00, + 0x01); + if (ret) + return ret; + + data[0] = (value >> 8) & 0x1f; + data[1] = value & 0xff; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x23, + data[0], 0x1f); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x24, + data[1], 0xff); + if (ret) + return ret; + + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT: + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x48, data[0], + 0xff); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x49, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL: + data[0] = value & 0x07; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x4a, data[0], + 0x07); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL: + data[0] = (value & 0x07) << 3; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x4a, data[0], + 0x38); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE: + if (value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN || + value > CXD2880_TNRDMD_CLOCKMODE_C) + return -EINVAL; + tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value; + break; + + case CXD2880_TNRDMD_CFG_CABLE_INPUT: + tnr_dmd->is_cable_input = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE: + tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE: + tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x99, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9a, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9b, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9c, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS: + data[0] = (value >> 8) & 0x07; + data[1] = value & 0xff; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9d, data[0], + 0x07); + if (ret) + return ret; + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x00, 0x9e, data[1], + 0xff); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST: + tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0; + break; + + case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD: + if (value < 0 || value > 31) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x60, + value & 0x1f, 0x1f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD: + if (value < 0 || value > 7) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x6f, + value & 0x07, 0x07); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x20, 0x72, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x20, 0x6f, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT_PER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x10, 0x5c, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + case CXD2880_TNRDMD_CFG_DVBT2_PER_MES: + if (value < 0 || value > 15) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_DMD, + 0x24, 0xdc, + value & 0x0f, 0x0f); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + if (need_sub_setting && + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value); + + return ret; +} + +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x40 + id, mode, + 0x0f); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x43, + open_drain ? (1 << id) : 0, + 1 << id); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, + 0x00, 0x44, + invert ? (1 << id) : 0, + 1 << id); + if (ret) + return ret; + + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x45, + en ? 0 : (1 << id), + 1 << id); +} + +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, u8 invert) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, + open_drain, invert); +} + +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd || !value) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x20, &data, 1); + if (ret) + return ret; + + *value = (data >> id) & 0x01; + + return 0; +} + +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); +} + +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (id > 2) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, + CXD2880_IO_TGT_SYS, + 0x00, 0x46, + value ? (1 << id) : 0, + 1 << id); +} + +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); +} + +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd || !value) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x0a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; + + *value = (data[0] << 8) | data[1]; + + return 0; +} + +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + data[0] = (value >> 8) & 0xff; + data[1] = value & 0xff; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x3c, data, 2); +} + +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf) +{ + int ret; + u8 data[2] = { 0 }; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + data[0] = clear_overflow_flag ? 0x02 : 0x00; + data[0] |= clear_underflow_flag ? 0x01 : 0x00; + data[1] = clear_buf ? 0x01 : 0x00; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9f, data, 2); +} + +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id) +{ + int ret; + u8 data = 0; + + if (!tnr_dmd || !chip_id) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0xfd, &data, 1); + if (ret) + return ret; + + *chip_id = (enum cxd2880_tnrdmd_chip_id)data; + + return 0; +} + +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank); + if (ret) + return ret; + + ret = cxd2880_io_set_reg_bits(tnr_dmd->io, + tgt, address, value, bit_mask); + if (ret) + return ret; + + return set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); +} + +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + tnr_dmd->scan_mode = scan_mode_end; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + return cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, + scan_mode_end); + else + return 0; +} + +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) + return -ENOTTY; + + if (pid_ftr_cfg) { + tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg; + tnr_dmd->pid_ftr_cfg_en = 1; + } else { + tnr_dmd->pid_ftr_cfg_en = 0; + } + + if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) + return pid_ftr_setting(tnr_dmd, pid_ftr_cfg); + else + return 0; +} + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) +{ + if (!tnr_dmd) + return -EINVAL; + + tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn; + + return 0; +} + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, + rf_lvl_cmpstn); +} + +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) +{ + if (!tnr_dmd) + return -EINVAL; + + tnr_dmd->lna_thrs_tbl_air = tbl_air; + tnr_dmd->lna_thrs_tbl_cable = tbl_cable; + + return 0; +} + +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable) +{ + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, + tbl_air, tbl_cable); +} + +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) + return -EINVAL; + + if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS) + return -ENOTTY; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x00); + if (ret) + return ret; + + if (en) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x50, ((value & 0x1f) | 0x80)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x52, (value & 0x1f)); + } else { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_pin_seq, + ARRAY_SIZE(set_ts_pin_seq)); + if (ret) + return ret; + + ret = load_cfg_mem(tnr_dmd); + } + + return ret; +} + +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_TS: + if (en) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq1, + ARRAY_SIZE(set_ts_output_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq2, + ARRAY_SIZE(set_ts_output_seq2)); + if (ret) + return ret; + } else { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + set_ts_output_seq3, + ARRAY_SIZE(set_ts_output_seq3)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + set_ts_output_seq4, + ARRAY_SIZE(set_ts_output_seq4)); + if (ret) + return ret; + } + break; + + case CXD2880_TNRDMD_TSOUT_IF_SPI: + break; + + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + break; + + default: + return -EINVAL; + } + + return 0; +} + +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 data; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + switch (tnr_dmd->create_param.ts_output_if) { + case CXD2880_TNRDMD_TSOUT_IF_SPI: + case CXD2880_TNRDMD_TSOUT_IF_SDIO: + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, &data, 1); + if (ret) + return ret; + + break; + case CXD2880_TNRDMD_TSOUT_IF_TS: + default: + break; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x01, 0x01); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h new file mode 100644 index 000000000000..9d809a251fc7 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h @@ -0,0 +1,365 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common control interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_H +#define CXD2880_TNRDMD_H + +#include + +#include "cxd2880_common.h" +#include "cxd2880_io.h" +#include "cxd2880_dtv.h" +#include "cxd2880_dvbt.h" +#include "cxd2880_dvbt2.h" + +#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100 + +#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\ +((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00))) + +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW 0x0001 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW 0x0002 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY 0x0004 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL 0x0008 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY 0x0010 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND 0x0020 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS 0x0040 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR 0x0100 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK 0x0200 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK 0x0400 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM 0x0800 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS 0x1000 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW 0x2000 +#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL 0x4000 + +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK 0x01 +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK 0x02 +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK 0x04 + +enum cxd2880_tnrdmd_chip_id { + CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00, + CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62, + CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a +}; + +#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \ + (((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \ + ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) + +enum cxd2880_tnrdmd_state { + CXD2880_TNRDMD_STATE_UNKNOWN, + CXD2880_TNRDMD_STATE_SLEEP, + CXD2880_TNRDMD_STATE_ACTIVE, + CXD2880_TNRDMD_STATE_INVALID +}; + +enum cxd2880_tnrdmd_divermode { + CXD2880_TNRDMD_DIVERMODE_SINGLE, + CXD2880_TNRDMD_DIVERMODE_MAIN, + CXD2880_TNRDMD_DIVERMODE_SUB +}; + +enum cxd2880_tnrdmd_clockmode { + CXD2880_TNRDMD_CLOCKMODE_UNKNOWN, + CXD2880_TNRDMD_CLOCKMODE_A, + CXD2880_TNRDMD_CLOCKMODE_B, + CXD2880_TNRDMD_CLOCKMODE_C +}; + +enum cxd2880_tnrdmd_tsout_if { + CXD2880_TNRDMD_TSOUT_IF_TS, + CXD2880_TNRDMD_TSOUT_IF_SPI, + CXD2880_TNRDMD_TSOUT_IF_SDIO +}; + +enum cxd2880_tnrdmd_xtal_share { + CXD2880_TNRDMD_XTAL_SHARE_NONE, + CXD2880_TNRDMD_XTAL_SHARE_EXTREF, + CXD2880_TNRDMD_XTAL_SHARE_MASTER, + CXD2880_TNRDMD_XTAL_SHARE_SLAVE +}; + +enum cxd2880_tnrdmd_spectrum_sense { + CXD2880_TNRDMD_SPECTRUM_NORMAL, + CXD2880_TNRDMD_SPECTRUM_INV +}; + +enum cxd2880_tnrdmd_cfg_id { + CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB, + CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI, + CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI, + CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI, + CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE, + CXD2880_TNRDMD_CFG_TSCLK_CONT, + CXD2880_TNRDMD_CFG_TSCLK_MASK, + CXD2880_TNRDMD_CFG_TSVALID_MASK, + CXD2880_TNRDMD_CFG_TSERR_MASK, + CXD2880_TNRDMD_CFG_TSERR_VALID_DIS, + CXD2880_TNRDMD_CFG_TSPIN_CURRENT, + CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL, + CXD2880_TNRDMD_CFG_TSPIN_PULLUP, + CXD2880_TNRDMD_CFG_TSCLK_FREQ, + CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL, + CXD2880_TNRDMD_CFG_TS_PACKET_GAP, + CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE, + CXD2880_TNRDMD_CFG_PWM_VALUE, + CXD2880_TNRDMD_CFG_INTERRUPT, + CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL, + CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL, + CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS, + CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS, + CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS, + CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE, + CXD2880_TNRDMD_CFG_CABLE_INPUT, + CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE, + CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE, + CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST, + CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, + CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, + CXD2880_TNRDMD_CFG_DVBT_PER_MES, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, +}; + +enum cxd2880_tnrdmd_lock_result { + CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT, + CXD2880_TNRDMD_LOCK_RESULT_LOCKED, + CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED +}; + +enum cxd2880_tnrdmd_gpio_mode { + CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00, + CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01, + CXD2880_TNRDMD_GPIO_MODE_INT = 0x02, + CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03, + CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04, + CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05, + CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06 +}; + +enum cxd2880_tnrdmd_serial_ts_clk { + CXD2880_TNRDMD_SERIAL_TS_CLK_FULL, + CXD2880_TNRDMD_SERIAL_TS_CLK_HALF +}; + +struct cxd2880_tnrdmd_cfg_mem { + enum cxd2880_io_tgt tgt; + u8 bank; + u8 address; + u8 value; + u8 bit_mask; +}; + +struct cxd2880_tnrdmd_pid_cfg { + u8 is_en; + u16 pid; +}; + +struct cxd2880_tnrdmd_pid_ftr_cfg { + u8 is_negative; + struct cxd2880_tnrdmd_pid_cfg pid_cfg[32]; +}; + +struct cxd2880_tnrdmd_lna_thrs { + u8 off_on; + u8 on_off; +}; + +struct cxd2880_tnrdmd_lna_thrs_tbl_air { + struct cxd2880_tnrdmd_lna_thrs thrs[24]; +}; + +struct cxd2880_tnrdmd_lna_thrs_tbl_cable { + struct cxd2880_tnrdmd_lna_thrs thrs[32]; +}; + +struct cxd2880_tnrdmd_create_param { + enum cxd2880_tnrdmd_tsout_if ts_output_if; + u8 en_internal_ldo; + enum cxd2880_tnrdmd_xtal_share xtal_share_type; + u8 xosc_cap; + u8 xosc_i; + u8 is_cxd2881gg; + u8 stationary_use; +}; + +struct cxd2880_tnrdmd_diver_create_param { + enum cxd2880_tnrdmd_tsout_if ts_output_if; + u8 en_internal_ldo; + u8 xosc_cap_main; + u8 xosc_i_main; + u8 xosc_i_sub; + u8 is_cxd2881gg; + u8 stationary_use; +}; + +struct cxd2880_tnrdmd { + struct cxd2880_tnrdmd *diver_sub; + struct cxd2880_io *io; + struct cxd2880_tnrdmd_create_param create_param; + enum cxd2880_tnrdmd_divermode diver_mode; + enum cxd2880_tnrdmd_clockmode fixed_clk_mode; + u8 is_cable_input; + u8 en_fef_intmtnt_base; + u8 en_fef_intmtnt_lite; + u8 blind_tune_dvbt2_first; + int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air; + struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable; + u8 srl_ts_clk_mod_cnts; + enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq; + u8 ts_byte_clk_manual_setting; + u8 is_ts_backwards_compatible_mode; + struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT]; + u8 cfg_mem_last_entry; + struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg; + u8 pid_ftr_cfg_en; + void *user; + enum cxd2880_tnrdmd_chip_id chip_id; + enum cxd2880_tnrdmd_state state; + enum cxd2880_tnrdmd_clockmode clk_mode; + u32 frequency_khz; + enum cxd2880_dtv_sys sys; + enum cxd2880_dtv_bandwidth bandwidth; + u8 scan_mode; + atomic_t cancel; +}; + +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_io *io, + struct cxd2880_tnrdmd_create_param + *create_param); + +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd + *tnr_dmd_main, + struct cxd2880_io *io_main, + struct cxd2880_tnrdmd *tnr_dmd_sub, + struct cxd2880_io *io_sub, + struct + cxd2880_tnrdmd_diver_create_param + *create_param); + +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *task_completed); + +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u32 frequency_khz, + enum cxd2880_dtv_bandwidth + bandwidth, u8 one_seg_opt, + u8 one_seg_opt_shft_dir); + +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 en_fef_intmtnt_ctrl); + +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_cfg_id id, + int value); + +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode mode, + u8 open_drain, u8 invert); + +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, + u8 en, + enum cxd2880_tnrdmd_gpio_mode + mode, u8 open_drain, + u8 invert); + +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 *value); + +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 id, u8 value); + +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, + u16 *value); + +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, + u16 value); + +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, + u8 clear_overflow_flag, + u8 clear_underflow_flag, + u8 clear_buf); + +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_tnrdmd_chip_id *chip_id); + +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_io_tgt tgt, + u8 bank, u8 address, + u8 value, u8 bit_mask); + +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dtv_sys sys, + u8 scan_mode_end); + +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_tnrdmd_pid_ftr_cfg + *pid_ftr_cfg); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd + *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd, + int (*rf_lvl_cmpstn) + (struct cxd2880_tnrdmd *, + int *)); + +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd, + struct + cxd2880_tnrdmd_lna_thrs_tbl_air + *tbl_air, + struct + cxd2880_tnrdmd_lna_thrs_tbl_cable + *tbl_cable); + +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd + *tnr_dmd, u8 en, u8 value); + +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, + u8 en); + +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd); + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h new file mode 100644 index 000000000000..fab55038b37b --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_driver_version.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * version information + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.4" + +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-01-17" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c new file mode 100644 index 000000000000..3d8012c18e3f --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd_mon.h" + +static const u8 rf_lvl_seq[2] = { + 0x80, 0x00, +}; + +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) +{ + u8 rdata[2]; + int ret; + + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x01); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x5b, rf_lvl_seq, 2); + if (ret) + return ret; + + usleep_range(2000, 3000); + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, rdata, 2); + if (ret) + return ret; + + if (rdata[0] || rdata[1]) + return -EINVAL; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x11, rdata, 2); + if (ret) + return ret; + + *rf_lvl_db = + cxd2880_convert2s_complement((rdata[0] << 3) | + ((rdata[1] & 0xe0) >> 5), 11); + + *rf_lvl_db *= 125; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, 0x00); + if (ret) + return ret; + + if (tnr_dmd->rf_lvl_cmpstn) + ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db); + + return ret; +} + +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db) +{ + if (!tnr_dmd || !rf_lvl_db) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); +} + +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status) +{ + u8 data[2] = { 0 }; + int ret; + + if (!tnr_dmd || !status) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x00, 0x1a); + if (ret) + return ret; + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + 0x15, data, 2); + if (ret) + return ret; + + *status = (data[0] << 8) | data[1]; + + return 0; +} + +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status) +{ + if (!tnr_dmd || !status) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, + status); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h new file mode 100644 index 000000000000..570360925f87 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * common monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_MON_H +#define CXD2880_TNRDMD_MON_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, + int *rf_lvl_db); + +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd + *tnr_dmd, u16 *status); + +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + u16 *status); +#endif -- cgit From aff18712be87c0cfb735037741c0f26da287e10c Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:51:10 -0500 Subject: media: cxd2880: Add integration layer for the driver These functions monitor the driver and watch for task completion. This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- .../media/dvb-frontends/cxd2880/cxd2880_integ.c | 72 ++++++++++++++++++++++ .../media/dvb-frontends/cxd2880/cxd2880_integ.h | 27 ++++++++ 2 files changed, 99 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c new file mode 100644 index 000000000000..5302ab0964c1 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_integ.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * integration layer common functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include +#include + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_integ.h" + +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + ktime_t start; + u8 cpu_task_completed = 0; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_tnrdmd_init1(tnr_dmd); + if (ret) + return ret; + + start = ktime_get(); + + while (1) { + ret = + cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, + &cpu_task_completed); + if (ret) + return ret; + + if (cpu_task_completed) + break; + + if (ktime_to_ms(ktime_sub(ktime_get(), start)) > + CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) + return -ETIMEDOUT; + + usleep_range(CXD2880_TNRDMD_WAIT_INIT_INTVL, + CXD2880_TNRDMD_WAIT_INIT_INTVL + 1000); + } + + return cxd2880_tnrdmd_init2(tnr_dmd); +} + +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 1); + + return 0; +} + +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd) +{ + if (!tnr_dmd) + return -EINVAL; + + if (atomic_read(&tnr_dmd->cancel) != 0) + return -ECANCELED; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h new file mode 100644 index 000000000000..7160225db8b9 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_integ.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * integration layer common interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_INTEG_H +#define CXD2880_INTEG_H + +#include "cxd2880_tnrdmd.h" + +#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT 500 +#define CXD2880_TNRDMD_WAIT_INIT_INTVL 10 + +#define CXD2880_TNRDMD_WAIT_AGC_STABLE 100 + +int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd + *tnr_dmd); + +#endif -- cgit From 9593810cd42a6d620aa2950ea2d74f079dfa2f4e Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:52:17 -0500 Subject: media: cxd2880: Add top level of the driver This provides the main dvb frontend operation functions for the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1954 +++++++++++++++++++++ 1 file changed, 1954 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c new file mode 100644 index 000000000000..f109e9d98cc0 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -0,0 +1,1954 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_top.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include + +#include "dvb_frontend.h" +#include "dvb_math.h" + +#include "cxd2880.h" +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" +#include "cxd2880_integ.h" +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_devio_spi.h" +#include "cxd2880_spi_device.h" +#include "cxd2880_tnrdmd_driver_version.h" + +struct cxd2880_priv { + struct cxd2880_tnrdmd tnrdmd; + struct spi_device *spi; + struct cxd2880_io regio; + struct cxd2880_spi_device spi_device; + struct cxd2880_spi cxd2880_spi; + struct cxd2880_dvbt_tune_param dvbt_tune_param; + struct cxd2880_dvbt2_tune_param dvbt2_tune_param; + struct mutex *spi_mutex; /* For SPI access exclusive control */ + unsigned long pre_ber_update; + unsigned long pre_ber_interval; + unsigned long post_ber_update; + unsigned long post_ber_interval; + unsigned long ucblock_update; + unsigned long ucblock_interval; + enum fe_status s; +}; + +static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, u32 *pre_bit_count) +{ + u8 rdata[2]; + int ret; + + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x39, rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if ((rdata[0] & 0x01) == 0) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x22, rdata, 2); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + *pre_bit_err = (rdata[0] << 8) | rdata[1]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + slvt_unfreeze_reg(tnrdmd); + + *pre_bit_count = ((rdata[0] & 0x07) == 0) ? + 256 : (0x1000 << (rdata[0] & 0x07)); + + return 0; +} + +static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *pre_bit_err, + u32 *pre_bit_count) +{ + u32 period_exp = 0; + u32 n_ldpc = 0; + u8 data[5]; + int ret; + + if (!tnrdmd || !pre_bit_err || !pre_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (!(data[0] & 0x01)) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + *pre_bit_err = + ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == + CXD2880_DVBT2_FEC_LDPC_16K) + n_ldpc = 16200; + else + n_ldpc = 64800; + slvt_unfreeze_reg(tnrdmd); + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x6f, data, 1); + if (ret) + return ret; + + period_exp = data[0] & 0x0f; + + *pre_bit_count = (1U << period_exp) * n_ldpc; + + return 0; +} + +static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) +{ + u8 rdata[3]; + u32 bit_error = 0; + u32 period_exp = 0; + int ret; + + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x40) == 0) + return -EAGAIN; + + *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x60, rdata, 1); + if (ret) + return ret; + + period_exp = (rdata[0] & 0x1f); + + if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8)) + return -EAGAIN; + + *post_bit_count = (1U << period_exp) * 204 * 8; + + return 0; +} + +static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *post_bit_err, + u32 *post_bit_count) +{ + u32 period_exp = 0; + u32 n_bch = 0; + u8 data[3]; + enum cxd2880_dvbt2_plp_fec plp_fec_type = + CXD2880_DVBT2_FEC_LDPC_16K; + enum cxd2880_dvbt2_plp_code_rate plp_code_rate = + CXD2880_DVBT2_R1_2; + int ret; + static const u16 n_bch_bits_lookup[2][8] = { + {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, + {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} + }; + + if (!tnrdmd || !post_bit_err || !post_bit_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnrdmd); + if (ret) + return ret; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x15, data, 3); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + if (!(data[0] & 0x40)) { + slvt_unfreeze_reg(tnrdmd); + return -EAGAIN; + } + + *post_bit_err = + ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2]; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + plp_code_rate = + (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xa0, data, 1); + if (ret) { + slvt_unfreeze_reg(tnrdmd); + return ret; + } + + plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); + + slvt_unfreeze_reg(tnrdmd); + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x72, data, 1); + if (ret) + return ret; + + period_exp = data[0] & 0x0f; + + if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K || + plp_code_rate > CXD2880_DVBT2_R2_5) + return -EAGAIN; + + n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; + + if (*post_bit_err > ((1U << period_exp) * n_bch)) + return -EAGAIN; + + *post_bit_count = (1U << period_exp) * n_bch; + + return 0; +} + +static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) +{ + u8 rdata[3]; + int ret; + + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x01) == 0) + return -EAGAIN; + + *block_err = (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x5c, rdata, 1); + if (ret) + return ret; + + *block_count = 1U << (rdata[0] & 0x0f); + + if ((*block_count == 0) || (*block_err > *block_count)) + return -EAGAIN; + + return 0; +} + +static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd, + u32 *block_err, + u32 *block_count) +{ + u8 rdata[3]; + int ret; + + if (!tnrdmd || !block_err || !block_count) + return -EINVAL; + + if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x18, rdata, 3); + if (ret) + return ret; + + if ((rdata[0] & 0x01) == 0) + return -EAGAIN; + + *block_err = (rdata[1] << 8) | rdata[2]; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x24); + if (ret) + return ret; + + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, rdata, 1); + if (ret) + return ret; + + *block_count = 1U << (rdata[0] & 0x0f); + + if ((*block_count == 0) || (*block_err > *block_count)) + return -EAGAIN; + + return 0; +} + +static void cxd2880_release(struct dvb_frontend *fe) +{ + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg.\n"); + return; + } + priv = fe->demodulator_priv; + kfree(priv); +} + +static int cxd2880_init(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct cxd2880_tnrdmd_create_param create_param; + + if (!fe) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI; + create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE; + create_param.en_internal_ldo = 1; + create_param.xosc_cap = 18; + create_param.xosc_i = 8; + create_param.stationary_use = 1; + + mutex_lock(priv->spi_mutex); + if (priv->tnrdmd.io != &priv->regio) { + ret = cxd2880_tnrdmd_create(&priv->tnrdmd, + &priv->regio, &create_param); + if (ret) { + mutex_unlock(priv->spi_mutex); + pr_info("cxd2880 tnrdmd create failed %d\n", ret); + return ret; + } + } + ret = cxd2880_integ_init(&priv->tnrdmd); + if (ret) { + mutex_unlock(priv->spi_mutex); + pr_err("cxd2880 integ init failed %d\n", ret); + return ret; + } + mutex_unlock(priv->spi_mutex); + + pr_debug("OK.\n"); + + return ret; +} + +static int cxd2880_sleep(struct dvb_frontend *fe) +{ + int ret; + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); + mutex_unlock(priv->spi_mutex); + + pr_debug("tnrdmd_sleep ret %d\n", ret); + + return ret; +} + +static int cxd2880_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + int level = 0; + + if (!fe || !strength) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT || + c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level); + } else { + pr_debug("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + level /= 125; + /* + * level should be between -105dBm and -30dBm. + * E.g. they should be between: + * -105000/125 = -840 and -30000/125 = -240 + */ + level = clamp(level, -840, -240); + /* scale value to 0x0000-0xffff */ + *strength = ((level + 840) * 0xffff) / (-240 + 840); + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int ret; + int snrvalue = 0; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !snr) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd, + &snrvalue); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd, + &snrvalue); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + if (snrvalue < 0) + snrvalue = 0; + *snr = snrvalue; + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !ucblocks) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd, + ucblocks); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd, + ucblocks); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + if (ret) + pr_debug("ret = %d\n", ret); + + return ret; +} + +static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + +static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) +{ + int ret; + struct dtv_frontend_properties *c; + struct cxd2880_priv *priv; + struct cxd2880_dvbt_tpsinfo info; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125}; + static const int denominator_tbl[4] = {125664, 129472, 137088, 152320}; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + bw = priv->dvbt_tune_param.bandwidth; + + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, + &info); + if (ret) { + pr_err("tps monitor error ret = %d\n", ret); + info.hierarchy = CXD2880_DVBT_HIERARCHY_NON; + info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK; + info.guard = CXD2880_DVBT_GUARD_1_4; + info.rate_hp = CXD2880_DVBT_CODERATE_1_2; + info.rate_lp = CXD2880_DVBT_CODERATE_1_2; + } + + if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) { + pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = 875 * cr_table[info.rate_hp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + } else { + u8 data = 0; + struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd; + + ret = tnrdmd->io->write_reg(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (!ret) { + ret = tnrdmd->io->read_regs(tnrdmd->io, + CXD2880_IO_TGT_DMD, + 0x67, &data, 1); + if (ret) + data = 0x00; + } else { + data = 0x00; + } + + if (data & 0x01) { /* Low priority */ + pre_ber_rate = + 63000000 * bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_lp] * bw * + (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] * + bw * (info.constellation * 2 + 2) / + denominator_tbl[info.guard]; + } else { /* High priority */ + pre_ber_rate = + 63000000 * bw * 2 / denominator_tbl[info.guard]; + + post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 / + denominator_tbl[info.guard]; + + ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] * + bw * 2 / denominator_tbl[info.guard]; + } + } + + mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, + mes_exp == 8 ? 0 : mes_exp - 12); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, + mes_exp); + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT_PER_MES, + mes_exp); + + return 0; +} + +static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) +{ + int ret; + struct dtv_frontend_properties *c; + struct cxd2880_priv *priv; + struct cxd2880_dvbt2_l1pre l1pre; + struct cxd2880_dvbt2_l1post l1post; + struct cxd2880_dvbt2_plp plp; + struct cxd2880_dvbt2_bbheader bbheader; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + u32 pre_ber_rate = 0; + u32 post_ber_rate = 0; + u32 ucblock_rate = 0; + u32 mes_exp = 0; + u32 term_a = 0; + u32 term_b = 0; + u32 denominator = 0; + static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76}; + static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1}; + static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32}; + static const u32 kbch_tbl[2][8] = { + {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232}, + {32128, 38608, 42960, 48328, 51568, 53760, 0, 0} + }; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + bw = priv->dvbt2_tune_param.bandwidth; + + ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); + if (ret) { + pr_info("l1 pre error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, &plp); + if (ret) { + pr_info("plp info error\n"); + goto error_ber_setting; + } + + ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post); + if (ret) { + pr_info("l1 post error\n"); + goto error_ber_setting; + } + + term_a = + (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) * + (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048; + + if (l1pre.mixed && l1post.fef_intvl) { + term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) / + l1post.fef_intvl; + } else { + term_b = 0; + } + + switch (bw) { + case CXD2880_DTV_BW_1_7_MHZ: + denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131; + break; + case CXD2880_DTV_BW_5_MHZ: + denominator = ((term_a + term_b) * 7 + 20) / 40; + break; + case CXD2880_DTV_BW_6_MHZ: + denominator = ((term_a + term_b) * 7 + 24) / 48; + break; + case CXD2880_DTV_BW_7_MHZ: + denominator = ((term_a + term_b) + 4) / 8; + break; + case CXD2880_DTV_BW_8_MHZ: + default: + denominator = ((term_a + term_b) * 7 + 32) / 64; + break; + } + + if (plp.til_type && plp.til_len) { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) / + plp.til_len; + } else { + pre_ber_rate = + (plp.num_blocks_max * 1000000 + (denominator / 2)) / + denominator; + } + + post_ber_rate = pre_ber_rate; + + mes_exp = intlog2(pre_ber_rate) >> 24; + priv->pre_ber_interval = + ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / + pre_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, + mes_exp); + + mes_exp = intlog2(post_ber_rate) >> 24; + priv->post_ber_interval = + ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / + post_ber_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, + mes_exp); + + ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &bbheader); + if (ret) { + pr_info("bb header error\n"); + goto error_ucblock_setting; + } + + if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + if (!bbheader.issy_indicator) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 752) / 1504; + } else { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + + 764) / 1528; + } + } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) { + ucblock_rate = + (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) / + 1496; + } else { + pr_info("plp mode is not Normal or HEM\n"); + goto error_ucblock_setting; + } + + mes_exp = intlog2(ucblock_rate) >> 24; + priv->ucblock_interval = + ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / + ucblock_rate; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, + mes_exp); + + return 0; + +error_ber_setting: + priv->pre_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0); + + priv->post_ber_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0); + +error_ucblock_setting: + priv->ucblock_interval = 1000; + cxd2880_tnrdmd_set_cfg(&priv->tnrdmd, + CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8); + + return 0; +} + +static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); +} + +static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + atomic_set(&tnr_dmd->cancel, 0); + + if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && + tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { + return -ENOTTY; + } + + if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE && + tune_param->profile != CXD2880_DVBT2_PROFILE_LITE) + return -EINVAL; + + ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); + if (ret) + return ret; + + usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, + CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); + + return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); +} + +static int cxd2880_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct dtv_frontend_properties *c; + struct cxd2880_priv *priv; + enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[0].uvalue = 0; + c->pre_bit_error.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[0].uvalue = 0; + c->pre_bit_count.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_error.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_count.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[0].uvalue = 0; + c->block_error.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].uvalue = 0; + c->block_count.len = 1; + + switch (c->bandwidth_hz) { + case 1712000: + bw = CXD2880_DTV_BW_1_7_MHZ; + break; + case 5000000: + bw = CXD2880_DTV_BW_5_MHZ; + break; + case 6000000: + bw = CXD2880_DTV_BW_6_MHZ; + break; + case 7000000: + bw = CXD2880_DTV_BW_7_MHZ; + break; + case 8000000: + bw = CXD2880_DTV_BW_8_MHZ; + break; + default: + return -EINVAL; + } + + priv->s = 0; + + pr_info("sys:%d freq:%d bw:%d\n", + c->delivery_system, c->frequency, bw); + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT; + priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000; + priv->dvbt_tune_param.bandwidth = bw; + priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP; + ret = cxd2880_dvbt_tune(&priv->tnrdmd, + &priv->dvbt_tune_param); + } else if (c->delivery_system == SYS_DVBT2) { + priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2; + priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000; + priv->dvbt2_tune_param.bandwidth = bw; + priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id; + priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE; + ret = cxd2880_dvbt2_tune(&priv->tnrdmd, + &priv->dvbt2_tune_param); + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + + pr_info("tune result %d\n", ret); + + return ret; +} + +static int cxd2880_get_stats(struct dvb_frontend *fe, + enum fe_status status) +{ + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + u32 pre_bit_err = 0, pre_bit_count = 0; + u32 post_bit_err = 0, post_bit_count = 0; + u32 block_err = 0, block_count = 0; + int ret; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + + if (!(status & FE_HAS_LOCK)) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + return 0; + } + + if (time_after(jiffies, priv->pre_ber_update)) { + priv->pre_ber_update = + jiffies + msecs_to_jiffies(priv->pre_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, + &pre_bit_err, + &pre_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += pre_bit_err; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += pre_bit_count; + } else { + c->pre_bit_error.len = 1; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.len = 1; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("pre_bit_error_t failed %d\n", ret); + } + } + + if (time_after(jiffies, priv->post_ber_update)) { + priv->post_ber_update = + jiffies + msecs_to_jiffies(priv->post_ber_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, + &post_bit_err, + &post_bit_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + + if (!ret) { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += post_bit_err; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += post_bit_count; + } else { + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = + FE_SCALE_NOT_AVAILABLE; + pr_debug("post_bit_err_t %d\n", ret); + } + } + + if (time_after(jiffies, priv->ucblock_update)) { + priv->ucblock_update = + jiffies + msecs_to_jiffies(priv->ucblock_interval); + if (c->delivery_system == SYS_DVBT) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else if (c->delivery_system == SYS_DVBT2) { + mutex_lock(priv->spi_mutex); + ret = cxd2880_read_block_err_t2(&priv->tnrdmd, + &block_err, + &block_count); + mutex_unlock(priv->spi_mutex); + } else { + return -EINVAL; + } + if (!ret) { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += block_err; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += block_count; + } else { + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_block_err_t %d\n", ret); + } + } + + return 0; +} + +static int cxd2880_check_l1post_plp(struct dvb_frontend *fe) +{ + u8 valid = 0; + u8 plp_not_found; + int ret; + struct cxd2880_priv *priv = NULL; + + if (!fe) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd, + &valid); + if (ret) + return ret; + + if (!valid) + return -EAGAIN; + + ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd, + &plp_not_found); + if (ret) + return ret; + + if (plp_not_found) { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; + } else { + priv->dvbt2_tune_param.tune_info = + CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; + } + + return 0; +} + +static int cxd2880_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + int ret; + u8 sync = 0; + u8 lock = 0; + u8 unlock = 0; + struct cxd2880_priv *priv = NULL; + struct dtv_frontend_properties *c = NULL; + + if (!fe || !status) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + c = &fe->dtv_property_cache; + *status = 0; + + if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) { + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd, + &sync, + &lock, + &unlock); + } else { + pr_err("invalid system"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + + mutex_unlock(priv->spi_mutex); + if (ret) { + pr_err("failed. sys = %d\n", priv->tnrdmd.sys); + return ret; + } + + if (sync == 6) { + *status = FE_HAS_SIGNAL | + FE_HAS_CARRIER; + } + if (lock) + *status |= FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_LOCK; + } + + pr_debug("status %d\n", *status); + + if (priv->s == 0 && (*status & FE_HAS_LOCK)) { + mutex_lock(priv->spi_mutex); + if (c->delivery_system == SYS_DVBT) { + ret = cxd2880_set_ber_per_period_t(fe); + priv->s = *status; + } else if (c->delivery_system == SYS_DVBT2) { + ret = cxd2880_check_l1post_plp(fe); + if (!ret) { + ret = cxd2880_set_ber_per_period_t2(fe); + priv->s = *status; + } + } else { + pr_err("invalid system\n"); + mutex_unlock(priv->spi_mutex); + return -EINVAL; + } + mutex_unlock(priv->spi_mutex); + } + + cxd2880_get_stats(fe, *status); + return 0; +} + +static int cxd2880_tune(struct dvb_frontend *fe, + bool retune, + unsigned int mode_flags, + unsigned int *delay, + enum fe_status *status) +{ + int ret; + + if (!fe || !delay || !status) { + pr_err("invalid arg."); + return -EINVAL; + } + + if (retune) { + ret = cxd2880_set_frontend(fe); + if (ret) { + pr_err("cxd2880_set_frontend failed %d\n", ret); + return ret; + } + } + + *delay = HZ / 5; + + return cxd2880_read_status(fe, status); +} + +static int cxd2880_get_frontend_t(struct dvb_frontend *fe, + struct dtv_frontend_properties *c) +{ + int ret; + struct cxd2880_priv *priv = NULL; + enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K; + enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32; + struct cxd2880_dvbt_tpsinfo tps; + enum cxd2880_tnrdmd_spectrum_sense sense; + u16 snr = 0; + int strength = 0; + + if (!fe || !c) { + pr_err("invalid arg\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd, + &mode, &guard); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (mode) { + case CXD2880_DVBT_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case CXD2880_DVBT_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + c->transmission_mode = TRANSMISSION_MODE_2K; + pr_debug("transmission mode is invalid %d\n", mode); + break; + } + switch (guard) { + case CXD2880_DVBT_GUARD_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case CXD2880_DVBT_GUARD_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case CXD2880_DVBT_GUARD_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case CXD2880_DVBT_GUARD_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("guard interval is invalid %d\n", + guard); + break; + } + } else { + c->transmission_mode = TRANSMISSION_MODE_2K; + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("ModeGuard err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (tps.hierarchy) { + case CXD2880_DVBT_HIERARCHY_NON: + c->hierarchy = HIERARCHY_NONE; + break; + case CXD2880_DVBT_HIERARCHY_1: + c->hierarchy = HIERARCHY_1; + break; + case CXD2880_DVBT_HIERARCHY_2: + c->hierarchy = HIERARCHY_2; + break; + case CXD2880_DVBT_HIERARCHY_4: + c->hierarchy = HIERARCHY_4; + break; + default: + c->hierarchy = HIERARCHY_NONE; + pr_debug("TPSInfo hierarchy is invalid %d\n", + tps.hierarchy); + break; + } + + switch (tps.rate_hp) { + case CXD2880_DVBT_CODERATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CXD2880_DVBT_CODERATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CXD2880_DVBT_CODERATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CXD2880_DVBT_CODERATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CXD2880_DVBT_CODERATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + default: + c->code_rate_HP = FEC_NONE; + pr_debug("TPSInfo rateHP is invalid %d\n", + tps.rate_hp); + break; + } + switch (tps.rate_lp) { + case CXD2880_DVBT_CODERATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CXD2880_DVBT_CODERATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CXD2880_DVBT_CODERATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CXD2880_DVBT_CODERATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CXD2880_DVBT_CODERATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + default: + c->code_rate_LP = FEC_NONE; + pr_debug("TPSInfo rateLP is invalid %d\n", + tps.rate_lp); + break; + } + switch (tps.constellation) { + case CXD2880_DVBT_CONSTELLATION_QPSK: + c->modulation = QPSK; + break; + case CXD2880_DVBT_CONSTELLATION_16QAM: + c->modulation = QAM_16; + break; + case CXD2880_DVBT_CONSTELLATION_64QAM: + c->modulation = QAM_64; + break; + default: + c->modulation = QPSK; + pr_debug("TPSInfo constellation is invalid %d\n", + tps.constellation); + break; + } + } else { + c->hierarchy = HIERARCHY_NONE; + c->code_rate_HP = FEC_NONE; + c->code_rate_LP = FEC_NONE; + c->modulation = QPSK; + pr_debug("TPS info err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (sense) { + case CXD2880_TNRDMD_SPECTRUM_NORMAL: + c->inversion = INVERSION_OFF; + break; + case CXD2880_TNRDMD_SPECTRUM_INV: + c->inversion = INVERSION_ON; + break; + default: + c->inversion = INVERSION_OFF; + pr_debug("spectrum sense is invalid %d\n", sense); + break; + } + } else { + c->inversion = INVERSION_OFF; + pr_debug("spectrum_sense %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); + mutex_unlock(priv->spi_mutex); + if (!ret) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("mon_rf_lvl %d\n", ret); + } + + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = snr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_snr %d\n", ret); + } + + return 0; +} + +static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, + struct dtv_frontend_properties *c) +{ + int ret; + struct cxd2880_priv *priv = NULL; + struct cxd2880_dvbt2_l1pre l1pre; + enum cxd2880_dvbt2_plp_code_rate coderate; + enum cxd2880_dvbt2_plp_constell qam; + enum cxd2880_tnrdmd_spectrum_sense sense; + u16 snr = 0; + int strength = 0; + + if (!fe || !c) { + pr_err("invalid arg.\n"); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (l1pre.fft_mode) { + case CXD2880_DVBT2_M2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case CXD2880_DVBT2_M8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + case CXD2880_DVBT2_M4K: + c->transmission_mode = TRANSMISSION_MODE_4K; + break; + case CXD2880_DVBT2_M1K: + c->transmission_mode = TRANSMISSION_MODE_1K; + break; + case CXD2880_DVBT2_M16K: + c->transmission_mode = TRANSMISSION_MODE_16K; + break; + case CXD2880_DVBT2_M32K: + c->transmission_mode = TRANSMISSION_MODE_32K; + break; + default: + c->transmission_mode = TRANSMISSION_MODE_2K; + pr_debug("L1Pre fft_mode is invalid %d\n", + l1pre.fft_mode); + break; + } + switch (l1pre.gi) { + case CXD2880_DVBT2_G1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case CXD2880_DVBT2_G1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case CXD2880_DVBT2_G1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case CXD2880_DVBT2_G1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + case CXD2880_DVBT2_G1_128: + c->guard_interval = GUARD_INTERVAL_1_128; + break; + case CXD2880_DVBT2_G19_128: + c->guard_interval = GUARD_INTERVAL_19_128; + break; + case CXD2880_DVBT2_G19_256: + c->guard_interval = GUARD_INTERVAL_19_256; + break; + default: + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("L1Pre guard interval is invalid %d\n", + l1pre.gi); + break; + } + } else { + c->transmission_mode = TRANSMISSION_MODE_2K; + c->guard_interval = GUARD_INTERVAL_1_32; + pr_debug("L1Pre err %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &coderate); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (coderate) { + case CXD2880_DVBT2_R1_2: + c->fec_inner = FEC_1_2; + break; + case CXD2880_DVBT2_R3_5: + c->fec_inner = FEC_3_5; + break; + case CXD2880_DVBT2_R2_3: + c->fec_inner = FEC_2_3; + break; + case CXD2880_DVBT2_R3_4: + c->fec_inner = FEC_3_4; + break; + case CXD2880_DVBT2_R4_5: + c->fec_inner = FEC_4_5; + break; + case CXD2880_DVBT2_R5_6: + c->fec_inner = FEC_5_6; + break; + default: + c->fec_inner = FEC_NONE; + pr_debug("CodeRate is invalid %d\n", coderate); + break; + } + } else { + c->fec_inner = FEC_NONE; + pr_debug("CodeRate %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd, + CXD2880_DVBT2_PLP_DATA, + &qam); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (qam) { + case CXD2880_DVBT2_QPSK: + c->modulation = QPSK; + break; + case CXD2880_DVBT2_QAM16: + c->modulation = QAM_16; + break; + case CXD2880_DVBT2_QAM64: + c->modulation = QAM_64; + break; + case CXD2880_DVBT2_QAM256: + c->modulation = QAM_256; + break; + default: + c->modulation = QPSK; + pr_debug("QAM is invalid %d\n", qam); + break; + } + } else { + c->modulation = QPSK; + pr_debug("QAM %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); + mutex_unlock(priv->spi_mutex); + if (!ret) { + switch (sense) { + case CXD2880_TNRDMD_SPECTRUM_NORMAL: + c->inversion = INVERSION_OFF; + break; + case CXD2880_TNRDMD_SPECTRUM_INV: + c->inversion = INVERSION_ON; + break; + default: + c->inversion = INVERSION_OFF; + pr_debug("spectrum sense is invalid %d\n", sense); + break; + } + } else { + c->inversion = INVERSION_OFF; + pr_debug("SpectrumSense %d\n", ret); + } + + mutex_lock(priv->spi_mutex); + ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); + mutex_unlock(priv->spi_mutex); + if (!ret) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = strength; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("mon_rf_lvl %d\n", ret); + } + + ret = cxd2880_read_snr(fe, &snr); + if (!ret) { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = snr; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + pr_debug("read_snr %d\n", ret); + } + + return 0; +} + +static int cxd2880_get_frontend(struct dvb_frontend *fe, + struct dtv_frontend_properties *props) +{ + struct cxd2880_priv *priv = NULL; + int ret; + + if (!fe || !props) { + pr_err("invalid arg."); + return -EINVAL; + } + + priv = fe->demodulator_priv; + + pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2880_get_frontend_t(fe, props); + break; + case SYS_DVBT2: + ret = cxd2880_get_frontend_t2(fe, props); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { + .info = { + .name = "Sony CXD2880", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 1000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_2G_MODULATION | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS, + }, + .delsys = { SYS_DVBT, SYS_DVBT2 }, + + .release = cxd2880_release, + .init = cxd2880_init, + .sleep = cxd2880_sleep, + .tune = cxd2880_tune, + .set_frontend = cxd2880_set_frontend, + .get_frontend = cxd2880_get_frontend, + .read_status = cxd2880_read_status, + .read_ber = cxd2880_read_ber, + .read_signal_strength = cxd2880_read_signal_strength, + .read_snr = cxd2880_read_snr, + .read_ucblocks = cxd2880_read_ucblocks, + .get_frontend_algo = cxd2880_get_frontend_algo, +}; + +struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, + struct cxd2880_config *cfg) +{ + int ret; + enum cxd2880_tnrdmd_chip_id chipid = + CXD2880_TNRDMD_CHIP_ID_UNKNOWN; + static struct cxd2880_priv *priv; + u8 data = 0; + + if (!fe) { + pr_err("invalid arg.\n"); + return NULL; + } + + priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL); + if (!priv) + return NULL; + + priv->spi = cfg->spi; + priv->spi_mutex = cfg->spi_mutex; + priv->spi_device.spi = cfg->spi; + + memcpy(&fe->ops, &cxd2880_dvbt_t2_ops, + sizeof(struct dvb_frontend_ops)); + + ret = cxd2880_spi_device_initialize(&priv->spi_device, + CXD2880_SPI_MODE_0, + 55000000); + if (ret) { + pr_err("spi_device_initialize failed. %d\n", ret); + kfree(priv); + return NULL; + } + + ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, + &priv->spi_device); + if (ret) { + pr_err("spi_device_create_spi failed. %d\n", ret); + kfree(priv); + return NULL; + } + + ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); + if (ret) { + pr_err("io_spi_create failed. %d\n", ret); + kfree(priv); + return NULL; + } + ret = priv->regio.write_reg(&priv->regio, + CXD2880_IO_TGT_SYS, 0x00, 0x00); + if (ret) { + pr_err("set bank to 0x00 failed.\n"); + kfree(priv); + return NULL; + } + ret = priv->regio.read_regs(&priv->regio, + CXD2880_IO_TGT_SYS, 0xfd, &data, 1); + if (ret) { + pr_err("read chip id failed.\n"); + kfree(priv); + return NULL; + } + + chipid = (enum cxd2880_tnrdmd_chip_id)data; + if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X && + chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) { + pr_err("chip id invalid.\n"); + kfree(priv); + return NULL; + } + + fe->demodulator_priv = priv; + pr_info("CXD2880 driver version: Ver %s\n", + CXD2880_TNRDMD_DRIVER_VERSION); + + return fe; +} +EXPORT_SYMBOL(cxd2880_attach); + +MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver"); +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation"); +MODULE_LICENSE("GPL v2"); -- cgit From 90dc9aa75bbb2d0f8bb6178adf4de709e8463a3e Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:53:23 -0500 Subject: media: cxd2880: Add DVB-T control functions the driver Provide definitions, interfaces and functions needed for DVB-T of the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h | 74 ++ .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c | 919 +++++++++++++++++++++ .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h | 45 + 3 files changed, 1038 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h new file mode 100644 index 000000000000..76a1acc346ef --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dvbt.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DVBT_H +#define CXD2880_DVBT_H + +#include "cxd2880_common.h" + +enum cxd2880_dvbt_constellation { + CXD2880_DVBT_CONSTELLATION_QPSK, + CXD2880_DVBT_CONSTELLATION_16QAM, + CXD2880_DVBT_CONSTELLATION_64QAM, + CXD2880_DVBT_CONSTELLATION_RESERVED_3 +}; + +enum cxd2880_dvbt_hierarchy { + CXD2880_DVBT_HIERARCHY_NON, + CXD2880_DVBT_HIERARCHY_1, + CXD2880_DVBT_HIERARCHY_2, + CXD2880_DVBT_HIERARCHY_4 +}; + +enum cxd2880_dvbt_coderate { + CXD2880_DVBT_CODERATE_1_2, + CXD2880_DVBT_CODERATE_2_3, + CXD2880_DVBT_CODERATE_3_4, + CXD2880_DVBT_CODERATE_5_6, + CXD2880_DVBT_CODERATE_7_8, + CXD2880_DVBT_CODERATE_RESERVED_5, + CXD2880_DVBT_CODERATE_RESERVED_6, + CXD2880_DVBT_CODERATE_RESERVED_7 +}; + +enum cxd2880_dvbt_guard { + CXD2880_DVBT_GUARD_1_32, + CXD2880_DVBT_GUARD_1_16, + CXD2880_DVBT_GUARD_1_8, + CXD2880_DVBT_GUARD_1_4 +}; + +enum cxd2880_dvbt_mode { + CXD2880_DVBT_MODE_2K, + CXD2880_DVBT_MODE_8K, + CXD2880_DVBT_MODE_RESERVED_2, + CXD2880_DVBT_MODE_RESERVED_3 +}; + +enum cxd2880_dvbt_profile { + CXD2880_DVBT_PROFILE_HP = 0, + CXD2880_DVBT_PROFILE_LP +}; + +struct cxd2880_dvbt_tpsinfo { + enum cxd2880_dvbt_constellation constellation; + enum cxd2880_dvbt_hierarchy hierarchy; + enum cxd2880_dvbt_coderate rate_hp; + enum cxd2880_dvbt_coderate rate_lp; + enum cxd2880_dvbt_guard guard; + enum cxd2880_dvbt_mode mode; + u8 fnum; + u8 length_indicator; + u16 cell_id; + u8 cell_id_ok; + u8 reserved_even; + u8 reserved_odd; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c new file mode 100644 index 000000000000..e1ad5187ad8f --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -0,0 +1,919 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control functions for DVB-T + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "dvb_frontend.h" + +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" + +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x01}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03}, + {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = { + {0x00, 0x12}, {0x44, 0x00}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = { + {0x00, 0x11}, {0x87, 0xd2}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = { + {0x00, 0x00}, {0xfd, 0x01}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = { + {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00}, +}; + +static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = { + {0x00, 0x11}, {0x87, 0x04}, +}; + +static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) +{ + static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 }; + static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 }; + static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 }; + static const u8 ratectl_margin[2] = { 0x01, 0xf0 }; + static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 }; + static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa }; + static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 }; + + static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa}; + static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 }; + static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 }; + static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 }; + static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 }; + static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 }; + static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 }; + static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 }; + + static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55}; + static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c }; + static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 }; + static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 }; + static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 }; + static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa }; + static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 }; + + static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00}; + static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38}; + static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 }; + static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 }; + static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c }; + static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 }; + static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 }; + static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff }; + static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 }; + + static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99}; + static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa}; + static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d }; + static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 }; + static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 }; + static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 }; + static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 }; + static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc }; + static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 }; + const u8 *data = NULL; + u8 sst_data; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_ckffrq_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_ckffrq_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_ckffrq_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x65, data, 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5d, 0x07); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + u8 data[2] = { 0x01, 0x01 }; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, data, 2); + if (ret) + return ret; + } + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, ratectl_margin, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN || + tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq3, + ARRAY_SIZE(tune_dmd_setting_seq3)); + if (ret) + return ret; + } + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq4, + ARRAY_SIZE(tune_dmd_setting_seq4)); + if (ret) + return ret; + } + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = maxclkcnt_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = maxclkcnt_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = maxclkcnt_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x68, data, 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + switch (bandwidth) { + case CXD2880_DTV_BW_8_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x35; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x34; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw8_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw8_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_7_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2f; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x2e; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw7_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw7_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_6_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x29; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x2a; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw6_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw6_notch[2], 2); + if (ret) + return ret; + break; + + case CXD2880_DTV_BW_5_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, data, 5); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_gtdofst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_gtdofst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x7d, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_B: + sst_data = 0x24; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + sst_data = 0x23; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x71, sst_data); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, &data[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x51, &data[2], 3); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x72, &bw5_notch[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x6b, &bw5_notch[2], 2); + if (ret) + return ret; + break; + + default: + return -EINVAL; + } + + return cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq5, + ARRAY_SIZE(tune_dmd_setting_seq5)); +} + +static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq1, + ARRAY_SIZE(sleep_dmd_setting_seq1)); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + sleep_dmd_setting_seq2, + ARRAY_SIZE(sleep_dmd_setting_seq2)); + + return ret; +} + +static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt_profile profile) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x10); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x67, + (profile == CXD2880_DVBT_PROFILE_HP) + ? 0x00 : 0x01); +} + +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT, + tune_param->center_freq_khz, + tune_param->bandwidth, 0, 0); + if (ret) + return ret; + + ret = + x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth, + tnr_dmd->clk_mode); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune_dvbt_demod_setting(tnr_dmd->diver_sub, + tune_param->bandwidth, + tnr_dmd->diver_sub->clk_mode); + if (ret) + return ret; + } + + return dvbt_set_profile(tnr_dmd, tune_param->profile); +} + +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT, + 0); + if (ret) + return ret; + + tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->sys = CXD2880_DTV_SYS_DVBT; + tnr_dmd->bandwidth = tune_param->bandwidth; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT; + tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_sleep_dvbt_demod_setting(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (sync_stat == 6) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (ts_lock) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (ts_lock) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } else if (!unlock_detected) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h new file mode 100644 index 000000000000..35d81ccc732b --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control interface for DVB-T + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT_H +#define CXD2880_TNRDMD_DVBT_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +struct cxd2880_dvbt_tune_param { + u32 center_freq_khz; + enum cxd2880_dtv_bandwidth bandwidth; + enum cxd2880_dvbt_profile profile; +}; + +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +#endif -- cgit From cc438de9df2ce812da5c5b900f7262ea2938535d Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:54:33 -0500 Subject: media: cxd2880: Add DVB-T monitor functions Provide monitor functions (DVB-T) for the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c | 775 +++++++++++++++++++++ .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h | 77 ++ 2 files changed, 852 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c new file mode 100644 index 000000000000..78214a99a5df --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt.h" +#include "cxd2880_tnrdmd_dvbt_mon.h" + +#include "dvb_math.h" + +static const int ref_dbm_1000[3][5] = { + {-93000, -91000, -90000, -89000, -88000}, + {-87000, -85000, -84000, -83000, -82000}, + {-82000, -80000, -78000, -77000, -76000}, +}; + +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) +{ + u8 rdata = 0x00; + int ret; + + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &rdata, 1); + if (ret) + return ret; + + *unlock_detected = (rdata & 0x10) ? 1 : 0; + *sync_stat = rdata & 0x07; + *ts_lock_stat = (rdata & 0x20) ? 1 : 0; + + if (*sync_stat == 0x07) + return -EAGAIN; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected) +{ + u8 ts_lock_stat = 0; + + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); +} + +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard) +{ + u8 rdata = 0x00; + int ret; + + if (!tnr_dmd || !mode || !guard) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub, + mode, guard); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, &rdata, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03); + *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) +{ + u8 rdata[4]; + u32 ctl_val = 0; + int ret; + + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, rdata, 4); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ctl_val = + ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) | + (rdata[3]); + *offset = cxd2880_convert2s_complement(ctl_val, 29); + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235); + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) +{ + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, + offset); +} + +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info) +{ + u8 rdata[7]; + u8 cell_id_ok = 0; + int ret; + + if (!tnr_dmd || !info) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub, + info); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, rdata, 7); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x11); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xd5, &cell_id_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + info->constellation = + (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03); + info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07); + info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07); + info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07); + info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03); + info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03); + info->fnum = (rdata[2] >> 6) & 0x03; + info->length_indicator = rdata[2] & 0x3f; + info->cell_id = (rdata[3] << 8) | rdata[4]; + info->reserved_even = rdata[5] & 0x3f; + info->reserved_odd = rdata[6] & 0x3f; + + info->cell_id_ok = cell_id_ok & 0x01; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) +{ + u8 rdata[3]; + int ret; + + if (!tnr_dmd || !pen) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, rdata, 3); + if (ret) + return ret; + + if (!(rdata[0] & 0x01)) + return -EAGAIN; + + *pen = (rdata[1] << 8) | rdata[2]; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) +{ + u8 data = 0; + int ret; + + if (!tnr_dmd || !sense) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1c, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *sense = + (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : + CXD2880_TNRDMD_SPECTRUM_NORMAL; + + return ret; +} + +static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) +{ + u8 rdata[2]; + int ret; + + if (!tnr_dmd || !reg_value) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, rdata, 2); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *reg_value = (rdata[0] << 8) | rdata[1]; + + return ret; +} + +static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) +{ + if (!tnr_dmd || !snr) + return -EINVAL; + + if (reg_value == 0) + return -EAGAIN; + + if (reg_value > 4996) + reg_value = 4996; + + *snr = intlog10(reg_value) - intlog10(5350 - reg_value); + *snr = (*snr + 839) / 1678 + 28500; + + return 0; +} + +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) +{ + u16 reg_value = 0; + int ret; + + if (!tnr_dmd || !snr) + return -EINVAL; + + *snr = -1000 * 1000; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + ret = dvbt_read_snr_reg(tnr_dmd, ®_value); + if (ret) + return ret; + + ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); + } else { + int snr_main = 0; + int snr_sub = 0; + + ret = + cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main, + &snr_sub); + } + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) +{ + u16 reg_value = 0; + u32 reg_value_sum = 0; + int ret; + + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; + + *snr = -1000 * 1000; + *snr_main = -1000 * 1000; + *snr_sub = -1000 * 1000; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = dvbt_read_snr_reg(tnr_dmd, ®_value); + if (!ret) { + ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); + if (!ret) { + ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); +} + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + s8 diff_upper = 0; + int ret; + + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = is_tps_locked(tnr_dmd); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0d); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x21, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x60, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); + else + num = (int)(trl_ctl_val - trcg_nominal_rate); + + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; + + den >>= 1; + + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); +} + +static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) +{ + struct cxd2880_dvbt_tpsinfo tps; + int prel; + int temp_ssi = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); + if (ret) + return ret; + + if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 || + tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) + return -EINVAL; + + prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp]; + + if (prel < -15000) + temp_ssi = 0; + else if (prel < 0) + temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; + else if (prel < 20000) + temp_ssi = (((4 * prel) + 500) / 1000) + 10; + else if (prel < 35000) + temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; + else + temp_ssi = 100; + + *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; + + return ret; +} + +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); + if (ret) + return ret; + + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); + if (ret) + return ret; + + return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) +{ + u8 sync = 0; + u8 tslock = 0; + u8 early_unlock = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, + &early_unlock); + if (ret) + return ret; + + if (sync != 6) + return -EAGAIN; + + return 0; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h new file mode 100644 index 000000000000..f4c31725fa48 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT_MON_H +#define CXD2880_TNRDMD_DVBT_MON_H + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_dvbt.h" + +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt_mode + *mode, + enum cxd2880_dvbt_guard + *guard); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt_tpsinfo + *info); + +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen); + +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); + +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); + +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub); + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); + +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); + +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +#endif -- cgit From 9e049346f672bbbe14241e8ec12d4048b38b8f22 Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:55:32 -0500 Subject: media: cxd2880: Add DVB-T2 control functions for the driver Provide definitions, interfaces and functions needed for DVB-T2 of the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h | 385 +++++++ .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c | 1217 ++++++++++++++++++++ .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h | 65 ++ 3 files changed, 1667 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h new file mode 100644 index 000000000000..191047b158fe --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h @@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_dvbt2.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 related definitions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_DVBT2_H +#define CXD2880_DVBT2_H + +#include "cxd2880_common.h" + +enum cxd2880_dvbt2_profile { + CXD2880_DVBT2_PROFILE_BASE, + CXD2880_DVBT2_PROFILE_LITE, + CXD2880_DVBT2_PROFILE_ANY +}; + +enum cxd2880_dvbt2_version { + CXD2880_DVBT2_V111, + CXD2880_DVBT2_V121, + CXD2880_DVBT2_V131 +}; + +enum cxd2880_dvbt2_s1 { + CXD2880_DVBT2_S1_BASE_SISO = 0x00, + CXD2880_DVBT2_S1_BASE_MISO = 0x01, + CXD2880_DVBT2_S1_NON_DVBT2 = 0x02, + CXD2880_DVBT2_S1_LITE_SISO = 0x03, + CXD2880_DVBT2_S1_LITE_MISO = 0x04, + CXD2880_DVBT2_S1_RSVD3 = 0x05, + CXD2880_DVBT2_S1_RSVD4 = 0x06, + CXD2880_DVBT2_S1_RSVD5 = 0x07, + CXD2880_DVBT2_S1_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_base_s2 { + CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00, + CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01, + CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02, + CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03, + CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04, + CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05, + CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06, + CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07, + CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_lite_s2 { + CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00, + CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01, + CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02, + CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03, + CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04, + CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05, + CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06, + CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07, + CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_guard { + CXD2880_DVBT2_G1_32 = 0x00, + CXD2880_DVBT2_G1_16 = 0x01, + CXD2880_DVBT2_G1_8 = 0x02, + CXD2880_DVBT2_G1_4 = 0x03, + CXD2880_DVBT2_G1_128 = 0x04, + CXD2880_DVBT2_G19_128 = 0x05, + CXD2880_DVBT2_G19_256 = 0x06, + CXD2880_DVBT2_G_RSVD1 = 0x07, + CXD2880_DVBT2_G_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_mode { + CXD2880_DVBT2_M2K = 0x00, + CXD2880_DVBT2_M8K = 0x01, + CXD2880_DVBT2_M4K = 0x02, + CXD2880_DVBT2_M1K = 0x03, + CXD2880_DVBT2_M16K = 0x04, + CXD2880_DVBT2_M32K = 0x05, + CXD2880_DVBT2_M_RSVD1 = 0x06, + CXD2880_DVBT2_M_RSVD2 = 0x07 +}; + +enum cxd2880_dvbt2_bw { + CXD2880_DVBT2_BW_8 = 0x00, + CXD2880_DVBT2_BW_7 = 0x01, + CXD2880_DVBT2_BW_6 = 0x02, + CXD2880_DVBT2_BW_5 = 0x03, + CXD2880_DVBT2_BW_10 = 0x04, + CXD2880_DVBT2_BW_1_7 = 0x05, + CXD2880_DVBT2_BW_RSVD1 = 0x06, + CXD2880_DVBT2_BW_RSVD2 = 0x07, + CXD2880_DVBT2_BW_RSVD3 = 0x08, + CXD2880_DVBT2_BW_RSVD4 = 0x09, + CXD2880_DVBT2_BW_RSVD5 = 0x0a, + CXD2880_DVBT2_BW_RSVD6 = 0x0b, + CXD2880_DVBT2_BW_RSVD7 = 0x0c, + CXD2880_DVBT2_BW_RSVD8 = 0x0d, + CXD2880_DVBT2_BW_RSVD9 = 0x0e, + CXD2880_DVBT2_BW_RSVD10 = 0x0f, + CXD2880_DVBT2_BW_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1pre_type { + CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00, + CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01, + CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02, + CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03, + CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_papr { + CXD2880_DVBT2_PAPR_0 = 0x00, + CXD2880_DVBT2_PAPR_1 = 0x01, + CXD2880_DVBT2_PAPR_2 = 0x02, + CXD2880_DVBT2_PAPR_3 = 0x03, + CXD2880_DVBT2_PAPR_RSVD1 = 0x04, + CXD2880_DVBT2_PAPR_RSVD2 = 0x05, + CXD2880_DVBT2_PAPR_RSVD3 = 0x06, + CXD2880_DVBT2_PAPR_RSVD4 = 0x07, + CXD2880_DVBT2_PAPR_RSVD5 = 0x08, + CXD2880_DVBT2_PAPR_RSVD6 = 0x09, + CXD2880_DVBT2_PAPR_RSVD7 = 0x0a, + CXD2880_DVBT2_PAPR_RSVD8 = 0x0b, + CXD2880_DVBT2_PAPR_RSVD9 = 0x0c, + CXD2880_DVBT2_PAPR_RSVD10 = 0x0d, + CXD2880_DVBT2_PAPR_RSVD11 = 0x0e, + CXD2880_DVBT2_PAPR_RSVD12 = 0x0f, + CXD2880_DVBT2_PAPR_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_constell { + CXD2880_DVBT2_L1POST_BPSK = 0x00, + CXD2880_DVBT2_L1POST_QPSK = 0x01, + CXD2880_DVBT2_L1POST_QAM16 = 0x02, + CXD2880_DVBT2_L1POST_QAM64 = 0x03, + CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04, + CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05, + CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06, + CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07, + CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08, + CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09, + CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a, + CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b, + CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c, + CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d, + CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e, + CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f, + CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_cr { + CXD2880_DVBT2_L1POST_R1_2 = 0x00, + CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01, + CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02, + CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03, + CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_l1post_fec_type { + CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00, + CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01, + CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02, + CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03, + CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_pp { + CXD2880_DVBT2_PP1 = 0x00, + CXD2880_DVBT2_PP2 = 0x01, + CXD2880_DVBT2_PP3 = 0x02, + CXD2880_DVBT2_PP4 = 0x03, + CXD2880_DVBT2_PP5 = 0x04, + CXD2880_DVBT2_PP6 = 0x05, + CXD2880_DVBT2_PP7 = 0x06, + CXD2880_DVBT2_PP8 = 0x07, + CXD2880_DVBT2_PP_RSVD1 = 0x08, + CXD2880_DVBT2_PP_RSVD2 = 0x09, + CXD2880_DVBT2_PP_RSVD3 = 0x0a, + CXD2880_DVBT2_PP_RSVD4 = 0x0b, + CXD2880_DVBT2_PP_RSVD5 = 0x0c, + CXD2880_DVBT2_PP_RSVD6 = 0x0d, + CXD2880_DVBT2_PP_RSVD7 = 0x0e, + CXD2880_DVBT2_PP_RSVD8 = 0x0f, + CXD2880_DVBT2_PP_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_code_rate { + CXD2880_DVBT2_R1_2 = 0x00, + CXD2880_DVBT2_R3_5 = 0x01, + CXD2880_DVBT2_R2_3 = 0x02, + CXD2880_DVBT2_R3_4 = 0x03, + CXD2880_DVBT2_R4_5 = 0x04, + CXD2880_DVBT2_R5_6 = 0x05, + CXD2880_DVBT2_R1_3 = 0x06, + CXD2880_DVBT2_R2_5 = 0x07, + CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_constell { + CXD2880_DVBT2_QPSK = 0x00, + CXD2880_DVBT2_QAM16 = 0x01, + CXD2880_DVBT2_QAM64 = 0x02, + CXD2880_DVBT2_QAM256 = 0x03, + CXD2880_DVBT2_CON_RSVD1 = 0x04, + CXD2880_DVBT2_CON_RSVD2 = 0x05, + CXD2880_DVBT2_CON_RSVD3 = 0x06, + CXD2880_DVBT2_CON_RSVD4 = 0x07, + CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_type { + CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00, + CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01, + CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02, + CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03, + CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04, + CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05, + CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06, + CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07, + CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_payload { + CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00, + CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01, + CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02, + CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e, + CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f, + CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_fec { + CXD2880_DVBT2_FEC_LDPC_16K = 0x00, + CXD2880_DVBT2_FEC_LDPC_64K = 0x01, + CXD2880_DVBT2_FEC_RSVD1 = 0x02, + CXD2880_DVBT2_FEC_RSVD2 = 0x03, + CXD2880_DVBT2_FEC_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_mode { + CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00, + CXD2880_DVBT2_PLP_MODE_NM = 0x01, + CXD2880_DVBT2_PLP_MODE_HEM = 0x02, + CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03, + CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff +}; + +enum cxd2880_dvbt2_plp_btype { + CXD2880_DVBT2_PLP_COMMON, + CXD2880_DVBT2_PLP_DATA +}; + +enum cxd2880_dvbt2_stream { + CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00, + CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01, + CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02, + CXD2880_DVBT2_STREAM_TRANSPORT = 0x03, + CXD2880_DVBT2_STREAM_UNKNOWN = 0xff +}; + +struct cxd2880_dvbt2_l1pre { + enum cxd2880_dvbt2_l1pre_type type; + u8 bw_ext; + enum cxd2880_dvbt2_s1 s1; + u8 s2; + u8 mixed; + enum cxd2880_dvbt2_mode fft_mode; + u8 l1_rep; + enum cxd2880_dvbt2_guard gi; + enum cxd2880_dvbt2_papr papr; + enum cxd2880_dvbt2_l1post_constell mod; + enum cxd2880_dvbt2_l1post_cr cr; + enum cxd2880_dvbt2_l1post_fec_type fec; + u32 l1_post_size; + u32 l1_post_info_size; + enum cxd2880_dvbt2_pp pp; + u8 tx_id_availability; + u16 cell_id; + u16 network_id; + u16 sys_id; + u8 num_frames; + u16 num_symbols; + u8 regen; + u8 post_ext; + u8 num_rf_freqs; + u8 rf_idx; + enum cxd2880_dvbt2_version t2_version; + u8 l1_post_scrambled; + u8 t2_base_lite; + u32 crc32; +}; + +struct cxd2880_dvbt2_plp { + u8 id; + enum cxd2880_dvbt2_plp_type type; + enum cxd2880_dvbt2_plp_payload payload; + u8 ff; + u8 first_rf_idx; + u8 first_frm_idx; + u8 group_id; + enum cxd2880_dvbt2_plp_constell constell; + enum cxd2880_dvbt2_plp_code_rate plp_cr; + u8 rot; + enum cxd2880_dvbt2_plp_fec fec; + u16 num_blocks_max; + u8 frm_int; + u8 til_len; + u8 til_type; + u8 in_band_a_flag; + u8 in_band_b_flag; + u16 rsvd; + enum cxd2880_dvbt2_plp_mode plp_mode; + u8 static_flag; + u8 static_padding_flag; +}; + +struct cxd2880_dvbt2_l1post { + u16 sub_slices_per_frame; + u8 num_plps; + u8 num_aux; + u8 aux_cfg_rfu; + u8 rf_idx; + u32 freq; + u8 fef_type; + u32 fef_length; + u8 fef_intvl; +}; + +struct cxd2880_dvbt2_ofdm { + u8 mixed; + u8 is_miso; + enum cxd2880_dvbt2_mode mode; + enum cxd2880_dvbt2_guard gi; + enum cxd2880_dvbt2_pp pp; + u8 bw_ext; + enum cxd2880_dvbt2_papr papr; + u16 num_symbols; +}; + +struct cxd2880_dvbt2_bbheader { + enum cxd2880_dvbt2_stream stream_input; + u8 is_single_input_stream; + u8 is_constant_coding_modulation; + u8 issy_indicator; + u8 null_packet_deletion; + u8 ext; + u8 input_stream_identifier; + u16 user_packet_length; + u16 data_field_length; + u8 sync_byte; + u32 issy; + enum cxd2880_dvbt2_plp_mode plp_mode; +}; + +#endif diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c new file mode 100644 index 000000000000..81903102b12f --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -0,0 +1,1217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt2.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control functions for DVB-T2 + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "dvb_frontend.h" + +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" + +static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = { + {0x00, 0x00}, {0x31, 0x02}, +}; + +static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = { + {0x00, 0x04}, {0x5d, 0x0b}, +}; + +static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dtv_bandwidth + bandwidth, + enum cxd2880_tnrdmd_clockmode + clk_mode) +{ + static const u8 tsif_settings[2] = { 0x01, 0x01 }; + static const u8 init_settings[14] = { + 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, + 0x09, 0x9c, 0x0e, 0x4c + }; + static const u8 clk_mode_settings_a1[9] = { + 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c + }; + + static const u8 clk_mode_settings_b1[9] = { + 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d + }; + + static const u8 clk_mode_settings_c1[9] = { + 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e + }; + + static const u8 clk_mode_settings_a2[13] = { + 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49, + 0xcd, 0xcd, 0x1f, 0x5b + }; + + static const u8 clk_mode_settings_b2[13] = { + 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea, + 0xc8, 0xc8, 0x23, 0x91 + }; + + static const u8 clk_mode_settings_c2[13] = { + 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00, + 0xcd, 0xcd, 0x24, 0x95 + }; + + static const u8 clk_mode_settings_a3[5] = { + 0x0b, 0x6a, 0xc9, 0x03, 0x33 + }; + static const u8 clk_mode_settings_b3[5] = { + 0x01, 0x02, 0xe4, 0x03, 0x39 + }; + static const u8 clk_mode_settings_c3[5] = { + 0x01, 0x02, 0xeb, 0x03, 0x3b + }; + + static const u8 gtdofst[2] = { 0x3f, 0xff }; + + static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 }; + static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw8_sst_a[2] = { 0x06, 0x2a }; + static const u8 bw8_sst_b[2] = { 0x06, 0x29 }; + static const u8 bw8_sst_c[2] = { 0x06, 0x28 }; + static const u8 bw8_mrc_a[9] = { + 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x00 + }; + static const u8 bw8_mrc_b[9] = { + 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x55 + }; + static const u8 bw8_mrc_c[9] = { + 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x00 + }; + + static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 }; + static const u8 bw7_sst_a[2] = { 0x06, 0x23 }; + static const u8 bw7_sst_b[2] = { 0x06, 0x22 }; + static const u8 bw7_sst_c[2] = { 0x06, 0x21 }; + static const u8 bw7_mrc_a[9] = { + 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x92 + }; + static const u8 bw7_mrc_b[9] = { + 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa + }; + static const u8 bw7_mrc_c[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + + static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 }; + static const u8 bw6_sst_a[2] = { 0x06, 0x1c }; + static const u8 bw6_sst_b[2] = { 0x06, 0x1b }; + static const u8 bw6_sst_c[2] = { 0x06, 0x1a }; + static const u8 bw6_mrc_a[9] = { + 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00 + }; + static const u8 bw6_mrc_b[9] = { + 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7 + }; + static const u8 bw6_mrc_c[9] = { + 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff + }; + + static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 }; + static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 }; + static const u8 bw5_sst_a[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_b[2] = { 0x06, 0x15 }; + static const u8 bw5_sst_c[2] = { 0x06, 0x14 }; + static const u8 bw5_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66 + }; + static const u8 bw5_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55 + }; + static const u8 bw5_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc + }; + + static const u8 bw1_7_nomi_a[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_c[6] = { + 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03 + }; + static const u8 bw1_7_nomi_b[6] = { + 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03 + }; + static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c }; + static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b }; + static const u8 bw1_7_mrc_a[9] = { + 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f + }; + static const u8 bw1_7_mrc_b[9] = { + 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d + }; + static const u8 bw1_7_mrc_c[9] = { + 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d + }; + + const u8 *data = NULL; + const u8 *data2 = NULL; + const u8 *data3 = NULL; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_SYS, + tune_dmd_setting_seq1, + ARRAY_SIZE(tune_dmd_setting_seq1)); + if (ret) + return ret; + + ret = cxd2880_io_write_multi_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + tune_dmd_setting_seq2, + ARRAY_SIZE(tune_dmd_setting_seq2)); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xce, tsif_settings, 2); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x20); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8a, init_settings[0]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x90, init_settings[1]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xf0, &init_settings[2], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2a); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xdc, init_settings[4]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xde, init_settings[5]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2d); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x73, &init_settings[6], 4); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x8f, &init_settings[10], 4); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = clk_mode_settings_a1; + data2 = clk_mode_settings_a2; + data3 = clk_mode_settings_a3; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = clk_mode_settings_b1; + data2 = clk_mode_settings_b2; + data3 = clk_mode_settings_b3; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = clk_mode_settings_c1; + data2 = clk_mode_settings_c2; + data3 = clk_mode_settings_c3; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, &data[0], 3); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, data[3]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x24, data[4]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x26, data[5]); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x29, &data[6], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2d, data[8]); + if (ret) + return ret; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2e, &data2[0], 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x35, &data2[6], 7); + if (ret) + return ret; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x3c, &data3[0], 2); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x56, &data3[2], 3); + if (ret) + return ret; + + switch (bandwidth) { + case CXD2880_DTV_BW_8_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x00); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_gtdofst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = gtdofst; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, data, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw8_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw8_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw8_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_7_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x02); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_6_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x04); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw6_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw6_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw6_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_5_MHZ: + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_nomi_ac; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x06); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw5_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw5_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw5_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + case CXD2880_DTV_BW_1_7_MHZ: + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_nomi_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_nomi_c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_nomi_b; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, data, 6); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4a, 0x03); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x19, gtdofst, 2); + if (ret) + return ret; + + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_sst_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_sst_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_sst_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1b, data, 2); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + switch (clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + data = bw1_7_mrc_a; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + data = bw1_7_mrc_b; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + data = bw1_7_mrc_c; + break; + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x4b, data, 9); + if (ret) + return ret; + } + break; + + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x00); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xfd, 0x01); +} + +static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + static const u8 difint_clip[] = { + 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32 + }; + int ret = 0; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; + + ret = tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, difint_clip, 12); + } + + return ret; +} + +static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_profile profile) +{ + u8 t2_mode_tune_mode = 0; + u8 seq_not2_dtime = 0; + u8 dtime1 = 0; + u8 dtime2 = 0; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + switch (tnr_dmd->clk_mode) { + case CXD2880_TNRDMD_CLOCKMODE_A: + dtime1 = 0x27; + dtime2 = 0x0c; + break; + case CXD2880_TNRDMD_CLOCKMODE_B: + dtime1 = 0x2c; + dtime2 = 0x0d; + break; + case CXD2880_TNRDMD_CLOCKMODE_C: + dtime1 = 0x2e; + dtime2 = 0x0e; + break; + default: + return -EINVAL; + } + + switch (profile) { + case CXD2880_DVBT2_PROFILE_BASE: + t2_mode_tune_mode = 0x01; + seq_not2_dtime = dtime2; + break; + + case CXD2880_DVBT2_PROFILE_LITE: + t2_mode_tune_mode = 0x05; + seq_not2_dtime = dtime1; + break; + + case CXD2880_DVBT2_PROFILE_ANY: + t2_mode_tune_mode = 0x00; + seq_not2_dtime = dtime1; + break; + + default: + return -EINVAL; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x2e); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, t2_mode_tune_mode); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) + return ret; + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2c, seq_not2_dtime); +} + +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN && + tune_param->profile == CXD2880_DVBT2_PROFILE_ANY) + return -ENOTTY; + + ret = + cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2, + tune_param->center_freq_khz, + tune_param->bandwidth, 0, 0); + if (ret) + return ret; + + ret = + x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth, + tnr_dmd->clk_mode); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub, + tune_param->bandwidth, + tnr_dmd->diver_sub->clk_mode); + if (ret) + return ret; + } + + ret = dvbt2_set_profile(tnr_dmd, tune_param->profile); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile); + if (ret) + return ret; + } + + if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) + ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0); + else + ret = + cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0, + (u8)(tune_param->data_plp_id)); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param) +{ + u8 en_fef_intmtnt_ctrl = 1; + int ret; + + if (!tnr_dmd || !tune_param) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + switch (tune_param->profile) { + case CXD2880_DVBT2_PROFILE_BASE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base; + break; + case CXD2880_DVBT2_PROFILE_LITE: + en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite; + break; + case CXD2880_DVBT2_PROFILE_ANY: + if (tnr_dmd->en_fef_intmtnt_base && + tnr_dmd->en_fef_intmtnt_lite) + en_fef_intmtnt_ctrl = 1; + else + en_fef_intmtnt_ctrl = 0; + break; + default: + return -EINVAL; + } + + ret = + cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, + CXD2880_DTV_SYS_DVBT2, + en_fef_intmtnt_ctrl); + if (ret) + return ret; + + tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2; + tnr_dmd->bandwidth = tune_param->bandwidth; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { + tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE; + tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz; + tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2; + tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = x_sleep_dvbt2_demod_setting(tnr_dmd); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (sync_stat == 6) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (sync_stat == 6) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock) +{ + int ret; + + u8 sync_stat = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 unlock_detected_sub = 0; + + if (!tnr_dmd || !lock) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, + &unlock_detected); + if (ret) + return ret; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + if (ts_lock) + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + else if (unlock_detected) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; + } + + if (ts_lock) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; + return ret; + } else if (!unlock_detected) { + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + return ret; + } + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat, + &unlock_detected_sub); + if (ret) + return ret; + + if (unlock_detected && unlock_detected_sub) + *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; + else + *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id) +{ + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x23); + if (ret) + return ret; + + if (!auto_plp) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xaf, plp_id); + if (ret) + return ret; + } + + return tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xad, auto_plp ? 0x00 : 0x01); +} + +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd) +{ + struct cxd2880_dvbt2_ofdm ofdm; + static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0}; + int ret; + + if (!tnr_dmd) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) + return 0; + + ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); + if (ret) + return ret; + + if (!ofdm.mixed) + return 0; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x1d); + if (ret) + return ret; + + return tnr_dmd->io->write_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x47, data, 12); +} + +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid) +{ + int ret; + + u8 data; + + if (!tnr_dmd || !l1_post_valid) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && + tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) + return ret; + + *l1_post_valid = data & 0x01; + + return ret; +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h new file mode 100644 index 000000000000..7108e3540093 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt2.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * control interface for DVB-T2 + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT2_H +#define CXD2880_TNRDMD_DVBT2_H + +#include "cxd2880_common.h" +#include "cxd2880_tnrdmd.h" + +enum cxd2880_tnrdmd_dvbt2_tune_info { + CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK, + CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID +}; + +struct cxd2880_dvbt2_tune_param { + u32 center_freq_khz; + enum cxd2880_dtv_bandwidth bandwidth; + u16 data_plp_id; + enum cxd2880_dvbt2_profile profile; + enum cxd2880_tnrdmd_dvbt2_tune_info tune_info; +}; + +#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xffff + +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_tune_param + *tune_param); + +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_lock_result + *lock); + +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd + *tnr_dmd, u8 auto_plp, + u8 plp_id); + +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd + *tnr_dmd); + +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *l1_post_valid); + +#endif -- cgit From 55e13167c93896c7cac68d57c27733db6344d9cb Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:57:01 -0500 Subject: media: cxd2880: Add DVB-T2 monitor functions Provide monitor functions (DVB-T2) for the Sony CXD2880 DVB-T2/T tuner + demodulator driver. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c | 1878 ++++++++++++++++++++ .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h | 135 ++ 2 files changed, 2013 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c new file mode 100644 index 000000000000..5296cbbca8bd --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -0,0 +1,1878 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * cxd2880_tnrdmd_dvbt2_mon.c + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 monitor functions + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#include "cxd2880_tnrdmd_mon.h" +#include "cxd2880_tnrdmd_dvbt2.h" +#include "cxd2880_tnrdmd_dvbt2_mon.h" + +#include "dvb_math.h" + +static const int ref_dbm_1000[4][8] = { + {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, + {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000}, + {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000}, + {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000}, +}; + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected) +{ + u8 data; + int ret; + + if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, &data, sizeof(data)); + if (ret) + return ret; + + *sync_stat = data & 0x07; + *ts_lock_stat = ((data & 0x20) ? 1 : 0); + *unlock_detected = ((data & 0x10) ? 1 : 0); + + if (*sync_stat == 0x07) + return -EAGAIN; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected) +{ + u8 ts_lock_stat = 0; + + if (!tnr_dmd || !sync_stat || !unlock_detected) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, + sync_stat, + &ts_lock_stat, + unlock_detected); +} + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset) +{ + u8 data[4]; + u32 ctl_val = 0; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x30, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ctl_val = + ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8) + | (data[3]); + *offset = cxd2880_convert2s_complement(ctl_val, 28); + + switch (tnr_dmd->bandwidth) { + case CXD2880_DTV_BW_1_7_MHZ: + *offset = -1 * ((*offset) / 582); + break; + case CXD2880_DTV_BW_5_MHZ: + case CXD2880_DTV_BW_6_MHZ: + case CXD2880_DTV_BW_7_MHZ: + case CXD2880_DTV_BW_8_MHZ: + *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940); + break; + default: + return -EINVAL; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset) +{ + if (!tnr_dmd || !offset) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, + offset); +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre) +{ + u8 data[37]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 version = 0; + enum cxd2880_dvbt2_profile profile; + int ret; + + if (!tnr_dmd || !l1_pre) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x61, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + slvt_unfreeze_reg(tnr_dmd); + + l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0]; + l1_pre->bw_ext = data[1] & 0x01; + l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07); + l1_pre->s2 = data[3] & 0x0f; + l1_pre->l1_rep = data[4] & 0x01; + l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07); + l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f); + l1_pre->mod = + (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f); + l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03); + l1_pre->fec = + (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03); + l1_pre->l1_post_size = (data[10] & 0x03) << 16; + l1_pre->l1_post_size |= (data[11]) << 8; + l1_pre->l1_post_size |= (data[12]); + l1_pre->l1_post_info_size = (data[13] & 0x03) << 16; + l1_pre->l1_post_info_size |= (data[14]) << 8; + l1_pre->l1_post_info_size |= (data[15]); + l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f); + l1_pre->tx_id_availability = data[17]; + l1_pre->cell_id = (data[18] << 8); + l1_pre->cell_id |= (data[19]); + l1_pre->network_id = (data[20] << 8); + l1_pre->network_id |= (data[21]); + l1_pre->sys_id = (data[22] << 8); + l1_pre->sys_id |= (data[23]); + l1_pre->num_frames = data[24]; + l1_pre->num_symbols = (data[25] & 0x0f) << 8; + l1_pre->num_symbols |= data[26]; + l1_pre->regen = data[27] & 0x07; + l1_pre->post_ext = data[28] & 0x01; + l1_pre->num_rf_freqs = data[29] & 0x07; + l1_pre->rf_idx = data[30] & 0x07; + version = (data[31] & 0x03) << 2; + version |= (data[32] & 0xc0) >> 6; + l1_pre->t2_version = (enum cxd2880_dvbt2_version)version; + l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5; + l1_pre->t2_base_lite = (data[32] & 0x10) >> 4; + l1_pre->crc32 = (data[33] << 24); + l1_pre->crc32 |= (data[34] << 16); + l1_pre->crc32 |= (data[35] << 8); + l1_pre->crc32 |= data[36]; + + if (profile == CXD2880_DVBT2_PROFILE_BASE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_BASE_S2_M1K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M1K; + break; + case CXD2880_DVBT2_BASE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_BASE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_BASE_S2_M16K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT: + case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M32K; + break; + default: + return -EAGAIN; + } + } else if (profile == CXD2880_DVBT2_PROFILE_LITE) { + switch ((l1_pre->s2 >> 1)) { + case CXD2880_DVBT2_LITE_S2_M2K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M2K; + break; + case CXD2880_DVBT2_LITE_S2_M4K_G_ANY: + l1_pre->fft_mode = CXD2880_DVBT2_M4K; + break; + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M8K; + break; + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT: + case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2: + l1_pre->fft_mode = CXD2880_DVBT2_M16K; + break; + default: + return -EAGAIN; + } + } else { + return -EAGAIN; + } + + l1_pre->mixed = l1_pre->s2 & 0x01; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver) +{ + u8 data[2]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 version = 0; + int ret; + + if (!tnr_dmd || !ver) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x80, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + version = ((data[0] & 0x03) << 2); + version |= ((data[1] & 0xc0) >> 6); + *ver = (enum cxd2880_dvbt2_version)version; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm) +{ + u8 data[5]; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !ofdm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + + ret = -EAGAIN; + + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub, + ofdm); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x1d, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + ofdm->mixed = ((data[0] & 0x20) ? 1 : 0); + ofdm->is_miso = ((data[0] & 0x10) >> 4); + ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07); + ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4); + ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07); + ofdm->bw_ext = (data[2] & 0x10) >> 4; + ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f); + ofdm->num_symbols = (data[3] << 8) | data[4]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps) +{ + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !num_plps) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc1, num_plps, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (*num_plps == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EINVAL; + } + + if (!plp_ids) { + slvt_unfreeze_reg(tnr_dmd); + return 0; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc2, + plp_ids, + ((*num_plps > 62) ? + 62 : *num_plps)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (*num_plps > 62) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0c); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, plp_ids + 62, + *num_plps - 62); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info) +{ + u8 data[20]; + u8 addr = 0; + u8 index = 0; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !plp_info) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!l1_post_ok) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa9; + else + addr = 0x96; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + if (type == CXD2880_DVBT2_PLP_COMMON && !data[13]) + return -EAGAIN; + + plp_info->id = data[index++]; + plp_info->type = + (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07); + plp_info->payload = + (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f); + plp_info->ff = data[index++] & 0x01; + plp_info->first_rf_idx = data[index++] & 0x07; + plp_info->first_frm_idx = data[index++]; + plp_info->group_id = data[index++]; + plp_info->plp_cr = + (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07); + plp_info->constell = + (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07); + plp_info->rot = data[index++] & 0x01; + plp_info->fec = + (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03); + plp_info->num_blocks_max = (data[index++] & 0x03) << 8; + plp_info->num_blocks_max |= data[index++]; + plp_info->frm_int = data[index++]; + plp_info->til_len = data[index++]; + plp_info->til_type = data[index++] & 0x01; + + plp_info->in_band_a_flag = data[index++] & 0x01; + plp_info->rsvd = data[index++] << 8; + plp_info->rsvd |= data[index++]; + + plp_info->in_band_b_flag = + (plp_info->rsvd & 0x8000) >> 15; + plp_info->plp_mode = + (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2); + plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1; + plp_info->static_padding_flag = plp_info->rsvd & 0x0001; + plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error) +{ + u8 data; + int ret; + + if (!tnr_dmd || !plp_error) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if ((data & 0x01) == 0x00) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xc0, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *plp_error = data & 0x01; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change) +{ + u8 data; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + int ret; + + if (!tnr_dmd || !l1_change) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) { + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub + (tnr_dmd, &sync_state, &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state < 5) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } else { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x5f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + *l1_change = data & 0x01; + if (*l1_change) { + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x22); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x16, 0x01); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + slvt_unfreeze_reg(tnr_dmd); + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post) +{ + u8 data[16]; + int ret; + + if (!tnr_dmd || !l1_post) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, data, sizeof(data)); + if (ret) + return ret; + + if (!(data[0] & 0x01)) + return -EAGAIN; + + l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8; + l1_post->sub_slices_per_frame |= data[2]; + l1_post->num_plps = data[3]; + l1_post->num_aux = data[4] & 0x0f; + l1_post->aux_cfg_rfu = data[5]; + l1_post->rf_idx = data[6] & 0x07; + l1_post->freq = data[7] << 24; + l1_post->freq |= data[8] << 16; + l1_post->freq |= data[9] << 8; + l1_post->freq |= data[10]; + l1_post->fef_type = data[11] & 0x0f; + l1_post->fef_length = data[12] << 16; + l1_post->fef_length |= data[13] << 8; + l1_post->fef_length |= data[14]; + l1_post->fef_intvl = data[15]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 data[14]; + u8 addr = 0; + int ret; + + if (!tnr_dmd || !bbheader) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!ts_lock) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + u8 l1_post_ok; + u8 data; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0x51; + else + addr = 0x42; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + bbheader->stream_input = + (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); + bbheader->is_single_input_stream = (data[0] >> 5) & 0x01; + bbheader->is_constant_coding_modulation = + (data[0] >> 4) & 0x01; + bbheader->issy_indicator = (data[0] >> 3) & 0x01; + bbheader->null_packet_deletion = (data[0] >> 2) & 0x01; + bbheader->ext = data[0] & 0x03; + + bbheader->input_stream_identifier = data[1]; + bbheader->plp_mode = + (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM : + CXD2880_DVBT2_PLP_MODE_NM; + bbheader->data_field_length = (data[4] << 8) | data[5]; + + if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { + bbheader->user_packet_length = + (data[6] << 8) | data[7]; + bbheader->sync_byte = data[8]; + bbheader->issy = 0; + } else { + bbheader->user_packet_length = 0; + bbheader->sync_byte = 0; + bbheader->issy = + (data[11] << 16) | (data[12] << 8) | data[13]; + } + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 l1_post_ok = 0; + u8 data[4]; + u8 addr = 0; + + int ret; + + if (!tnr_dmd || !ts_rate_bps) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!ts_lock) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xba; + else + addr = 0xa7; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if ((data[0] & 0x80) == 0x00) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x25); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) + addr = 0xa6; + else + addr = 0xaa; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + addr, &data[0], 4); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) | + (data[2] << 8) | data[3]; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 early_unlock = 0; + u8 data = 0; + int ret; + + if (!tnr_dmd || !sense) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, + &early_unlock); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + + ret = -EAGAIN; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub, + sense); + + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x2f, &data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *sense = + (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : + CXD2880_TNRDMD_SPECTRUM_NORMAL; + + return 0; +} + +static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, + u16 *reg_value) +{ + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + u8 data[2]; + int ret; + + if (!tnr_dmd || !reg_value) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x13, data, sizeof(data)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + *reg_value = (data[0] << 8) | data[1]; + + return ret; +} + +static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, + u32 reg_value, int *snr) +{ + if (!tnr_dmd || !snr) + return -EINVAL; + + if (reg_value == 0) + return -EAGAIN; + + if (reg_value > 10876) + reg_value = 10876; + + *snr = intlog10(reg_value) - intlog10(12600 - reg_value); + *snr = (*snr + 839) / 1678 + 32000; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr) +{ + u16 reg_value = 0; + int ret; + + if (!tnr_dmd || !snr) + return -EINVAL; + + *snr = -1000 * 1000; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (ret) + return ret; + + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); + } else { + int snr_main = 0; + int snr_sub = 0; + + ret = + cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main, + &snr_sub); + } + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, int *snr_sub) +{ + u16 reg_value = 0; + u32 reg_value_sum = 0; + int ret; + + if (!tnr_dmd || !snr || !snr_main || !snr_sub) + return -EINVAL; + + *snr = -1000 * 1000; + *snr_main = -1000 * 1000; + *snr_sub = -1000 * 1000; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); + if (!ret) { + ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); + if (ret) + reg_value = 0; + } else if (ret == -EAGAIN) { + reg_value = 0; + } else { + return ret; + } + + reg_value_sum += reg_value; + + return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); +} + +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen) +{ + int ret; + u8 data[3]; + + if (!tnr_dmd || !pen) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x39, data, sizeof(data)); + if (ret) + return ret; + + if (!(data[0] & 0x01)) + return -EAGAIN; + + *pen = ((data[1] << 8) | data[2]); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm) +{ + u8 ctl_val_reg[5]; + u8 nominal_rate_reg[5]; + u32 trl_ctl_val = 0; + u32 trcg_nominal_rate = 0; + int num; + int den; + int ret; + u8 sync_state = 0; + u8 ts_lock = 0; + u8 unlock_detected = 0; + s8 diff_upper = 0; + + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, + &ts_lock, + &unlock_detected); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (sync_state != 6) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x34, ctl_val_reg, + sizeof(ctl_val_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x04); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x10, nominal_rate_reg, + sizeof(nominal_rate_reg)); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + slvt_unfreeze_reg(tnr_dmd); + + diff_upper = + (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f); + + if (diff_upper < -1 || diff_upper > 1) + return -EAGAIN; + + trl_ctl_val = ctl_val_reg[1] << 24; + trl_ctl_val |= ctl_val_reg[2] << 16; + trl_ctl_val |= ctl_val_reg[3] << 8; + trl_ctl_val |= ctl_val_reg[4]; + + trcg_nominal_rate = nominal_rate_reg[1] << 24; + trcg_nominal_rate |= nominal_rate_reg[2] << 16; + trcg_nominal_rate |= nominal_rate_reg[3] << 8; + trcg_nominal_rate |= nominal_rate_reg[4]; + + trl_ctl_val >>= 1; + trcg_nominal_rate >>= 1; + + if (diff_upper == 1) + num = + (int)((trl_ctl_val + 0x80000000u) - + trcg_nominal_rate); + else if (diff_upper == -1) + num = + -(int)((trcg_nominal_rate + 0x80000000u) - + trl_ctl_val); + else + num = (int)(trl_ctl_val - trcg_nominal_rate); + + den = (nominal_rate_reg[0] & 0x7f) << 24; + den |= nominal_rate_reg[1] << 16; + den |= nominal_rate_reg[2] << 8; + den |= nominal_rate_reg[3]; + den = (den + (390625 / 2)) / 390625; + + den >>= 1; + + if (num >= 0) + *ppm = (num + (den / 2)) / den; + else + *ppm = (num - (den / 2)) / den; + + return 0; +} + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm) +{ + if (!tnr_dmd || !ppm) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, + ppm); +} + +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell *qam) +{ + u8 data; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !qam) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb1, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } else { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9e, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate) +{ + u8 data; + u8 l1_post_ok = 0; + int ret; + + if (!tnr_dmd || !code_rate) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = slvt_freeze_reg(tnr_dmd); + if (ret) + return ret; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x86, &l1_post_ok, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (!(l1_post_ok & 0x01)) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + if (type == CXD2880_DVBT2_PLP_COMMON) { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb6, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + + if (data == 0) { + slvt_unfreeze_reg(tnr_dmd); + return -EAGAIN; + } + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0xb0, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } else { + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x9d, &data, 1); + if (ret) { + slvt_unfreeze_reg(tnr_dmd); + return ret; + } + } + + slvt_unfreeze_reg(tnr_dmd); + + *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07); + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile) +{ + u8 data; + int ret; + + if (!tnr_dmd || !profile) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = tnr_dmd->io->write_reg(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x00, 0x0b); + if (ret) + return ret; + + ret = tnr_dmd->io->read_regs(tnr_dmd->io, + CXD2880_IO_TGT_DMD, + 0x22, &data, sizeof(data)); + if (ret) + return ret; + + if (data & 0x02) { + if (data & 0x01) + *profile = CXD2880_DVBT2_PROFILE_LITE; + else + *profile = CXD2880_DVBT2_PROFILE_BASE; + } else { + ret = -EAGAIN; + if (tnr_dmd->diver_mode == + CXD2880_TNRDMD_DIVERMODE_MAIN) + ret = + cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub, + profile); + + return ret; + } + + return 0; +} + +static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, + int rf_lvl, u8 *ssi) +{ + enum cxd2880_dvbt2_plp_constell qam; + enum cxd2880_dvbt2_plp_code_rate code_rate; + int prel; + int temp_ssi = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + ret = + cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); + if (ret) + return ret; + + ret = + cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, + &code_rate); + if (ret) + return ret; + + if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256) + return -EINVAL; + + prel = rf_lvl - ref_dbm_1000[qam][code_rate]; + + if (prel < -15000) + temp_ssi = 0; + else if (prel < 0) + temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000; + else if (prel < 20000) + temp_ssi = (((4 * prel) + 500) / 1000) + 10; + else if (prel < 35000) + temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90; + else + temp_ssi = 100; + + *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi; + + return ret; +} + +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); + if (ret) + return ret; + + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); +} + +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi) +{ + int rf_lvl = 0; + int ret; + + if (!tnr_dmd || !ssi) + return -EINVAL; + + if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) + return -EINVAL; + + if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) + return -EINVAL; + + if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) + return -EINVAL; + + ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); + if (ret) + return ret; + + return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi); +} diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h new file mode 100644 index 000000000000..5b7adaceff22 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cxd2880_tnrdmd_dvbt2_mon.h + * Sony CXD2880 DVB-T2/T tuner + demodulator driver + * DVB-T2 monitor interface + * + * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation + */ + +#ifndef CXD2880_TNRDMD_DVBT2_MON_H +#define CXD2880_TNRDMD_DVBT2_MON_H + +#include "cxd2880_tnrdmd.h" +#include "cxd2880_dvbt2.h" + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd + *tnr_dmd, u8 *sync_stat, + u8 *ts_lock_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *sync_stat, + u8 *unlock_detected); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *offset); + +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_l1pre + *l1_pre); + +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_version + *ver); + +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, + struct cxd2880_dvbt2_ofdm *ofdm); + +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd + *tnr_dmd, u8 *plp_ids, + u8 *num_plps); + +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_plp + *plp_info); + +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd + *tnr_dmd, + u8 *plp_error); + +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd + *tnr_dmd, u8 *l1_change); + +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd + *tnr_dmd, + struct cxd2880_dvbt2_l1post + *l1_post); + +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + struct cxd2880_dvbt2_bbheader + *bbheader); + +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_dvbt2_plp_btype + type, + u32 *ts_rate_bps); + +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd + *tnr_dmd, + enum + cxd2880_tnrdmd_spectrum_sense + *sense); + +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, + int *snr); + +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd + *tnr_dmd, int *snr, + int *snr_main, + int *snr_sub); + +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct + cxd2880_tnrdmd + *tnr_dmd, + u32 *pen); + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd + *tnr_dmd, int *ppm); + +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct + cxd2880_tnrdmd + *tnr_dmd, + int *ppm); + +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, + enum cxd2880_dvbt2_plp_btype type, + enum cxd2880_dvbt2_plp_constell + *qam); + +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_plp_btype + type, + enum + cxd2880_dvbt2_plp_code_rate + *code_rate); + +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd + *tnr_dmd, + enum cxd2880_dvbt2_profile + *profile); + +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, + u8 *ssi); + +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd + *tnr_dmd, u8 *ssi); + +#endif -- cgit From 7cbc3013f60dbc22955645443855c8f092d3c534 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 05:02:37 -0500 Subject: media: cxd2880: Fix location of DVB headers Fix a trivial conflict, where the location of DVB headers got moved. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c | 2 +- drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 4 ++-- drivers/media/spi/cxd2880-spi.c | 6 +++--- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c index b9ef134aed79..25851bbb846e 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -7,7 +7,7 @@ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ -#include "dvb_frontend.h" +#include #include "cxd2880_common.h" #include "cxd2880_tnrdmd.h" #include "cxd2880_tnrdmd_mon.h" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c index e1ad5187ad8f..fe3c6f8b1b3e 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -7,7 +7,7 @@ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ -#include "dvb_frontend.h" +#include #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c index 81903102b12f..dd32004a12d8 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -7,7 +7,7 @@ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation */ -#include "dvb_frontend.h" +#include #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c index 5296cbbca8bd..604580bf7cf7 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" -#include "dvb_math.h" +#include static const int ref_dbm_1000[4][8] = { {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c index 78214a99a5df..fedc3b4a2fa0 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -#include "dvb_math.h" +#include static const int ref_dbm_1000[3][5] = { {-93000, -91000, -90000, -89000, -88000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c index f109e9d98cc0..05360a11bea9 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -10,8 +10,8 @@ #include -#include "dvb_frontend.h" -#include "dvb_math.h" +#include +#include #include "cxd2880.h" #include "cxd2880_tnrdmd_mon.h" diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index 857e4c0d7a92..4df3bd312f48 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -12,9 +12,9 @@ #include #include -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_frontend.h" +#include +#include +#include #include "cxd2880.h" #define CXD2880_MAX_FILTER_SIZE 32 -- cgit From 9dbaad428d692815f01cda36dc6ae8ae0a4e8bf4 Mon Sep 17 00:00:00 2001 From: Yasunari Takiguchi Date: Thu, 18 Jan 2018 03:59:42 -0500 Subject: media: cxd2880: Add all Makefile, Kconfig files and Update MAINTAINERS file for the driver This is the Makefile, Kconfig files of driver and MAINTAINERS file update about the driver for the Sony CXD2880 DVB-T2/T tuner + demodulator. Signed-off-by: Yasunari Takiguchi Signed-off-by: Masayuki Yamamoto Signed-off-by: Hideki Nozawa Signed-off-by: Kota Yonezawa Signed-off-by: Toshihiko Matsumoto Signed-off-by: Satoshi Watanabe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 ++ drivers/media/dvb-frontends/Makefile | 1 + drivers/media/dvb-frontends/cxd2880/Kconfig | 8 ++++++++ drivers/media/dvb-frontends/cxd2880/Makefile | 19 +++++++++++++++++++ drivers/media/spi/Kconfig | 14 ++++++++++++++ drivers/media/spi/Makefile | 5 +++++ 6 files changed, 49 insertions(+) create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index ca8c7ed079dd..2ad81907c714 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -546,6 +546,8 @@ config DVB_GP8PSK_FE depends on DVB_CORE default DVB_USB_GP8PSK +source "drivers/media/dvb-frontends/cxd2880/Kconfig" + comment "DVB-C (cable) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index abbd76ede540..67a783fd5ed0 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o obj-$(CONFIG_DVB_HELENE) += helene.o obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o obj-$(CONFIG_DVB_CXD2099) += cxd2099.o +obj-$(CONFIG_DVB_CXD2880) += cxd2880/ diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig new file mode 100644 index 000000000000..9d989676e800 --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +config DVB_CXD2880 + tristate "Sony CXD2880 DVB-T2/T tuner + demodulator" + depends on DVB_CORE && SPI + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Say Y when you want to support this frontend. \ No newline at end of file diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile new file mode 100644 index 000000000000..65a5d37f28cc --- /dev/null +++ b/drivers/media/dvb-frontends/cxd2880/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +cxd2880-objs := cxd2880_common.o \ + cxd2880_devio_spi.o \ + cxd2880_integ.o \ + cxd2880_io.o \ + cxd2880_spi_device.o \ + cxd2880_tnrdmd.o \ + cxd2880_tnrdmd_dvbt2.o \ + cxd2880_tnrdmd_dvbt2_mon.o \ + cxd2880_tnrdmd_dvbt.o \ + cxd2880_tnrdmd_dvbt_mon.o\ + cxd2880_tnrdmd_mon.o\ + cxd2880_top.o + +obj-$(CONFIG_DVB_CXD2880) += cxd2880.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index a21f5a39a440..b07ac86fc53c 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -12,3 +12,17 @@ config VIDEO_GS1662 endmenu endif + +if SPI +menu "Media SPI Adapters" + +config CXD2880_SPI_DRV + tristate "Sony CXD2880 SPI support" + depends on DVB_CORE && SPI + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Choose if you would like to have SPI interface support for Sony CXD2880. + +endmenu + +endif diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile index ea64013d16cc..9e536777a330 100644 --- a/drivers/media/spi/Makefile +++ b/drivers/media/spi/Makefile @@ -1 +1,6 @@ obj-$(CONFIG_VIDEO_GS1662) += gs1662.o +obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/dvb-frontends/cxd2880 -- cgit From e61591875b7b626085c079499ac1c4663bfe510e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 04:58:49 -0500 Subject: media: cxd2880: Makefile: remove an include It is not needed anymore to include the dvb-core directory, as all the public headers that used to be there was moved to include/media. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile index 65a5d37f28cc..c6baa4caba19 100644 --- a/drivers/media/dvb-frontends/cxd2880/Makefile +++ b/drivers/media/dvb-frontends/cxd2880/Makefile @@ -15,5 +15,4 @@ cxd2880-objs := cxd2880_common.o \ obj-$(CONFIG_DVB_CXD2880) += cxd2880.o -ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends -- cgit From 9ca4897be5adef66b8fe384b4365ce385e83582f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 05:09:30 -0500 Subject: media: cxd2880: don't return unitialized values drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c:59 cxd2880_io_spi_read_reg() error: uninitialized symbol 'ret'. drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c:111 cxd2880_io_spi_write_reg() error: uninitialized symbol 'ret'. drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c:2985 cxd2880_tnrdmd_set_cfg() error: uninitialized symbol 'ret'. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c | 4 ++-- drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c index d2e37c95d748..aba59400859e 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c @@ -16,7 +16,7 @@ static int cxd2880_io_spi_read_reg(struct cxd2880_io *io, u8 sub_address, u8 *data, u32 size) { - int ret; + int ret = 0; struct cxd2880_spi *spi = NULL; u8 send_data[6]; u8 *read_data_top = data; @@ -64,7 +64,7 @@ static int cxd2880_io_spi_write_reg(struct cxd2880_io *io, u8 sub_address, const u8 *data, u32 size) { - int ret; + int ret = 0; struct cxd2880_spi *spi = NULL; u8 send_data[BURST_WRITE_MAX + 4]; const u8 *write_data_top = data; diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c index 25851bbb846e..4cf2d7cfd3f5 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -2503,7 +2503,7 @@ int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, enum cxd2880_tnrdmd_cfg_id id, int value) { - int ret; + int ret = 0; u8 data[2] = { 0 }; u8 need_sub_setting = 0; -- cgit From 8239bac18a760249c800eb032acc3f66cba8df04 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 05:11:29 -0500 Subject: media: cxd2880: remove unused vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/dvb-frontends/cxd2880/cxd2880_top.c: In function ‘cxd2880_set_ber_per_period_t’: drivers/media/dvb-frontends/cxd2880/cxd2880_top.c:677:34: warning: variable ‘c’ set but not used [-Wunused-but-set-variable] struct dtv_frontend_properties *c; ^ drivers/media/dvb-frontends/cxd2880/cxd2880_top.c: In function ‘cxd2880_set_ber_per_period_t2’: drivers/media/dvb-frontends/cxd2880/cxd2880_top.c:790:34: warning: variable ‘c’ set but not used [-Wunused-but-set-variable] struct dtv_frontend_properties *c; ^ drivers/media/dvb-frontends/cxd2880/cxd2880_top.c: In function ‘cxd2880_get_frontend’: drivers/media/dvb-frontends/cxd2880/cxd2880_top.c:1799:23: warning: variable ‘priv’ set but not used [-Wunused-but-set-variable] struct cxd2880_priv *priv = NULL; ^~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c index 05360a11bea9..d474dc1b05da 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -674,7 +674,6 @@ static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) { int ret; - struct dtv_frontend_properties *c; struct cxd2880_priv *priv; struct cxd2880_dvbt_tpsinfo info; enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; @@ -691,7 +690,6 @@ static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) } priv = fe->demodulator_priv; - c = &fe->dtv_property_cache; bw = priv->dvbt_tune_param.bandwidth; ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, @@ -787,7 +785,6 @@ static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) { int ret; - struct dtv_frontend_properties *c; struct cxd2880_priv *priv; struct cxd2880_dvbt2_l1pre l1pre; struct cxd2880_dvbt2_l1post l1post; @@ -815,7 +812,6 @@ static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) } priv = fe->demodulator_priv; - c = &fe->dtv_property_cache; bw = priv->dvbt2_tune_param.bandwidth; ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre); @@ -1796,7 +1792,6 @@ static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, static int cxd2880_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *props) { - struct cxd2880_priv *priv = NULL; int ret; if (!fe || !props) { @@ -1804,8 +1799,6 @@ static int cxd2880_get_frontend(struct dvb_frontend *fe, return -EINVAL; } - priv = fe->demodulator_priv; - pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system); switch (fe->dtv_property_cache.delivery_system) { case SYS_DVBT: -- cgit From 39ad07b7de82bff26118a69e680cda3d081392dc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Dec 2017 06:43:37 -0500 Subject: media: s5c73m3-core: fix logic on a timeout condition As warned by smatch: drivers/media/i2c/s5c73m3/s5c73m3-core.c:268 s5c73m3_check_status() error: uninitialized symbol 'status'. if s5c73m3_check_status() is called too late, time_is_after_jiffies(end) will return 0, causing the while to abort before reading status. The current code will do the wrong thing here, as it will still check if status != value. The right fix here is to change the logic to ensure that it will always read the status. Suggested-by: Andrzej Hajda Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index cdc4f2392ef9..ce196b60f917 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -248,17 +248,17 @@ static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value) { unsigned long start = jiffies; unsigned long end = start + msecs_to_jiffies(2000); - int ret = 0; + int ret; u16 status; int count = 0; - while (time_is_after_jiffies(end)) { + do { ret = s5c73m3_read(state, REG_STATUS, &status); if (ret < 0 || status == value) break; usleep_range(500, 1000); ++count; - } + } while (time_is_after_jiffies(end)); if (count > 0) v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, -- cgit From fce61d1dfd5b38529792898ba11a25e296e6d069 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 08:57:05 -0500 Subject: media: si2168: fix a comment about firmware version There's a comment there at s82168 that it is wrong. With firmware 4.0.11, sleep/resume works well without need of download it every time. But firmware 4.0.19 needs to be downloaded again after sleep. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index a91947784842..324493e05f9f 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -614,7 +614,7 @@ static int si2168_sleep(struct dvb_frontend *fe) if (ret) goto err; - /* Firmware B 4.0-11 or later loses warm state during sleep */ + /* Firmware later than B 4.0-11 loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; -- cgit From 883273053607c75264d8d7bc0ecc868bb26012c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Mar 2018 09:51:17 -0500 Subject: media: Kconfig: fix DVB dependencies If I2C is present and it is module, the DVB core should also be a module, otherwise build will now fail with: drivers/media/dvb-core/dvbdev.o: In function `dvb_module_probe': drivers/media/dvb-core/dvbdev.c:965: undefined reference to `i2c_new_device' drivers/media/dvb-core/dvbdev.c:972: undefined reference to `i2c_unregister_device' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 372c074bb1b9..29609661cf3d 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -141,6 +141,7 @@ config DVB_CORE tristate depends on MEDIA_SUPPORT depends on MEDIA_DIGITAL_TV_SUPPORT + depends on (I2C || I2C=n) default y select CRC32 -- cgit From d158490ae52062411f16f7af4b45efa6620cd47c Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Wed, 7 Mar 2018 14:23:47 -0500 Subject: media: dvb-frontends/cxd2099: Kconfig additions The cxd2099 driver makes use of the Regmap I2C kernel API, thus add "select REGMAP_I2C" to it's Kconfig block. Also, make it default "m" if !MEDIA_SUBDRV_AUTOSELECT, just like every other dvb-frontend driver. And, while at it, remove the hyphens around the help tag. Cc: Jasmin Jessich Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2ad81907c714..fcfa1135557e 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -912,7 +912,9 @@ comment "Common Interface (EN50221) controller drivers" config DVB_CXD2099 tristate "CXD2099AR Common Interface driver" depends on DVB_CORE && I2C - ---help--- + select REGMAP_I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help A driver for the CI controller currently found mostly on Digital Devices DuoFlex CI (single) addon modules. -- cgit From a31b86b17681fd2b888b11981222b472541d4a4d Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Wed, 7 Mar 2018 14:23:48 -0500 Subject: media: dvb-frontends/Kconfig: move the SP2 driver to the CI section The CIMaX SP2 driver is a EN50221 CI controller I2C driver similar to the cxd2099 driver. Move it's Kconfig block into the newly introduced CI subsection. Cc: Olli Salonen Cc: Antti Palosaari Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index fcfa1135557e..687086cdb870 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -824,13 +824,6 @@ config DVB_A8293 depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT -config DVB_SP2 - tristate "CIMaX SP2" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - CIMaX SP2/SP2HF Common Interface module. - config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C @@ -920,6 +913,13 @@ config DVB_CXD2099 Say Y when you want to support these devices. +config DVB_SP2 + tristate "CIMaX SP2" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + CIMaX SP2/SP2HF Common Interface module. + comment "Tools to develop new frontends" config DVB_DUMMY_FE -- cgit From c966453b1386136e47f7c45a6d3b66f4013f974d Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Wed, 7 Mar 2018 15:07:55 -0500 Subject: media: ddbridge: use common DVB I2C client handling helpers Instead of keeping duplicated I2C client handling construct, make use of the newly introduced dvb_module_*() helpers. This not only keeps things way cleaner and removes the need for duplicated I2C client attach code, but even allows to get rid of some variables that won't help in making things look cleaner anymore. The check on a valid ptr on port->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-ci.c | 33 ++++++--------------------- drivers/media/pci/ddbridge/ddbridge-core.c | 36 ++++++------------------------ 2 files changed, 14 insertions(+), 55 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 6585ef54ac22..a9dbc4ebf94f 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -324,34 +324,20 @@ static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) { struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; cxd_cfg.bitrate = bitrate; cxd_cfg.en = &port->en; - request_module(board_info.type); - - client = i2c_new_device(&port->i2c->adap, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!port->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap, + 0x40, &cxd_cfg); + if (!client) + goto err; port->dvb[0].i2c_client[0] = client; port->en_freedata = 0; return 0; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(port->dev->dev, "CXD2099AR attach failed\n"); return -ENODEV; } @@ -385,18 +371,13 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { - struct i2c_client *client; - if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - client = port->dvb[0].i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + dvb_module_release(port->dvb[0].i2c_client[0]); + port->dvb[0].i2c_client[0] = NULL; /* free alloc'ed memory if needed */ if (port->en_freedata) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index f9bee36f1cad..90687eff5909 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -999,37 +999,21 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (input->nr & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (input->nr & 1) ? 0x63 : 0x60; /* due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when * cold started, or it very likely will fail. */ if (porttype == DDB_TUNER_DVBCT_ST) - tuner_tda18212_ping(input, board_info.addr); - - request_module(board_info.type); - - /* perform tuner init/attach */ - client = i2c_new_device(adapter, &board_info); - if (!client || !client->dev.driver) - goto err; + tuner_tda18212_ping(input, addr); - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, adapter, addr, &config); + if (!client) goto err; - } dvb->i2c_client[0] = client; - return 0; err: dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); @@ -1253,7 +1237,6 @@ static void dvb_input_detach(struct ddb_input *input) { struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; struct dvb_demux *dvbdemux = &dvb->demux; - struct i2c_client *client; switch (dvb->attached) { case 0x31: @@ -1263,13 +1246,8 @@ static void dvb_input_detach(struct ddb_input *input) dvb_unregister_frontend(dvb->fe); /* fallthrough */ case 0x30: - client = dvb->i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - dvb->i2c_client[0] = NULL; - client = NULL; - } + dvb_module_release(dvb->i2c_client[0]); + dvb->i2c_client[0] = NULL; if (dvb->fe2) dvb_frontend_detach(dvb->fe2); -- cgit From 78c4e0820134fdf873c8ab6660b9283bb4be5496 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Wed, 7 Mar 2018 15:07:56 -0500 Subject: media: ngene: use common DVB I2C client handling helpers Like in ddbridge, get rid of all duplicated I2C client handling constructs and rather make use of the newly added dvb_module_*() helpers. Makes things more clean and removes the (cosmetic) need for some variables. The check on a valid ptr on ci->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 25 ++++---------------- drivers/media/pci/ngene/ngene-core.c | 43 ++++++++--------------------------- 2 files changed, 15 insertions(+), 53 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 37e9f0eb6d20..65fc8f23ad86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -253,15 +253,7 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (chan->number & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (chan->number & 1) ? 0x63 : 0x60; /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 @@ -269,20 +261,13 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) * cold started, or it very likely will fail. */ if (dmdtype == DEMOD_TYPE_STV0367) - tuner_tda18212_ping(chan, i2c, board_info.addr); - - request_module(board_info.type); + tuner_tda18212_ping(chan, i2c, addr); - /* perform tuner init/attach */ - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, i2c, addr, &config); + if (!client) goto err; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - goto err; - } - chan->i2c_client[0] = client; chan->i2c_client_fe = 1; diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index f69a8fc1ec2a..3b9a1bfaf6c0 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1408,7 +1408,6 @@ static void release_channel(struct ngene_channel *chan) { struct dvb_demux *dvbdemux = &chan->demux; struct ngene *dev = chan->dev; - struct i2c_client *client; if (chan->running) set_transfer(chan, 0); @@ -1427,12 +1426,9 @@ static void release_channel(struct ngene_channel *chan) dvb_unregister_frontend(chan->fe); /* release I2C client (tuner) if needed */ - client = chan->i2c_client[0]; - if (chan->i2c_client_fe && client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); + if (chan->i2c_client_fe) { + dvb_module_release(chan->i2c_client[0]); chan->i2c_client[0] = NULL; - client = NULL; } dvb_frontend_detach(chan->fe); @@ -1584,11 +1580,6 @@ static void cxd_attach(struct ngene *dev) struct ngene_ci *ci = &dev->ci; struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; int ret; u8 type; @@ -1605,26 +1596,17 @@ static void cxd_attach(struct ngene *dev) } cxd_cfg.en = &ci->en; - - request_module(board_info.type); - - client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!ci->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", NULL, + &dev->channel[0].i2c_adapter, + 0x40, &cxd_cfg); + if (!client) + goto err; ci->dev = dev; dev->channel[0].i2c_client[0] = client; return; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(pdev, "CXD2099AR attach failed\n"); return; } @@ -1632,16 +1614,11 @@ err_ret: static void cxd_detach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; - struct i2c_client *client; dvb_ca_en50221_release(ci->en); - client = dev->channel[0].i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - + dvb_module_release(dev->channel[0].i2c_client[0]); + dev->channel[0].i2c_client[0] = NULL; ci->en = NULL; } -- cgit From 3f127ce11353fd1071cae9b65bc13add6aec6b90 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Mar 2018 04:31:00 -0500 Subject: media: em28xx-cards: fix em28xx_duplicate_dev() There is a double sizeof() typo here so we don't duplicate the struct properly. Fixes: be7fd3c3a8c5 ("media: em28xx: Hauppauge DualHD second tuner functionality") Signed-off-by: Dan Carpenter --- drivers/media/usb/em28xx/em28xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 6e8247849c4f..6e0e67d23876 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3515,7 +3515,7 @@ static int em28xx_duplicate_dev(struct em28xx *dev) dev->dev_next = NULL; return -ENOMEM; } - memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev))); + memcpy(sec_dev, dev, sizeof(*sec_dev)); /* Check to see next free device and mark as used */ do { nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); -- cgit From 10e712064b0454621d2974cbd353e9d5bebbae4a Mon Sep 17 00:00:00 2001 From: Philipp Rossak Date: Tue, 13 Feb 2018 07:29:47 -0500 Subject: media: rc: update sunxi-ir driver to get base clock frequency from devicetree This patch updates the sunxi-ir driver to set the base clock frequency from devicetree. This is necessary since there are different ir receivers on the market, that operate with different frequencies. So this value could be set if the attached ir receiver needs a different base clock frequency, than the default 8 MHz. Signed-off-by: Philipp Rossak Reviewed-by: Andi Shyti Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/sunxi-cir.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 97f367b446c4..f500cea228a9 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -72,12 +72,8 @@ /* CIR_REG register idle threshold */ #define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8))) -/* Required frequency for IR0 or IR1 clock in CIR mode */ +/* Required frequency for IR0 or IR1 clock in CIR mode (default) */ #define SUNXI_IR_BASE_CLK 8000000 -/* Frequency after IR internal divider */ -#define SUNXI_IR_CLK (SUNXI_IR_BASE_CLK / 64) -/* Sample period in ns */ -#define SUNXI_IR_SAMPLE (1000000000ul / SUNXI_IR_CLK) /* Noise threshold in samples */ #define SUNXI_IR_RXNOISE 1 /* Idle Threshold in samples */ @@ -122,7 +118,8 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) /* for each bit in fifo */ dt = readb(ir->base + SUNXI_IR_RXFIFO_REG); rawir.pulse = (dt & 0x80) != 0; - rawir.duration = ((dt & 0x7f) + 1) * SUNXI_IR_SAMPLE; + rawir.duration = ((dt & 0x7f) + 1) * + ir->rc->rx_resolution; ir_raw_event_store_with_filter(ir->rc, &rawir); } } @@ -148,6 +145,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) struct device_node *dn = dev->of_node; struct resource *res; struct sunxi_ir *ir; + u32 b_clk_freq = SUNXI_IR_BASE_CLK; ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL); if (!ir) @@ -172,6 +170,9 @@ static int sunxi_ir_probe(struct platform_device *pdev) return PTR_ERR(ir->clk); } + /* Base clock frequency (optional) */ + of_property_read_u32(dn, "clock-frequency", &b_clk_freq); + /* Reset (optional) */ ir->rst = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(ir->rst)) @@ -180,11 +181,12 @@ static int sunxi_ir_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); + ret = clk_set_rate(ir->clk, b_clk_freq); if (ret) { dev_err(dev, "set ir base clock failed!\n"); goto exit_reset_assert; } + dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq); if (clk_prepare_enable(ir->apb_clk)) { dev_err(dev, "try to enable apb_ir_clk failed\n"); @@ -225,7 +227,8 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - ir->rc->rx_resolution = SUNXI_IR_SAMPLE; + /* Frequency after IR internal divider with sample period in ns */ + ir->rc->rx_resolution = (1000000000ul / (b_clk_freq / 64)); ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT); ir->rc->driver_name = SUNXI_IR_DEV; -- cgit From 1b450f211e009d207402ed546837ad5dbbeac276 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 6 Jan 2018 07:24:50 -0500 Subject: media: Revert "[media] staging: lirc_imon: port remaining usb ids to imon and remove" This code was ported without the necessary hardware to test. There are multiple problems which are more easily solved by writing a separate driver. This reverts commit f41003a23a02dc7299539300f74360c2a932714a. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 135 +++--------------------------------------------- 1 file changed, 7 insertions(+), 128 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 950d068ba806..527920a59d99 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -92,7 +92,6 @@ struct imon_usb_dev_descr { __u16 flags; #define IMON_NO_FLAGS 0 #define IMON_NEED_20MS_PKT_DELAY 1 -#define IMON_IR_RAW 2 struct imon_panel_key_table key_table[]; }; @@ -123,12 +122,6 @@ struct imon_context { unsigned char usb_tx_buf[8]; unsigned int send_packet_delay; - struct rx_data { - int count; /* length of 0 or 1 sequence */ - int prev_bit; /* logic level of sequence */ - int initial_space; /* initial space flag */ - } rx; - struct tx_t { unsigned char data_buf[35]; /* user data buffer */ struct completion finished; /* wait for write to finish */ @@ -331,10 +324,6 @@ static const struct imon_usb_dev_descr imon_DH102 = { } }; -static const struct imon_usb_dev_descr imon_ir_raw = { - .flags = IMON_IR_RAW, -}; - /* * USB Device ID for iMON USB Control Boards * @@ -418,18 +407,6 @@ static const struct usb_device_id imon_usb_id_table[] = { /* device specifics unknown */ { USB_DEVICE(0x15c2, 0x0046), .driver_info = (unsigned long)&imon_default_table}, - /* TriGem iMON (IR only) -- TG_iMON.inf */ - { USB_DEVICE(0x0aa8, 0x8001), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON (IR only) -- sg_imon.inf */ - { USB_DEVICE(0x04e8, 0xff30), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ - { USB_DEVICE(0x0aa8, 0xffda), - .driver_info = (unsigned long)&imon_ir_raw}, - /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ - { USB_DEVICE(0x15c2, 0xffda), - .driver_info = (unsigned long)&imon_ir_raw}, {} }; @@ -1572,91 +1549,8 @@ static int imon_parse_press_type(struct imon_context *ictx, /* * Process the incoming packet */ -/* - * Convert bit count to time duration (in us) and submit - * the value to lirc_dev. - */ -static void submit_data(struct imon_context *context) -{ - DEFINE_IR_RAW_EVENT(ev); - - ev.pulse = context->rx.prev_bit; - ev.duration = US_TO_NS(context->rx.count * BIT_DURATION); - ir_raw_event_store_with_filter(context->rdev, &ev); -} - -/* - * Process the incoming packet - */ -static void imon_incoming_ir_raw(struct imon_context *context, +static void imon_incoming_packet(struct imon_context *ictx, struct urb *urb, int intf) -{ - int len = urb->actual_length; - unsigned char *buf = urb->transfer_buffer; - struct device *dev = context->dev; - int octet, bit; - unsigned char mask; - - if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n", - __func__, len, intf); - return; - } - - if (debug) - dev_info(dev, "raw packet: %*ph\n", len, buf); - /* - * Translate received data to pulse and space lengths. - * Received data is active low, i.e. pulses are 0 and - * spaces are 1. - * - * My original algorithm was essentially similar to - * Changwoo Ryu's with the exception that he switched - * the incoming bits to active high and also fed an - * initial space to LIRC at the start of a new sequence - * if the previous bit was a pulse. - * - * I've decided to adopt his algorithm. - */ - - if (buf[7] == 1 && context->rx.initial_space) { - /* LIRC requires a leading space */ - context->rx.prev_bit = 0; - context->rx.count = 4; - submit_data(context); - context->rx.count = 0; - } - - for (octet = 0; octet < 5; ++octet) { - mask = 0x80; - for (bit = 0; bit < 8; ++bit) { - int curr_bit = !(buf[octet] & mask); - - if (curr_bit != context->rx.prev_bit) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.prev_bit = curr_bit; - } - ++context->rx.count; - mask >>= 1; - } - } - - if (buf[7] == 10) { - if (context->rx.count) { - submit_data(context); - context->rx.count = 0; - } - context->rx.initial_space = context->rx.prev_bit; - } - - ir_raw_event_handle(context->rdev); -} - -static void imon_incoming_scancode(struct imon_context *ictx, - struct urb *urb, int intf) { int len = urb->actual_length; unsigned char *buf = urb->transfer_buffer; @@ -1839,10 +1733,7 @@ static void usb_rx_callback_intf0(struct urb *urb) break; case 0: - if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) - imon_incoming_ir_raw(ictx, urb, intfnum); - else - imon_incoming_scancode(ictx, urb, intfnum); + imon_incoming_packet(ictx, urb, intfnum); break; default: @@ -1883,10 +1774,7 @@ static void usb_rx_callback_intf1(struct urb *urb) break; case 0: - if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) - imon_incoming_ir_raw(ictx, urb, intfnum); - else - imon_incoming_scancode(ictx, urb, intfnum); + imon_incoming_packet(ictx, urb, intfnum); break; default: @@ -2000,14 +1888,11 @@ static void imon_set_display_type(struct imon_context *ictx) case 0x0041: case 0x0042: case 0x0043: - case 0x8001: - case 0xff30: configured_display_type = IMON_DISPLAY_TYPE_NONE; ictx->display_supported = false; break; case 0x0036: case 0x0044: - case 0xffda: default: configured_display_type = IMON_DISPLAY_TYPE_VFD; break; @@ -2032,8 +1917,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) static const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 }; - rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ? - RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE); + rdev = rc_allocate_device(RC_DRIVER_SCANCODE); if (!rdev) { dev_err(ictx->dev, "remote control dev allocation failed\n"); goto out; @@ -2051,12 +1935,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->dev.parent = ictx->dev; rdev->priv = ictx; - if (ictx->dev_descr->flags & IMON_IR_RAW) - rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - else - /* iMON PAD or MCE */ - rdev->allowed_protocols = RC_PROTO_BIT_OTHER | - RC_PROTO_BIT_RC6_MCE; + /* iMON PAD or MCE */ + rdev->allowed_protocols = RC_PROTO_BIT_OTHER | RC_PROTO_BIT_RC6_MCE; rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -2074,8 +1954,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) imon_set_display_type(ictx); - if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || - ictx->dev_descr->flags & IMON_IR_RAW) + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) rdev->map_name = RC_MAP_IMON_MCE; else rdev->map_name = RC_MAP_IMON_PAD; -- cgit From 572eca036d71e2bb2822dba633ebda4fd3e6c05a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 5 Mar 2018 08:32:14 -0500 Subject: media: rc: add keymap for iMON RSC remote Note that the stick on the remote is not supported yet. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-imon-rsc.c | 81 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-imon-rsc.c (limited to 'drivers/media') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 50b319355edf..d6b913a3032d 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hisi-tv-demo.o \ rc-imon-mce.o \ rc-imon-pad.o \ + rc-imon-rsc.o \ rc-iodata-bctv7e.o \ rc-it913x-v1.o \ rc-it913x-v2.o \ diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c new file mode 100644 index 000000000000..83e4564aaa22 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-imon-rsc.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2018 Sean Young + +#include +#include + +// +// Note that this remote has a stick which its own IR protocol, +// with 16 directions. This is not supported yet. +// +static struct rc_map_table imon_rsc[] = { + { 0x801010, KEY_EXIT }, + { 0x80102f, KEY_POWER }, + { 0x80104a, KEY_SCREENSAVER }, /* Screensaver */ + { 0x801049, KEY_TIME }, /* Timer */ + { 0x801054, KEY_NUMERIC_1 }, + { 0x801055, KEY_NUMERIC_2 }, + { 0x801056, KEY_NUMERIC_3 }, + { 0x801057, KEY_NUMERIC_4 }, + { 0x801058, KEY_NUMERIC_5 }, + { 0x801059, KEY_NUMERIC_6 }, + { 0x80105a, KEY_NUMERIC_7 }, + { 0x80105b, KEY_NUMERIC_8 }, + { 0x80105c, KEY_NUMERIC_9 }, + { 0x801081, KEY_SCREEN }, /* Desktop */ + { 0x80105d, KEY_NUMERIC_0 }, + { 0x801082, KEY_MAX }, + { 0x801048, KEY_ESC }, + { 0x80104b, KEY_MEDIA }, /* Windows key */ + { 0x801083, KEY_MENU }, + { 0x801045, KEY_APPSELECT }, /* app launcher */ + { 0x801084, KEY_STOP }, + { 0x801046, KEY_CYCLEWINDOWS }, + { 0x801085, KEY_BACKSPACE }, + { 0x801086, KEY_KEYBOARD }, + { 0x801087, KEY_SPACE }, + { 0x80101e, KEY_RESERVED }, /* shift tab */ + { 0x801098, BTN_0 }, + { 0x80101f, KEY_TAB }, + { 0x80101b, BTN_LEFT }, + { 0x80101d, BTN_RIGHT }, + { 0x801016, BTN_MIDDLE }, /* drag and drop */ + { 0x801088, KEY_MUTE }, + { 0x80105e, KEY_VOLUMEDOWN }, + { 0x80105f, KEY_VOLUMEUP }, + { 0x80104c, KEY_PLAY }, + { 0x80104d, KEY_PAUSE }, + { 0x80104f, KEY_EJECTCD }, + { 0x801050, KEY_PREVIOUS }, + { 0x801051, KEY_NEXT }, + { 0x80104e, KEY_STOP }, + { 0x801052, KEY_REWIND }, + { 0x801053, KEY_FASTFORWARD }, + { 0x801089, KEY_ZOOM } /* full screen */ +}; + +static struct rc_map_list imon_rsc_map = { + .map = { + .scan = imon_rsc, + .size = ARRAY_SIZE(imon_rsc), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_IMON_RSC, + } +}; + +static int __init init_rc_map_imon_rsc(void) +{ + return rc_map_register(&imon_rsc_map); +} + +static void __exit exit_rc_map_imon_rsc(void) +{ + rc_map_unregister(&imon_rsc_map); +} + +module_init(init_rc_map_imon_rsc) +module_exit(exit_rc_map_imon_rsc) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young "); -- cgit From 8a4e8f8dfc69941eab6ede7a844fbed0c4841241 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 5 Jan 2018 14:58:51 -0500 Subject: media: rc: new driver for early iMon device These devices were supported by the lirc_imon.c driver which was removed from staging in commit f41003a23a02 ("[media] staging: lirc_imon: port remaining usb ids to imon and remove"). Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 12 +++ drivers/media/rc/Makefile | 1 + drivers/media/rc/imon_raw.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 drivers/media/rc/imon_raw.c (limited to 'drivers/media') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 447f82c1f65a..7ad05a6ef350 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -175,6 +175,18 @@ config IR_IMON To compile this driver as a module, choose M here: the module will be called imon. +config IR_IMON_RAW + tristate "SoundGraph iMON Receiver (early raw IR models)" + depends on USB_ARCH_HAS_HCD + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use a SoundGraph iMON IR Receiver, + early raw models. + + To compile this driver as a module, choose M here: the + module will be called imon_raw. + config IR_MCEUSB tristate "Windows Media Center Ed. eHome Infrared Transceiver" depends on USB_ARCH_HAS_HCD diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 0e857816ac2d..e098e127b26a 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o obj-$(CONFIG_IR_IMON) += imon.o +obj-$(CONFIG_IR_IMON_RAW) += imon_raw.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_FINTEK) += fintek-cir.o diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c new file mode 100644 index 000000000000..32709f96de14 --- /dev/null +++ b/drivers/media/rc/imon_raw.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2018 Sean Young + +#include +#include +#include +#include + +/* Each bit is 250us */ +#define BIT_DURATION 250000 + +struct imon { + struct device *dev; + struct urb *ir_urb; + struct rc_dev *rcdev; + u8 ir_buf[8]; + char phys[64]; +}; + +/* + * ffs/find_next_bit() searches in the wrong direction, so open-code our own. + */ +static inline int is_bit_set(const u8 *buf, int bit) +{ + return buf[bit / 8] & (0x80 >> (bit & 7)); +} + +static void imon_ir_data(struct imon *imon) +{ + DEFINE_IR_RAW_EVENT(rawir); + int offset = 0, size = 5 * 8; + int bit; + + dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf); + + while (offset < size) { + bit = offset; + while (!is_bit_set(imon->ir_buf, bit) && bit < size) + bit++; + dev_dbg(imon->dev, "pulse: %d bits", bit - offset); + if (bit > offset) { + rawir.pulse = true; + rawir.duration = (bit - offset) * BIT_DURATION; + ir_raw_event_store_with_filter(imon->rcdev, &rawir); + } + + if (bit >= size) + break; + + offset = bit; + while (is_bit_set(imon->ir_buf, bit) && bit < size) + bit++; + dev_dbg(imon->dev, "space: %d bits", bit - offset); + + rawir.pulse = false; + rawir.duration = (bit - offset) * BIT_DURATION; + ir_raw_event_store_with_filter(imon->rcdev, &rawir); + + offset = bit; + } + + if (imon->ir_buf[7] == 0x0a) { + ir_raw_event_set_idle(imon->rcdev, true); + ir_raw_event_handle(imon->rcdev); + } +} + +static void imon_ir_rx(struct urb *urb) +{ + struct imon *imon = urb->context; + int ret; + + switch (urb->status) { + case 0: + if (imon->ir_buf[7] != 0xff) + imon_ir_data(imon); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + case -EPIPE: + default: + dev_dbg(imon->dev, "error: urb status = %d", urb->status); + break; + } + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret && ret != -ENODEV) + dev_warn(imon->dev, "failed to resubmit urb: %d", ret); +} + +static int imon_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *ir_ep = NULL; + struct usb_host_interface *idesc; + struct usb_device *udev; + struct rc_dev *rcdev; + struct imon *imon; + int i, ret; + + udev = interface_to_usbdev(intf); + idesc = intf->cur_altsetting; + + for (i = 0; i < idesc->desc.bNumEndpoints; i++) { + struct usb_endpoint_descriptor *ep = &idesc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(ep)) { + ir_ep = ep; + break; + } + } + + if (!ir_ep) { + dev_err(&intf->dev, "IR endpoint missing"); + return -ENODEV; + } + + imon = devm_kmalloc(&intf->dev, sizeof(*imon), GFP_KERNEL); + if (!imon) + return -ENOMEM; + + imon->ir_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!imon->ir_urb) + return -ENOMEM; + + imon->dev = &intf->dev; + usb_fill_int_urb(imon->ir_urb, udev, + usb_rcvintpipe(udev, ir_ep->bEndpointAddress), + imon->ir_buf, sizeof(imon->ir_buf), + imon_ir_rx, imon, ir_ep->bInterval); + + rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW); + if (!rcdev) { + ret = -ENOMEM; + goto free_urb; + } + + usb_make_path(udev, imon->phys, sizeof(imon->phys)); + + rcdev->device_name = "iMON Station"; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->input_phys = imon->phys; + usb_to_input_id(udev, &rcdev->input_id); + rcdev->dev.parent = &intf->dev; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rcdev->map_name = RC_MAP_IMON_RSC; + rcdev->rx_resolution = BIT_DURATION; + rcdev->priv = imon; + + ret = devm_rc_register_device(&intf->dev, rcdev); + if (ret) + goto free_urb; + + imon->rcdev = rcdev; + + ret = usb_submit_urb(imon->ir_urb, GFP_KERNEL); + if (ret) + goto free_urb; + + usb_set_intfdata(intf, imon); + + return 0; + +free_urb: + usb_free_urb(imon->ir_urb); + return ret; +} + +static void imon_disconnect(struct usb_interface *intf) +{ + struct imon *imon = usb_get_intfdata(intf); + + usb_kill_urb(imon->ir_urb); + usb_free_urb(imon->ir_urb); +} + +static const struct usb_device_id imon_table[] = { + /* SoundGraph iMON (IR only) -- sg_imon.inf */ + { USB_DEVICE(0x04e8, 0xff30) }, + {} +}; + +static struct usb_driver imon_driver = { + .name = KBUILD_MODNAME, + .probe = imon_probe, + .disconnect = imon_disconnect, + .id_table = imon_table +}; + +module_usb_driver(imon_driver); + +MODULE_DESCRIPTION("Early raw iMON IR devices"); +MODULE_AUTHOR("Sean Young "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, imon_table); -- cgit From 8d4068810d9926250dd2435719a080b889eb44c3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 6 Mar 2018 08:57:57 -0500 Subject: media: rc: oops in ir_timer_keyup after device unplug If there is IR in the raw kfifo when ir_raw_event_unregister() is called, then kthread_stop() causes ir_raw_event_thread to be scheduled, decode some scancodes and re-arm timer_keyup. The timer_keyup then fires when the rc device is long gone. Cc: stable@vger.kernel.org Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 4a952108ba1e..8621761a680f 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1932,12 +1932,12 @@ void rc_unregister_device(struct rc_dev *dev) if (!dev) return; - del_timer_sync(&dev->timer_keyup); - del_timer_sync(&dev->timer_repeat); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + del_timer_sync(&dev->timer_keyup); + del_timer_sync(&dev->timer_repeat); + rc_free_rx_device(dev); mutex_lock(&dev->lock); -- cgit From 447dcc0cf12922fcda67731559dd970bde7b35a6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 3 Dec 2017 11:06:54 -0500 Subject: media: rc: add new imon protocol decoder and encoder This makes it possible to use the various iMON remotes with any raw IR RC device. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 9 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/ir-imon-decoder.c | 193 +++++++++++++++++++++++++++++++++ drivers/media/rc/keymaps/rc-imon-pad.c | 3 +- drivers/media/rc/rc-core-priv.h | 6 + drivers/media/rc/rc-main.c | 3 + 6 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 drivers/media/rc/ir-imon-decoder.c (limited to 'drivers/media') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 7ad05a6ef350..eb2c3b6eca7f 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -111,6 +111,15 @@ config IR_XMP_DECODER ---help--- Enable this option if you have IR with XMP protocol, and if the IR is decoded in software + +config IR_IMON_DECODER + tristate "Enable IR raw decoder for the iMON protocol" + depends on RC_CORE + ---help--- + Enable this option if you have iMON PAD or Antec Veris infrared + remote control and you would like to use it with a raw IR + receiver, or if you wish to use an encoder to transmit this IR. + endif #RC_DECODERS menuconfig RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index e098e127b26a..2e1c87066f6c 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o +obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o # stand-alone IR receivers/transmitters obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c new file mode 100644 index 000000000000..a1ff06a26542 --- /dev/null +++ b/drivers/media/rc/ir-imon-decoder.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +// ir-imon-decoder.c - handle iMon protocol +// +// Copyright (C) 2018 by Sean Young + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include "rc-core-priv.h" + +#define IMON_UNIT 415662 /* ns */ +#define IMON_BITS 30 +#define IMON_CHKBITS (BIT(30) | BIT(25) | BIT(24) | BIT(22) | \ + BIT(21) | BIT(20) | BIT(19) | BIT(18) | \ + BIT(17) | BIT(16) | BIT(14) | BIT(13) | \ + BIT(12) | BIT(11) | BIT(10) | BIT(9)) + +/* + * This protocol has 30 bits. The format is one IMON_UNIT header pulse, + * followed by 30 bits. Each bit is one IMON_UNIT check field, and then + * one IMON_UNIT field with the actual bit (1=space, 0=pulse). + * The check field is always space for some bits, for others it is pulse if + * both the preceding and current bit are zero, else space. IMON_CHKBITS + * defines which bits are of type check. + * + * There is no way to distinguish an incomplete message from one where + * the lower bits are all set, iow. the last pulse is for the lowest + * bit which is 0. + */ +enum imon_state { + STATE_INACTIVE, + STATE_BIT_CHK, + STATE_BIT_START, + STATE_FINISHED +}; + +/** + * ir_imon_decode() - Decode one iMON pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct imon_dec *data = &dev->raw->imon; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + dev_dbg(&dev->dev, + "iMON decode started at state %d bitno %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), + TO_STR(ev.pulse)); + + for (;;) { + if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2)) + return 0; + + decrease_duration(&ev, IMON_UNIT); + + switch (data->state) { + case STATE_INACTIVE: + if (ev.pulse) { + data->state = STATE_BIT_CHK; + data->bits = 0; + data->count = IMON_BITS; + } + break; + case STATE_BIT_CHK: + if (IMON_CHKBITS & BIT(data->count)) + data->last_chk = ev.pulse; + else if (ev.pulse) + goto err_out; + data->state = STATE_BIT_START; + break; + case STATE_BIT_START: + data->bits <<= 1; + if (!ev.pulse) + data->bits |= 1; + + if (IMON_CHKBITS & BIT(data->count)) { + if (data->last_chk != !(data->bits & 3)) + goto err_out; + } + + if (!data->count--) + data->state = STATE_FINISHED; + else + data->state = STATE_BIT_CHK; + break; + case STATE_FINISHED: + if (ev.pulse) + goto err_out; + rc_keydown(dev, RC_PROTO_IMON, data->bits, 0); + data->state = STATE_INACTIVE; + break; + } + } + +err_out: + dev_dbg(&dev->dev, + "iMON decode failed at state %d bitno %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), + TO_STR(ev.pulse)); + + data->state = STATE_INACTIVE; + + return -EINVAL; +} + +/** + * ir_imon_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_imon_encode(enum rc_proto protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int i, pulse; + + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(e, 1, IMON_UNIT); + + for (i = IMON_BITS; i >= 0; i--) { + if (BIT(i) & IMON_CHKBITS) + pulse = !(scancode & (BIT(i) | BIT(i + 1))); + else + pulse = 0; + + if (pulse == e->pulse) { + e->duration += IMON_UNIT; + } else { + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(++e, pulse, IMON_UNIT); + } + + pulse = !(scancode & BIT(i)); + + if (pulse == e->pulse) { + e->duration += IMON_UNIT; + } else { + if (!max--) + return -ENOBUFS; + init_ir_raw_event_duration(++e, pulse, IMON_UNIT); + } + } + + if (e->pulse) + e++; + + return e - events; +} + +static struct ir_raw_handler imon_handler = { + .protocols = RC_PROTO_BIT_IMON, + .decode = ir_imon_decode, + .encode = ir_imon_encode, + .carrier = 38000, +}; + +static int __init ir_imon_decode_init(void) +{ + ir_raw_handler_register(&imon_handler); + + pr_info("IR iMON protocol handler initialized\n"); + return 0; +} + +static void __exit ir_imon_decode_exit(void) +{ + ir_raw_handler_unregister(&imon_handler); +} + +module_init(ir_imon_decode_init); +module_exit(ir_imon_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young "); +MODULE_DESCRIPTION("iMON IR protocol decoder"); diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index a7296ffbf218..8501cf0a3253 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -134,8 +134,7 @@ static struct rc_map_list imon_pad_map = { .map = { .scan = imon_pad, .size = ARRAY_SIZE(imon_pad), - /* actual protocol details unknown, hardware decoder */ - .rc_proto = RC_PROTO_OTHER, + .rc_proto = RC_PROTO_IMON, .name = RC_MAP_IMON_PAD, } }; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 5e80b4273e2d..e0e6a17460f6 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -118,6 +118,12 @@ struct ir_raw_event_ctrl { unsigned count; u32 durations[16]; } xmp; + struct imon_dec { + int state; + int count; + int last_chk; + unsigned int bits; + } imon; }; /* macros for IR decoders */ diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8621761a680f..b67be33bd62f 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -68,6 +68,8 @@ static const struct { .scancode_bits = 0x1fff, .repeat_period = 250 }, [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 }, + [RC_PROTO_IMON] = { .name = "imon", + .scancode_bits = 0x7fffffff, .repeat_period = 250 }, }; /* Used to keep track of known keymaps */ @@ -1004,6 +1006,7 @@ static const struct { RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, { RC_PROTO_BIT_CEC, "cec", NULL }, + { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" }, }; /** -- cgit From 2525fdcb6e8211ee9dbc270a7f882fbfb6433b55 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 7 Mar 2018 05:55:38 -0500 Subject: media: imon: rename protocol from other to imon This renames the protocol for the imon rc driver from other to imon, since it is now an known protocol. Although different name will show up in the sysfs protocol file, loading a keymap using existing ir-keytable versions still works. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 527920a59d99..1041c056854d 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1110,18 +1110,18 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; *rc_proto = RC_PROTO_BIT_RC6_MCE; - } else if (*rc_proto & RC_PROTO_BIT_OTHER) { + } else if (*rc_proto & RC_PROTO_BIT_IMON) { dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_proto = RC_PROTO_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_IMON; } else { dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_proto = RC_PROTO_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_IMON; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); @@ -1388,7 +1388,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1455,7 +1455,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1639,11 +1639,18 @@ static void imon_incoming_packet(struct imon_context *ictx, if (press_type == 0) rc_keyup(ictx->rdev); else { - if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || - ictx->rc_proto == RC_PROTO_BIT_OTHER) - rc_keydown(ictx->rdev, - ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ? RC_PROTO_RC6_MCE : RC_PROTO_OTHER, - ictx->rc_scancode, ictx->rc_toggle); + enum rc_proto proto; + + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) + proto = RC_PROTO_RC6_MCE; + else if (ictx->rc_proto == RC_PROTO_BIT_IMON) + proto = RC_PROTO_IMON; + else + return; + + rc_keydown(ictx->rdev, proto, ictx->rc_scancode, + ictx->rc_toggle); + spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1800,7 +1807,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_PROTO_BIT_OTHER; + u64 allowed_protos = RC_PROTO_BIT_IMON; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -1848,8 +1855,10 @@ static void imon_get_ffdc_type(struct imon_context *ictx) default: dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - /* We don't know which one it is, allow user to set the - * RC6 one from userspace if OTHER wasn't correct. */ + /* + * We don't know which one it is, allow user to set the + * RC6 one from userspace if IMON wasn't correct. + */ allowed_protos |= RC_PROTO_BIT_RC6_MCE; break; } @@ -1936,7 +1945,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->priv = ictx; /* iMON PAD or MCE */ - rdev->allowed_protocols = RC_PROTO_BIT_OTHER | RC_PROTO_BIT_RC6_MCE; + rdev->allowed_protocols = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE; rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; -- cgit From 95ce9c28601afc5da0c11792601ad32dd14cdd44 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 23 Feb 2018 04:50:14 -0500 Subject: media: v4l: common: Add a function to obtain best size from a list Add a function (as well as a helper macro) to obtain the best size in a list of device specific sizes. This helps writing drivers as well as aligns interface behaviour across drivers. The struct in which this information is contained in is typically specific to the driver, therefore the existing function v4l2_find_nearest_format() does not address the need. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 96c1b31de9e3..9b65529dfaf6 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -383,6 +383,36 @@ v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes, } EXPORT_SYMBOL_GPL(v4l2_find_nearest_format); +const void * +__v4l2_find_nearest_size(const void *array, size_t array_size, + size_t entry_size, size_t width_offset, + size_t height_offset, s32 width, s32 height) +{ + u32 error, min_error = U32_MAX; + const void *best = NULL; + unsigned int i; + + if (!array) + return NULL; + + for (i = 0; i < array_size; i++, array += entry_size) { + const u32 *entry_width = array + width_offset; + const u32 *entry_height = array + height_offset; + + error = abs(*entry_width - width) + abs(*entry_height - height); + if (error > min_error) + continue; + + min_error = error; + best = array; + if (!error) + break; + } + + return best; +} +EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size); + void v4l2_get_timestamp(struct timeval *tv) { struct timespec ts; -- cgit From 227b183dcbcc430a6ce29518d3b24d481597e87d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Feb 2018 06:24:34 -0500 Subject: media: ov13858: Use v4l2_find_nearest_size Use v4l2_find_nearest_size instead of a driver specific function to find nearest matching size. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index d4156eb62dab..30ee9f71bf0d 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1355,39 +1355,6 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd, return ret; } -/* - * Calculate resolution distance - */ -static int -ov13858_get_resolution_dist(const struct ov13858_mode *mode, - struct v4l2_mbus_framefmt *framefmt) -{ - return abs(mode->width - framefmt->width) + - abs(mode->height - framefmt->height); -} - -/* - * Find the closest supported resolution to the requested resolution - */ -static const struct ov13858_mode * -ov13858_find_best_fit(struct ov13858 *ov13858, - struct v4l2_subdev_format *fmt) -{ - int i, dist, cur_best_fit = 0, cur_best_fit_dist = -1; - struct v4l2_mbus_framefmt *framefmt = &fmt->format; - - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = ov13858_get_resolution_dist(&supported_modes[i], - framefmt); - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { - cur_best_fit_dist = dist; - cur_best_fit = i; - } - } - - return &supported_modes[cur_best_fit]; -} - static int ov13858_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, @@ -1408,7 +1375,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10) fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - mode = ov13858_find_best_fit(ov13858, fmt); + mode = v4l2_find_nearest_size(supported_modes, width, height, + fmt->format.width, fmt->format.height); ov13858_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); -- cgit From 894de53b4938f6e4eb5dd0435c60cc87b5747855 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Feb 2018 06:25:20 -0500 Subject: media: ov5670: Use v4l2_find_nearest_size Use v4l2_find_nearest_size instead of a driver specific function to find nearest matching size. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 9f9196568eb8..556a95c30781 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2180,36 +2180,6 @@ static int ov5670_enum_frame_size(struct v4l2_subdev *sd, return 0; } -/* Calculate resolution distance */ -static int ov5670_get_reso_dist(const struct ov5670_mode *mode, - struct v4l2_mbus_framefmt *framefmt) -{ - return abs(mode->width - framefmt->width) + - abs(mode->height - framefmt->height); -} - -/* Find the closest supported resolution to the requested resolution */ -static const struct ov5670_mode *ov5670_find_best_fit( - struct ov5670 *ov5670, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *framefmt = &fmt->format; - int dist; - int cur_best_fit = 0; - int cur_best_fit_dist = -1; - int i; - - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = ov5670_get_reso_dist(&supported_modes[i], framefmt); - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { - cur_best_fit_dist = dist; - cur_best_fit = i; - } - } - - return &supported_modes[cur_best_fit]; -} - static void ov5670_update_pad_format(const struct ov5670_mode *mode, struct v4l2_subdev_format *fmt) { @@ -2259,7 +2229,8 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd, fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - mode = ov5670_find_best_fit(ov5670, fmt); + mode = v4l2_find_nearest_size(supported_modes, width, height, + fmt->format.width, fmt->format.height); ov5670_update_pad_format(mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; -- cgit From ac53212880a1af2191fd469dab275b94cd9d13c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Feb 2018 07:00:02 -0500 Subject: media: vivid: Use v4l2_find_nearest_size Use v4l2_find_nearest_size instead of a driver specific function to find nearest matching size. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 808967c7b0ab..01c703683657 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -561,9 +561,8 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, mp->field = vivid_field_cap(dev, mp->field); if (vivid_is_webcam(dev)) { const struct v4l2_frmsize_discrete *sz = - v4l2_find_nearest_format(webcam_sizes, - VIVID_WEBCAM_SIZES, - mp->width, mp->height); + v4l2_find_nearest_size(webcam_sizes, width, height, + mp->width, mp->height); w = sz->width; h = sz->height; -- cgit From 3c91d24fcd89c6b40bc3d4741311bc046456291d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Feb 2018 07:00:48 -0500 Subject: media: v4l: common: Remove v4l2_find_nearest_format v4l2_find_nearest_format is not useful for drivers in finding the best matching format as it assumes a V4L2 specific struct. Drivers will use v4l2_find_nearest_size instead. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 9b65529dfaf6..b518b92d6d96 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -357,32 +357,6 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } EXPORT_SYMBOL_GPL(v4l_bound_align_image); -const struct v4l2_frmsize_discrete * -v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes, - size_t num_sizes, - s32 width, s32 height) -{ - int i; - u32 error, min_error = UINT_MAX; - const struct v4l2_frmsize_discrete *size, *best = NULL; - - if (!sizes) - return NULL; - - for (i = 0, size = sizes; i < num_sizes; i++, size++) { - error = abs(size->width - width) + abs(size->height - height); - if (error < min_error) { - min_error = error; - best = size; - } - if (!error) - break; - } - - return best; -} -EXPORT_SYMBOL_GPL(v4l2_find_nearest_format); - const void * __v4l2_find_nearest_size(const void *array, size_t array_size, size_t entry_size, size_t width_offset, -- cgit From f8c5363db34e4d1bbcbaeeb5cbb2762abb876162 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 22 Feb 2018 04:49:14 -0500 Subject: media: stm32-dcmi: fix lock scheme Fix lock scheme leading to spurious freeze. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 57 +++++++++++++------------------ 1 file changed, 24 insertions(+), 33 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index cc104a0805e2..37d82d3e33f9 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -197,7 +197,7 @@ static void dcmi_dma_callback(void *param) struct dma_tx_state state; enum dma_status status; - spin_lock(&dcmi->irqlock); + spin_lock_irq(&dcmi->irqlock); /* Check DMA status */ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); @@ -239,7 +239,7 @@ static void dcmi_dma_callback(void *param) dcmi->errors_count++; dcmi->active = NULL; - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return; } @@ -248,13 +248,11 @@ static void dcmi_dma_callback(void *param) list_del_init(&dcmi->active->list); - if (dcmi_start_capture(dcmi)) { + spin_unlock_irq(&dcmi->irqlock); + if (dcmi_start_capture(dcmi)) dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", __func__); - - spin_unlock(&dcmi->irqlock); - return; - } + return; } break; @@ -263,7 +261,7 @@ static void dcmi_dma_callback(void *param) break; } - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); } static int dcmi_start_dma(struct stm32_dcmi *dcmi, @@ -360,7 +358,7 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; - spin_lock(&dcmi->irqlock); + spin_lock_irq(&dcmi->irqlock); /* Stop capture is required */ if (dcmi->state == STOPPING) { @@ -370,7 +368,7 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) complete(&dcmi->complete); - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } @@ -383,35 +381,34 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) __func__); dcmi->errors_count++; - dmaengine_terminate_all(dcmi->dma_chan); - dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n"); - if (dcmi_start_capture(dcmi)) { + spin_unlock_irq(&dcmi->irqlock); + dmaengine_terminate_all(dcmi->dma_chan); + + if (dcmi_start_capture(dcmi)) dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", __func__); - - spin_unlock(&dcmi->irqlock); - return IRQ_HANDLED; - } + return IRQ_HANDLED; } - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } static irqreturn_t dcmi_irq_callback(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; + unsigned long flags; - spin_lock(&dcmi->irqlock); + spin_lock_irqsave(&dcmi->irqlock, flags); dcmi->misr = reg_read(dcmi->regs, DCMI_MIS); /* Clear interrupt */ reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock(&dcmi->irqlock); + spin_unlock_irqrestore(&dcmi->irqlock, flags); return IRQ_WAKE_THREAD; } @@ -490,9 +487,8 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); - unsigned long flags = 0; - spin_lock_irqsave(&dcmi->irqlock, flags); + spin_lock_irq(&dcmi->irqlock); if ((dcmi->state == RUNNING) && (!dcmi->active)) { dcmi->active = buf; @@ -500,19 +496,15 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n", buf->vb.vb2_buf.index); - if (dcmi_start_capture(dcmi)) { + spin_unlock_irq(&dcmi->irqlock); + if (dcmi_start_capture(dcmi)) dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", __func__); - - spin_unlock_irqrestore(&dcmi->irqlock, flags); - return; - } } else { /* Enqueue to video buffers list */ list_add_tail(&buf->list, &dcmi->buffers); + spin_unlock_irq(&dcmi->irqlock); } - - spin_unlock_irqrestore(&dcmi->irqlock, flags); } static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) @@ -598,20 +590,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dev_dbg(dcmi->dev, "Start streaming, starting capture\n"); + spin_unlock_irq(&dcmi->irqlock); ret = dcmi_start_capture(dcmi); if (ret) { dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", __func__); - - spin_unlock_irq(&dcmi->irqlock); goto err_subdev_streamoff; } /* Enable interruptions */ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock_irq(&dcmi->irqlock); - return 0; err_subdev_streamoff: @@ -654,7 +643,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", __func__, ret); + spin_lock_irq(&dcmi->irqlock); dcmi->state = STOPPING; + spin_unlock_irq(&dcmi->irqlock); timeout = wait_for_completion_interruptible_timeout(&dcmi->complete, time_ms); -- cgit From a1029f552c3f66dc205eea6473e64040ca5023b5 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 8 Mar 2018 05:46:23 -0500 Subject: media: stm32-dcmi: rework overrun/error case Do not stop/restart dma on overrun or errors. Dma will be restarted on current frame transfer completion. Frame transfer completion is ensured even if overrun or error occurs by DCMI continuous capture mode which restarts data transfer at next frame sync. Do no warn on overrun while in irq thread, this slows down system and lead to more overrun errors. Use a counter instead and log errors at stop streaming. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 37d82d3e33f9..95ace0ffa687 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -160,6 +160,7 @@ struct stm32_dcmi { dma_cookie_t dma_cookie; u32 misr; int errors_count; + int overrun_count; int buffers_count; }; @@ -373,23 +374,9 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) } if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { - /* - * An overflow or an error has been detected, - * stop current DMA transfert & restart it - */ - dev_warn(dcmi->dev, "%s: Overflow or error detected\n", - __func__); - dcmi->errors_count++; - dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n"); - - spin_unlock_irq(&dcmi->irqlock); - dmaengine_terminate_all(dcmi->dma_chan); - - if (dcmi_start_capture(dcmi)) - dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", - __func__); - return IRQ_HANDLED; + if (dcmi->misr & IT_OVR) + dcmi->overrun_count++; } spin_unlock_irq(&dcmi->irqlock); @@ -572,6 +559,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi->sequence = 0; dcmi->errors_count = 0; + dcmi->overrun_count = 0; dcmi->buffers_count = 0; dcmi->active = NULL; @@ -682,8 +670,13 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) clk_disable(dcmi->mclk); - dev_dbg(dcmi->dev, "Stop streaming, errors=%d buffers=%d\n", - dcmi->errors_count, dcmi->buffers_count); + if (dcmi->errors_count) + dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); + dev_dbg(dcmi->dev, "Stop streaming, errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); } static const struct vb2_ops dcmi_video_qops = { -- cgit From b4ee319480e6d8a066b9522e65cee41795496951 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 22 Feb 2018 04:51:27 -0500 Subject: media: stm32-dcmi: fix unnecessary parentheses Fix unnecessary parentheses in if conditions. Detected by checkpatch.pl --strict. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 95ace0ffa687..b46725b19499 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -477,7 +477,7 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) spin_lock_irq(&dcmi->irqlock); - if ((dcmi->state == RUNNING) && (!dcmi->active)) { + if (dcmi->state == RUNNING && !dcmi->active) { dcmi->active = buf; dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n", @@ -730,7 +730,7 @@ static void __find_outer_frame_size(struct stm32_dcmi *dcmi, int h_err = (fsize->height - pix->height); int err = w_err + h_err; - if ((w_err >= 0) && (h_err >= 0) && (err < min_err)) { + if (w_err >= 0 && h_err >= 0 && err < min_err) { min_err = err; match = fsize; } @@ -1065,10 +1065,10 @@ static int dcmi_s_selection(struct file *file, void *priv, r.top = clamp_t(s32, r.top, 0, pix.height - r.height); r.left = clamp_t(s32, r.left, 0, pix.width - r.width); - if (!((r.top == dcmi->sd_bounds.top) && - (r.left == dcmi->sd_bounds.left) && - (r.width == dcmi->sd_bounds.width) && - (r.height == dcmi->sd_bounds.height))) { + if (!(r.top == dcmi->sd_bounds.top && + r.left == dcmi->sd_bounds.left && + r.width == dcmi->sd_bounds.width && + r.height == dcmi->sd_bounds.height)) { /* Crop if request is different than sensor resolution */ dcmi->do_crop = true; dcmi->crop = r; -- cgit From 3e187c81d405474ef6361acf6d875657940cc2c0 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 28 Feb 2018 12:20:16 -0500 Subject: media: stm32-dcmi: add JPEG support Add DCMI JPEG support. Signed-off-by: Hugues Fruchet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 193 ++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 47 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index b46725b19499..2e1933d872ee 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -93,6 +93,11 @@ enum state { #define MIN_HEIGHT 16U #define MAX_HEIGHT 2048U +#define MIN_JPEG_WIDTH 16U +#define MAX_JPEG_WIDTH 2592U +#define MIN_JPEG_HEIGHT 16U +#define MAX_JPEG_HEIGHT 2592U + #define TIMEOUT_MS 1000 struct dcmi_graph_entity { @@ -191,14 +196,67 @@ static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) static int dcmi_start_capture(struct stm32_dcmi *dcmi); +static void dcmi_buffer_done(struct stm32_dcmi *dcmi, + struct dcmi_buf *buf, + size_t bytesused, + int err) +{ + struct vb2_v4l2_buffer *vbuf; + + if (!buf) + return; + + vbuf = &buf->vb; + + vbuf->sequence = dcmi->sequence++; + vbuf->field = V4L2_FIELD_NONE; + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused); + vb2_buffer_done(&vbuf->vb2_buf, + err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev_dbg(dcmi->dev, "buffer[%d] done seq=%d, bytesused=%zu\n", + vbuf->vb2_buf.index, vbuf->sequence, bytesused); + + dcmi->buffers_count++; + dcmi->active = NULL; +} + +static int dcmi_restart_capture(struct stm32_dcmi *dcmi) +{ + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->state != RUNNING) { + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + /* Restart a new DMA transfer with next buffer */ + if (list_empty(&dcmi->buffers)) { + dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n", + __func__); + dcmi->errors_count++; + dcmi->active = NULL; + + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + dcmi->active = list_entry(dcmi->buffers.next, + struct dcmi_buf, list); + list_del_init(&dcmi->active->list); + + spin_unlock_irq(&dcmi->irqlock); + + return dcmi_start_capture(dcmi); +} + static void dcmi_dma_callback(void *param) { struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param; struct dma_chan *chan = dcmi->dma_chan; struct dma_tx_state state; enum dma_status status; - - spin_lock_irq(&dcmi->irqlock); + struct dcmi_buf *buf = dcmi->active; /* Check DMA status */ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); @@ -216,53 +274,18 @@ static void dcmi_dma_callback(void *param) case DMA_COMPLETE: dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__); - if (dcmi->active) { - struct dcmi_buf *buf = dcmi->active; - struct vb2_v4l2_buffer *vbuf = &dcmi->active->vb; - - vbuf->sequence = dcmi->sequence++; - vbuf->field = V4L2_FIELD_NONE; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vb2_set_plane_payload(&vbuf->vb2_buf, 0, buf->size); - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); - dev_dbg(dcmi->dev, "buffer[%d] done seq=%d\n", - vbuf->vb2_buf.index, vbuf->sequence); - - dcmi->buffers_count++; - dcmi->active = NULL; - } - - /* Restart a new DMA transfer with next buffer */ - if (dcmi->state == RUNNING) { - if (list_empty(&dcmi->buffers)) { - dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n", - __func__); - dcmi->errors_count++; - dcmi->active = NULL; - - spin_unlock_irq(&dcmi->irqlock); - return; - } - - dcmi->active = list_entry(dcmi->buffers.next, - struct dcmi_buf, list); - - list_del_init(&dcmi->active->list); - - spin_unlock_irq(&dcmi->irqlock); - if (dcmi_start_capture(dcmi)) - dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", - __func__); - return; - } + /* Return buffer to V4L2 */ + dcmi_buffer_done(dcmi, buf, buf->size, 0); + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", + __func__); break; default: dev_err(dcmi->dev, "%s: Received unknown status\n", __func__); break; } - - spin_unlock_irq(&dcmi->irqlock); } static int dcmi_start_dma(struct stm32_dcmi *dcmi, @@ -355,6 +378,52 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi) reg_set(dcmi->regs, DCMI_CR, CR_CROP); } +static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) +{ + struct dma_tx_state state; + enum dma_status status; + struct dma_chan *chan = dcmi->dma_chan; + struct dcmi_buf *buf = dcmi->active; + + if (!buf) + return; + + /* + * Because of variable JPEG buffer size sent by sensor, + * DMA transfer never completes due to transfer size + * never reached. + * In order to ensure that all the JPEG data are transferred + * in active buffer memory, DMA is drained. + * Then DMA tx status gives the amount of data transferred + * to memory, which is then returned to V4L2 through the active + * buffer payload. + */ + + /* Drain DMA */ + dmaengine_synchronize(chan); + + /* Get DMA residue to get JPEG size */ + status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); + if (status != DMA_ERROR && state.residue < buf->size) { + /* Return JPEG buffer to V4L2 with received JPEG buffer size */ + dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0); + } else { + dcmi->errors_count++; + dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n", + __func__); + /* Return JPEG buffer to V4L2 in ERROR state */ + dcmi_buffer_done(dcmi, buf, 0, -EIO); + } + + /* Abort DMA operation */ + dmaengine_terminate_all(dcmi->dma_chan); + + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n", + __func__); +} + static irqreturn_t dcmi_irq_thread(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; @@ -379,6 +448,14 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) dcmi->overrun_count++; } + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && + dcmi->misr & IT_FRAME) { + /* JPEG received */ + spin_unlock_irq(&dcmi->irqlock); + dcmi_process_jpeg(dcmi); + return IRQ_HANDLED; + } + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } @@ -552,6 +629,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (dcmi->do_crop) dcmi_set_crop(dcmi); + /* Enable jpeg capture */ + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) + reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ + /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); @@ -752,6 +833,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; + bool do_crop; int ret; sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); @@ -761,10 +843,19 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } /* Limit to hardware capabilities */ - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + pix->width = clamp(pix->width, MIN_JPEG_WIDTH, MAX_JPEG_WIDTH); + pix->height = + clamp(pix->height, MIN_JPEG_HEIGHT, MAX_JPEG_HEIGHT); + } else { + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + } + + /* No crop if JPEG is requested */ + do_crop = dcmi->do_crop && (pix->pixelformat != V4L2_PIX_FMT_JPEG); - if (dcmi->do_crop && dcmi->num_of_sd_framesizes) { + if (do_crop && dcmi->num_of_sd_framesizes) { struct dcmi_framesize outer_sd_fsize; /* * If crop is requested and sensor have discrete frame sizes, @@ -788,7 +879,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, sd_fsize.width = pix->width; sd_fsize.height = pix->height; - if (dcmi->do_crop) { + if (do_crop) { struct v4l2_rect c = dcmi->crop; struct v4l2_rect max_rect; @@ -843,6 +934,10 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) if (ret) return ret; + /* Disable crop if JPEG is requested */ + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) + dcmi->do_crop = false; + /* pix to mbus format */ v4l2_fill_mbus_format(mf, pix, sd_format->mbus_code); @@ -1334,6 +1429,10 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_JPEG, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + .bpp = 1, }, }; -- cgit From 36d6bf8976e9188915e34cb840a5a9d5a62fb8ca Mon Sep 17 00:00:00 2001 From: Douglas Fischer Date: Sun, 25 Feb 2018 21:24:06 -0500 Subject: media: radio: Tuning bugfix for si470x over i2c Fixed si470x_set_channel() trying to tune before chip is turned on, which causes warnings in dmesg and when probing, makes driver wait for 3s for tuning timeout. This issue did not affect USB devices because they have a different probing sequence. Signed-off-by: Douglas Fischer [hans.verkuil@cisco.com: fixed space-after-( checkpatch warning] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index e0054e0f410d..6f0bf438be59 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -207,6 +207,15 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) unsigned long time_left; bool timed_out = false; + retval = si470x_get_register(radio, POWERCFG); + if (retval) + return retval; + + if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE)) + != (POWERCFG_ENABLE|POWERCFG_DMUTE)) { + return 0; + } + /* start tuning */ radio->registers[CHANNEL] &= ~CHANNEL_CHAN; radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; -- cgit From 8c081b6f9a9b81a11dd453a91c302d1e6115411b Mon Sep 17 00:00:00 2001 From: Douglas Fischer Date: Mon, 26 Feb 2018 18:22:02 -0500 Subject: media: radio: Critical v4l2 registration bugfix for si470x over i2c Added the call to v4l2_device_register() required to add a new radio device. Without this patch, it is impossible for the driver to load. This does not affect USB devices. Signed-off-by: Douglas Fischer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-i2c.c | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b3034f80163f..41709b24b28f 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -43,7 +43,6 @@ static const struct i2c_device_id si470x_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, si470x_i2c_id); - /************************************************************************** * Module Parameters **************************************************************************/ @@ -362,22 +361,43 @@ static int si470x_i2c_probe(struct i2c_client *client, mutex_init(&radio->lock); init_completion(&radio->completion); + retval = v4l2_device_register(&client->dev, &radio->v4l2_dev); + if (retval < 0) { + dev_err(&client->dev, "couldn't register v4l2_device\n"); + goto err_radio; + } + + v4l2_ctrl_handler_init(&radio->hdl, 2); + v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15); + if (radio->hdl.error) { + retval = radio->hdl.error; + dev_err(&client->dev, "couldn't register control\n"); + goto err_dev; + } + /* video device initialization */ radio->videodev = si470x_viddev_template; + radio->videodev.ctrl_handler = &radio->hdl; + radio->videodev.lock = &radio->lock; + radio->videodev.v4l2_dev = &radio->v4l2_dev; + radio->videodev.release = video_device_release_empty; video_set_drvdata(&radio->videodev, radio); /* power up : need 110ms */ radio->registers[POWERCFG] = POWERCFG_ENABLE; if (si470x_set_register(radio, POWERCFG) < 0) { retval = -EIO; - goto err_radio; + goto err_ctrl; } msleep(110); /* get device and chip versions */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; - goto err_radio; + goto err_ctrl; } dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[SI_CHIPID]); @@ -407,7 +427,7 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; - goto err_radio; + goto err_ctrl; } /* rds buffer configuration */ @@ -437,6 +457,10 @@ err_all: free_irq(client->irq, radio); err_rds: kfree(radio->buffer); +err_ctrl: + v4l2_ctrl_handler_free(&radio->hdl); +err_dev: + v4l2_device_unregister(&radio->v4l2_dev); err_radio: kfree(radio); err_initial: -- cgit From dd328275e98634931419fdc652e99ebaf71bdc71 Mon Sep 17 00:00:00 2001 From: Douglas Fischer Date: Fri, 2 Mar 2018 10:25:43 -0500 Subject: media: radio: Critical interrupt bugfix for si470x over i2c Fixed si470x_start() disabling the interrupt signal, causing tune operations to never complete. This does not affect USB radios because they poll the registers instead of using the IRQ line. Signed-off-by: Douglas Fischer [hans.verkuil@cisco.com: fixed 80 column checkpatch warning] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 8 ++++++-- drivers/media/radio/si470x/radio-si470x.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 6f0bf438be59..b94d66e53d4e 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -386,8 +386,12 @@ int si470x_start(struct si470x_device *radio) goto done; /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = - (de << 11) & SYSCONFIG1_DE; /* DE*/ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN | + SYSCONFIG1_RDS; + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; + radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT; + if (de) + radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE; retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) goto done; diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index eb7b834a0ae5..0202f8eb90c4 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -79,6 +79,8 @@ #define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ #define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ #define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ +#define SYSCONFIG1_GPIO2_DIS 0x0000 /* Disable GPIO 2 interrupt */ +#define SYSCONFIG1_GPIO2_INT 0x0004 /* Enable STC/RDS interrupt */ #define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ #define SYSCONFIG2 5 /* System Configuration 2 */ -- cgit From 3aab15af9ad8fa8dc0399cb4b679d7cb85c20a56 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 21 Feb 2018 02:49:25 -0500 Subject: media: add tuner standby op, use where needed The v4l2_subdev core s_power op was used for two different things: power on/off sensors or video decoders/encoders and to put a tuner in standby (and only the tuner!). There is no 'tuner wakeup' op, that's done automatically when the tuner is accessed. The danger with calling (s_power, 0) to put a tuner into standby is that it is usually broadcast for all subdevs. So a video receiver subdev that supports s_power will also be powered off, and since there is no corresponding (s_power, 1) they will never be powered on again. In addition, this is specifically meant for tuners only since they draw the most current. This patch adds a new tuner op called 'standby' and replaces all calls to (core, s_power, 0) by (tuner, standby). This prevents confusion between the two uses of s_power. Note that there is no overlap: bridge drivers either just want to put the tuner into standby, or they deal with powering on/off sensors. Never both. This also makes it easier to replace s_power for the remaining bridge drivers with some PM code later. Whether we want something cleaner for tuners in the future is a separate topic. There is a lot of legacy code surrounding tuners, and I am very hesitant about making changes there. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 2 +- drivers/media/pci/cx23885/cx23885-dvb.c | 4 ++-- drivers/media/pci/cx88/cx88-cards.c | 2 +- drivers/media/pci/cx88/cx88-dvb.c | 4 ++-- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/tuners/e4000.c | 16 +++------------- drivers/media/tuners/fc2580.c | 16 +++------------- drivers/media/tuners/msi001.c | 19 +++---------------- drivers/media/usb/au0828/au0828-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-video.c | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/v4l2-core/tuner-core.c | 15 +++------------ 12 files changed, 24 insertions(+), 66 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index ff369e90b848..019fac49db5b 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -983,7 +983,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_card_setup(dev); - call_all(dev, core, s_power, 0); + call_all(dev, tuner, standby); cx23885_ir_init(dev); if (dev->board == CX23885_BOARD_VIEWCAST_460E) { diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 7bb1febb1cb2..114d9bcbe4f4 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2568,8 +2568,8 @@ static int dvb_register(struct cx23885_tsport *port) fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; #endif - /* Put the analog decoder in standby to keep it quiet */ - call_all(dev, core, s_power, 0); + /* Put the tuner in standby to keep it quiet */ + call_all(dev, tuner, standby); if (fe0->dvb.frontend->ops.analog_ops.standby) fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 6df21b29ea17..4c92d2388c26 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -3592,7 +3592,7 @@ static void cx88_card_setup(struct cx88_core *core) ctl.fname); call_all(core, tuner, s_config, &xc2028_cfg); } - call_all(core, core, s_power, 0); + call_all(core, tuner, standby); } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index ec65eca713f9..2f886140dd2e 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1631,8 +1631,8 @@ static int dvb_register(struct cx8802_dev *dev) if (fe1) fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; - /* Put the analog decoder in standby to keep it quiet */ - call_all(core, core, s_power, 0); + /* Put the tuner in standby to keep it quiet */ + call_all(core, tuner, standby); /* register everything */ res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1ca6a32ad10e..4f1091a11e91 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1200,7 +1200,7 @@ static int video_release(struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - saa_call_all(dev, core, s_power, 0); + saa_call_all(dev, tuner, standby); if (vdev->vfl_type == VFL_TYPE_RADIO) saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd); mutex_unlock(&dev->lock); diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 564a000f503e..b5b9d87ba75c 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -293,28 +293,18 @@ static inline struct e4000_dev *e4000_subdev_to_dev(struct v4l2_subdev *sd) return container_of(sd, struct e4000_dev, sd); } -static int e4000_s_power(struct v4l2_subdev *sd, int on) +static int e4000_standby(struct v4l2_subdev *sd) { struct e4000_dev *dev = e4000_subdev_to_dev(sd); - struct i2c_client *client = dev->client; int ret; - dev_dbg(&client->dev, "on=%d\n", on); - - if (on) - ret = e4000_init(dev); - else - ret = e4000_sleep(dev); + ret = e4000_sleep(dev); if (ret) return ret; return e4000_set_params(dev); } -static const struct v4l2_subdev_core_ops e4000_subdev_core_ops = { - .s_power = e4000_s_power, -}; - static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct e4000_dev *dev = e4000_subdev_to_dev(sd); @@ -382,6 +372,7 @@ static int e4000_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { + .standby = e4000_standby, .g_tuner = e4000_g_tuner, .s_tuner = e4000_s_tuner, .g_frequency = e4000_g_frequency, @@ -390,7 +381,6 @@ static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = { }; static const struct v4l2_subdev_ops e4000_subdev_ops = { - .core = &e4000_subdev_core_ops, .tuner = &e4000_subdev_tuner_ops, }; diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index f4d4665de168..743184ae0d26 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -386,28 +386,18 @@ static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd) return container_of(sd, struct fc2580_dev, subdev); } -static int fc2580_s_power(struct v4l2_subdev *sd, int on) +static int fc2580_standby(struct v4l2_subdev *sd) { struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); - struct i2c_client *client = dev->client; int ret; - dev_dbg(&client->dev, "on=%d\n", on); - - if (on) - ret = fc2580_init(dev); - else - ret = fc2580_sleep(dev); + ret = fc2580_sleep(dev); if (ret) return ret; return fc2580_set_params(dev); } -static const struct v4l2_subdev_core_ops fc2580_subdev_core_ops = { - .s_power = fc2580_s_power, -}; - static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct fc2580_dev *dev = fc2580_subdev_to_dev(sd); @@ -475,6 +465,7 @@ static int fc2580_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = { + .standby = fc2580_standby, .g_tuner = fc2580_g_tuner, .s_tuner = fc2580_s_tuner, .g_frequency = fc2580_g_frequency, @@ -483,7 +474,6 @@ static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = { }; static const struct v4l2_subdev_ops fc2580_subdev_ops = { - .core = &fc2580_subdev_core_ops, .tuner = &fc2580_subdev_tuner_ops, }; diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index 3a12ef35682b..5de6ed728708 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -291,26 +291,13 @@ err: return ret; } -static int msi001_s_power(struct v4l2_subdev *sd, int on) +static int msi001_standby(struct v4l2_subdev *sd) { struct msi001_dev *dev = sd_to_msi001_dev(sd); - struct spi_device *spi = dev->spi; - int ret; - - dev_dbg(&spi->dev, "on=%d\n", on); - - if (on) - ret = 0; - else - ret = msi001_wreg(dev, 0x000000); - return ret; + return msi001_wreg(dev, 0x000000); } -static const struct v4l2_subdev_core_ops msi001_core_ops = { - .s_power = msi001_s_power, -}; - static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct msi001_dev *dev = sd_to_msi001_dev(sd); @@ -386,6 +373,7 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd, } static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = { + .standby = msi001_standby, .g_tuner = msi001_g_tuner, .s_tuner = msi001_s_tuner, .g_frequency = msi001_g_frequency, @@ -394,7 +382,6 @@ static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = { }; static const struct v4l2_subdev_ops msi001_ops = { - .core = &msi001_core_ops, .tuner = &msi001_tuner_ops, }; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index c765d546114d..964cd7bcdd2c 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1091,8 +1091,8 @@ static int au0828_v4l2_close(struct file *filp) */ ret = v4l_enable_media_source(vdev); if (ret == 0) - v4l2_device_call_all(&dev->v4l2_dev, 0, core, - s_power, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, + standby); dev->std_set_in_tuner_core = 0; /* When close the device, set the usb intf0 into alt0 to free diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 5b321b8ada3a..f7fcd733a2ca 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1941,7 +1941,7 @@ static int cx231xx_close(struct file *filp) } /* Save some power by putting tuner to sleep */ - call_all(dev, core, s_power, 0); + call_all(dev, tuner, standby); /* do this before setting alternate! */ if (dev->USE_ISO) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f31339727d3b..d70ee13cc52e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2257,7 +2257,7 @@ static int em28xx_v4l2_close(struct file *filp) goto exit; /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby); /* do this before setting alternate! */ em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -2810,7 +2810,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby); /* initialize videobuf2 stuff */ em28xx_vb2_setup(dev); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 82852f23a3b6..7f858c39753c 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1099,23 +1099,14 @@ static int tuner_s_radio(struct v4l2_subdev *sd) */ /** - * tuner_s_power - controls the power state of the tuner + * tuner_standby - places the tuner in standby mode * @sd: pointer to struct v4l2_subdev - * @on: a zero value puts the tuner to sleep, non-zero wakes it up */ -static int tuner_s_power(struct v4l2_subdev *sd, int on) +static int tuner_standby(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (on) { - if (t->standby && set_mode(t, t->mode) == 0) { - dprintk("Waking up tuner\n"); - set_freq(t, 0); - } - return 0; - } - dprintk("Putting tuner to sleep\n"); t->standby = true; if (analog_ops->standby) @@ -1328,10 +1319,10 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg) static const struct v4l2_subdev_core_ops tuner_core_ops = { .log_status = tuner_log_status, - .s_power = tuner_s_power, }; static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = { + .standby = tuner_standby, .s_radio = tuner_s_radio, .g_tuner = tuner_g_tuner, .s_tuner = tuner_s_tuner, -- cgit From 06aa8f3aa9c409a3973e6d338a771500fcee014c Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 27 Feb 2018 10:05:48 -0500 Subject: media: i2c: adv748x: Simplify regmap configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADV748x has identical map configurations for each register map. The duplication of each map can be simplified using a helper macro such that each map is represented on a single line. Define ADV748X_REGMAP_CONF for this purpose use it to create the tables. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 109 ++++++------------------------- 1 file changed, 20 insertions(+), 89 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index accaa70134fb..b01e407e42fa 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -35,96 +35,27 @@ * Register manipulation */ -static const struct regmap_config adv748x_regmap_cnf[] = { - { - .name = "io", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "dpll", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "cp", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "hdmi", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "edid", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "repeater", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "infoframe", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "cec", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "sdp", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - - { - .name = "txb", - .reg_bits = 8, - .val_bits = 8, - - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, - { - .name = "txa", - .reg_bits = 8, - .val_bits = 8, +#define ADV748X_REGMAP_CONF(n) \ +{ \ + .name = n, \ + .reg_bits = 8, \ + .val_bits = 8, \ + .max_register = 0xff, \ + .cache_type = REGCACHE_NONE, \ +} - .max_register = 0xff, - .cache_type = REGCACHE_NONE, - }, +static const struct regmap_config adv748x_regmap_cnf[] = { + ADV748X_REGMAP_CONF("io"), + ADV748X_REGMAP_CONF("dpll"), + ADV748X_REGMAP_CONF("cp"), + ADV748X_REGMAP_CONF("hdmi"), + ADV748X_REGMAP_CONF("edid"), + ADV748X_REGMAP_CONF("repeater"), + ADV748X_REGMAP_CONF("infoframe"), + ADV748X_REGMAP_CONF("cec"), + ADV748X_REGMAP_CONF("sdp"), + ADV748X_REGMAP_CONF("txa"), + ADV748X_REGMAP_CONF("txb"), }; static int adv748x_configure_regmap(struct adv748x_state *state, int region) -- cgit From 71569850e3242db475a15b5e2674bf2b6e81d1a7 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 27 Feb 2018 10:05:49 -0500 Subject: media: i2c: adv748x: Add missing CBUS page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADV748x has 12 pages mapped onto I2C addresses. In the existing implementation only 11 are mapped correctly in the page enumerations, which causes an off-by-one fault on pages above the infoframe definition due to a missing 'CBUS' page. This causes the address for the CEC, SDP, TXA, and TXB to be incorrectly programmed during the iterations in adv748x_initialise_clients(). Until now this has gone un-noticed due to the fact that following the creation of the clients - the device is reset and the addresses are reprogrammed in manually by the call to "adv748x_write_regs(state, adv748x_set_slave_address);" As part of moving to dynamic i2c address allocations repair this by providing the missing CBUS page definition. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 3 +++ drivers/media/i2c/adv748x/adv748x.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index b01e407e42fa..e712c74cff50 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -52,6 +52,7 @@ static const struct regmap_config adv748x_regmap_cnf[] = { ADV748X_REGMAP_CONF("edid"), ADV748X_REGMAP_CONF("repeater"), ADV748X_REGMAP_CONF("infoframe"), + ADV748X_REGMAP_CONF("cbus"), ADV748X_REGMAP_CONF("cec"), ADV748X_REGMAP_CONF("sdp"), ADV748X_REGMAP_CONF("txa"), @@ -89,6 +90,7 @@ static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = { ADV748X_I2C_EDID, ADV748X_I2C_REPEATER, ADV748X_I2C_INFOFRAME, + ADV748X_I2C_CBUS, ADV748X_I2C_CEC, ADV748X_I2C_SDP, ADV748X_I2C_TXB, @@ -352,6 +354,7 @@ static const struct adv748x_reg_value adv748x_set_slave_address[] = { {ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1}, {ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1}, {ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1}, + {ADV748X_PAGE_IO, 0xf9, ADV748X_I2C_CBUS << 1}, {ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1}, {ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1}, {ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1}, diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 6789e2f3bc8c..725662edc4b8 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -35,6 +35,7 @@ #define ADV748X_I2C_EDID 0x36 /* EDID Map */ #define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */ #define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */ +#define ADV748X_I2C_CBUS 0x30 /* CBUS MHL Map */ #define ADV748X_I2C_CEC 0x41 /* CEC Map */ #define ADV748X_I2C_SDP 0x79 /* SDP Map */ #define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */ @@ -48,6 +49,7 @@ enum adv748x_page { ADV748X_PAGE_EDID, ADV748X_PAGE_REPEATER, ADV748X_PAGE_INFOFRAME, + ADV748X_PAGE_CBUS, ADV748X_PAGE_CEC, ADV748X_PAGE_SDP, ADV748X_PAGE_TXB, -- cgit From 67537fe960e5f837436403b148fcc33a356aa4bb Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 27 Feb 2018 10:05:50 -0500 Subject: media: i2c: adv748x: Add support for i2c_new_secondary_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADV748x has twelve 256-byte maps that can be accessed via the main I2C ports. Each map has it own I2C address and acts as a standard slave device on the I2C bus. Allow a device tree node to override the default addresses so that address conflicts with other devices on the same bus may be resolved at the board description level. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 77 +++++++++++++++----------------- drivers/media/i2c/adv748x/adv748x.h | 14 ------ 2 files changed, 36 insertions(+), 55 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index e712c74cff50..6ca88daa0ecd 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -80,21 +80,24 @@ static int adv748x_configure_regmap(struct adv748x_state *state, int region) return 0; } +struct adv748x_register_map { + const char *name; + u8 default_addr; +}; -/* Default addresses for the I2C pages */ -static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = { - ADV748X_I2C_IO, - ADV748X_I2C_DPLL, - ADV748X_I2C_CP, - ADV748X_I2C_HDMI, - ADV748X_I2C_EDID, - ADV748X_I2C_REPEATER, - ADV748X_I2C_INFOFRAME, - ADV748X_I2C_CBUS, - ADV748X_I2C_CEC, - ADV748X_I2C_SDP, - ADV748X_I2C_TXB, - ADV748X_I2C_TXA, +static const struct adv748x_register_map adv748x_default_addresses[] = { + [ADV748X_PAGE_IO] = { "main", 0x70 }, + [ADV748X_PAGE_DPLL] = { "dpll", 0x26 }, + [ADV748X_PAGE_CP] = { "cp", 0x22 }, + [ADV748X_PAGE_HDMI] = { "hdmi", 0x34 }, + [ADV748X_PAGE_EDID] = { "edid", 0x36 }, + [ADV748X_PAGE_REPEATER] = { "repeater", 0x32 }, + [ADV748X_PAGE_INFOFRAME] = { "infoframe", 0x31 }, + [ADV748X_PAGE_CBUS] = { "cbus", 0x30 }, + [ADV748X_PAGE_CEC] = { "cec", 0x41 }, + [ADV748X_PAGE_SDP] = { "sdp", 0x79 }, + [ADV748X_PAGE_TXB] = { "txb", 0x48 }, + [ADV748X_PAGE_TXA] = { "txa", 0x4a }, }; static int adv748x_read_check(struct adv748x_state *state, @@ -143,15 +146,20 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, return regmap_raw_write(regmap, init_reg, val, val_len); } -static struct i2c_client *adv748x_dummy_client(struct adv748x_state *state, - u8 addr, u8 io_reg) +static int adv748x_set_slave_addresses(struct adv748x_state *state) { - struct i2c_client *client = state->client; + struct i2c_client *client; + unsigned int i; + u8 io_reg; + + for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { + io_reg = ADV748X_IO_SLAVE_ADDR_BASE + i; + client = state->i2c_clients[i]; - if (addr) - io_write(state, io_reg, addr << 1); + io_write(state, io_reg, client->addr << 1); + } - return i2c_new_dummy(client->adapter, io_read(state, io_reg) >> 1); + return 0; } static void adv748x_unregister_clients(struct adv748x_state *state) @@ -164,13 +172,15 @@ static void adv748x_unregister_clients(struct adv748x_state *state) static int adv748x_initialise_clients(struct adv748x_state *state) { - int i; + unsigned int i; int ret; for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { - state->i2c_clients[i] = - adv748x_dummy_client(state, adv748x_i2c_addresses[i], - ADV748X_IO_SLAVE_ADDR_BASE + i); + state->i2c_clients[i] = i2c_new_secondary_device( + state->client, + adv748x_default_addresses[i].name, + adv748x_default_addresses[i].default_addr); + if (state->i2c_clients[i] == NULL) { adv_err(state, "failed to create i2c client %u\n", i); return -ENOMEM; @@ -181,7 +191,7 @@ static int adv748x_initialise_clients(struct adv748x_state *state) return ret; } - return 0; + return adv748x_set_slave_addresses(state); } /** @@ -347,21 +357,6 @@ static const struct adv748x_reg_value adv748x_sw_reset[] = { {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; -static const struct adv748x_reg_value adv748x_set_slave_address[] = { - {ADV748X_PAGE_IO, 0xf3, ADV748X_I2C_DPLL << 1}, - {ADV748X_PAGE_IO, 0xf4, ADV748X_I2C_CP << 1}, - {ADV748X_PAGE_IO, 0xf5, ADV748X_I2C_HDMI << 1}, - {ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1}, - {ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1}, - {ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1}, - {ADV748X_PAGE_IO, 0xf9, ADV748X_I2C_CBUS << 1}, - {ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1}, - {ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1}, - {ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1}, - {ADV748X_PAGE_IO, 0xfd, ADV748X_I2C_TXA << 1}, - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; - /* Supported Formats For Script Below */ /* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { @@ -492,7 +487,7 @@ static int adv748x_reset(struct adv748x_state *state) if (ret < 0) return ret; - ret = adv748x_write_regs(state, adv748x_set_slave_address); + ret = adv748x_set_slave_addresses(state); if (ret < 0) return ret; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 725662edc4b8..65f83741277e 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -27,20 +27,6 @@ #ifndef _ADV748X_H_ #define _ADV748X_H_ -/* I2C slave addresses */ -#define ADV748X_I2C_IO 0x70 /* IO Map */ -#define ADV748X_I2C_DPLL 0x26 /* DPLL Map */ -#define ADV748X_I2C_CP 0x22 /* CP Map */ -#define ADV748X_I2C_HDMI 0x34 /* HDMI Map */ -#define ADV748X_I2C_EDID 0x36 /* EDID Map */ -#define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */ -#define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */ -#define ADV748X_I2C_CBUS 0x30 /* CBUS MHL Map */ -#define ADV748X_I2C_CEC 0x41 /* CEC Map */ -#define ADV748X_I2C_SDP 0x79 /* SDP Map */ -#define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */ -#define ADV748X_I2C_TXA 0x4a /* CSI-TXA Map */ - enum adv748x_page { ADV748X_PAGE_IO, ADV748X_PAGE_DPLL, -- cgit From be2068bf648fd47a042a25fe998a3c7456101ae6 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Tue, 13 Feb 2018 12:48:56 -0500 Subject: media: adv7604: Add support for i2c_new_secondary_device The ADV7604 has thirteen 256-byte maps that can be accessed via the main I2C ports. Each map has it own I2C address and acts as a standard slave device on the I2C bus. Allow a device tree node to override the default addresses so that address conflicts with other devices on the same bus may be resolved at the board description level. [Kieran: Re-adapted for mainline] Signed-off-by: Jean-Michel Hautbois Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 62 +++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index b2caaff945ab..cac2081e876e 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2722,6 +2722,27 @@ static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = { /* ----------------------------------------------------------------------- */ +struct adv76xx_register_map { + const char *name; + u8 default_addr; +}; + +static const struct adv76xx_register_map adv76xx_default_addresses[] = { + [ADV76XX_PAGE_IO] = { "main", 0x4c }, + [ADV7604_PAGE_AVLINK] = { "avlink", 0x42 }, + [ADV76XX_PAGE_CEC] = { "cec", 0x40 }, + [ADV76XX_PAGE_INFOFRAME] = { "infoframe", 0x3e }, + [ADV7604_PAGE_ESDP] = { "esdp", 0x38 }, + [ADV7604_PAGE_DPP] = { "dpp", 0x3c }, + [ADV76XX_PAGE_AFE] = { "afe", 0x26 }, + [ADV76XX_PAGE_REP] = { "rep", 0x32 }, + [ADV76XX_PAGE_EDID] = { "edid", 0x36 }, + [ADV76XX_PAGE_HDMI] = { "hdmi", 0x34 }, + [ADV76XX_PAGE_TEST] = { "test", 0x30 }, + [ADV76XX_PAGE_CP] = { "cp", 0x22 }, + [ADV7604_PAGE_VDP] = { "vdp", 0x24 }, +}; + static int adv76xx_core_init(struct v4l2_subdev *sd) { struct adv76xx_state *state = to_state(sd); @@ -2822,13 +2843,26 @@ static void adv76xx_unregister_clients(struct adv76xx_state *state) } static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd, - u8 addr, u8 io_reg) + unsigned int page) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv76xx_state *state = to_state(sd); + struct adv76xx_platform_data *pdata = &state->pdata; + unsigned int io_reg = 0xf2 + page; + struct i2c_client *new_client; + + if (pdata && pdata->i2c_addresses[page]) + new_client = i2c_new_dummy(client->adapter, + pdata->i2c_addresses[page]); + else + new_client = i2c_new_secondary_device(client, + adv76xx_default_addresses[page].name, + adv76xx_default_addresses[page].default_addr); - if (addr) - io_write(sd, io_reg, addr << 1); - return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); + if (new_client) + io_write(sd, io_reg, new_client->addr << 1); + + return new_client; } static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = { @@ -3103,20 +3137,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) /* Disable the interrupt for now as no DT-based board uses it. */ state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; - /* Use the default I2C addresses. */ - state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; - state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40; - state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e; - state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; - state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; - state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26; - state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32; - state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36; - state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34; - state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30; - state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22; - state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; - /* Hardcode the remaining platform data fields. */ state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; @@ -3466,11 +3486,9 @@ static int adv76xx_probe(struct i2c_client *client, if (!(BIT(i) & state->info->page_mask)) continue; - state->i2c_clients[i] = - adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], - 0xf2 + i); + state->i2c_clients[i] = adv76xx_dummy_client(sd, i); if (!state->i2c_clients[i]) { - err = -ENOMEM; + err = -EINVAL; v4l2_err(sd, "failed to create i2c client %u\n", i); goto err_i2c; } -- cgit From 20f2e1aa77314decf395558fd3a13875c0e56074 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Mar 2018 04:49:36 -0500 Subject: media: cpia2_usb: drop bogus interface-release call Drop bogus call to usb_driver_release_interface() from the disconnect() callback. As the interface is already being unbound at this point, usb_driver_release_interface() simply returns early. Signed-off-by: Johan Hovold Reviewed-by: Greg Kroah-Hartman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cpia2/cpia2_usb.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index f3a1e5b1e57c..b51fc372ca25 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -910,9 +910,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) wake_up_interruptible(&cam->wq_stream); } - DBG("Releasing interface\n"); - usb_driver_release_interface(&cpia2_driver, intf); - LOG("CPiA2 camera disconnected.\n"); } -- cgit From 8d7a77ce56cdb5f50b83ca0c59a31362e1a5eeb4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 8 Mar 2018 09:42:44 -0500 Subject: media: rc: meson-ir: add timeout on idle Meson doesn't seem to be able to generate timeout events in hardware. So install a software timer to generate the timeout events required by the decoders to prevent "ghost keypresses". Reported-by: Matthias Reichl Tested-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 3 +-- drivers/media/rc/rc-ir-raw.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index f2204eb77e2a..64b0aa4f4db7 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -97,8 +97,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) status = readl_relaxed(ir->reg + IR_DEC_STATUS); rawir.pulse = !!(status & STATUS_IR_DEC_IN); - ir_raw_event_store(ir->rc, &rawir); - ir_raw_event_handle(ir->rc); + ir_raw_event_store_with_timeout(ir->rc, &rawir); spin_unlock(&ir->lock); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 984bb82851f9..374f83105a23 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -92,7 +92,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) { ktime_t now; DEFINE_IR_RAW_EVENT(ev); - int rc = 0; if (!dev->raw) return -EINVAL; @@ -101,8 +100,33 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); ev.pulse = !pulse; + return ir_raw_event_store_with_timeout(dev, &ev); +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); + +/* + * ir_raw_event_store_with_timeout() - pass a pulse/space duration to the raw + * ir decoders, schedule decoding and + * timeout + * @dev: the struct rc_dev device descriptor + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This routine (which may be called from an interrupt context) stores a + * pulse/space duration for the raw ir decoding state machines, schedules + * decoding and generates a timeout. + */ +int ir_raw_event_store_with_timeout(struct rc_dev *dev, struct ir_raw_event *ev) +{ + ktime_t now; + int rc = 0; + + if (!dev->raw) + return -EINVAL; + + now = ktime_get(); + spin_lock(&dev->raw->edge_spinlock); - rc = ir_raw_event_store(dev, &ev); + rc = ir_raw_event_store(dev, ev); dev->raw->last_event = now; @@ -117,7 +141,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) return rc; } -EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); +EXPORT_SYMBOL_GPL(ir_raw_event_store_with_timeout); /** * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing -- cgit From b358e747aebc4a52f20732d569ec04c6bc15d008 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 12 Mar 2018 17:23:00 -0400 Subject: media: rc: meson-ir: lower timeout and make configurable A timeout of 200ms is much longer than necessary, and delays the decoding decoding of a single scancode and the last scancode when a button is being held. This makes the remote seem sluggish. If the min_timeout and max_timeout values are set, the timeout is configurable via the LIRC_SET_REC_TIMEOUT ioctl. Tested-by: Matthias Reichl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 64b0aa4f4db7..f449b35d25e7 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -144,7 +144,9 @@ static int meson_ir_probe(struct platform_device *pdev) ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); - ir->rc->timeout = MS_TO_NS(200); + ir->rc->min_timeout = 1; + ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ir->rc->driver_name = DRIVER_NAME; spin_lock_init(&ir->lock); -- cgit From 279c60fd896dcab4b4ae1016f62a7e75b19746d1 Mon Sep 17 00:00:00 2001 From: A Sun Date: Fri, 16 Mar 2018 15:52:09 -0400 Subject: media: mceusb: add IR learning support features (IR carrier frequency measurement and wide-band/short-range receiver) Windows Media Center IR transceivers include two IR receivers; wide-band/short-range and narrow-band/long-range. The short-range (5cm distance) receiver is for IR learning and has IR carrier frequency measuring ability. Add mceusb driver support to select the short range IR receiver and enable pass through of its IR carrier frequency measurements. RC and LIRC already support these mceusb driver additions. Test platform: Linux raspberrypi 4.9.59-v7+ #1047 SMP Sun Oct 29 12:19:23 GMT 2017 armv7l GNU/Linux mceusb 1-1.2:1.0: Registered Pinnacle Systems PCTV Remote USB with mce emulator interface version 1 mceusb 1-1.2:1.0: 2 tx ports (0x0 cabled) and 2 rx sensors (0x1 active) Sony TV remote control ir-ctl from v4l-utils pi@raspberrypi:~ $ ir-ctl -V IR raw version 1.12.3 pi@raspberrypi:~ $ ir-ctl -m -r ... pulse 650 space 550 pulse 650 space 600 pulse 600 space 600 pulse 1200 space 600 pulse 650 space 550 pulse 650 space 600 pulse 600 space 600 pulse 550 carrier 40004 space 16777215 ^C pi@raspberrypi:~ $ exit Signed-off-by: A Sun Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 152 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index a9187b0b46a1..f8c23d577493 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -42,7 +42,7 @@ #include #include -#define DRIVER_VERSION "1.93" +#define DRIVER_VERSION "1.94" #define DRIVER_AUTHOR "Jarod Wilson " #define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ "device driver" @@ -198,6 +198,13 @@ struct mceusb_model { u32 mce_gen3:1; u32 tx_mask_normal:1; u32 no_tx:1; + /* + * 2nd IR receiver (short-range, wideband) for learning mode: + * 0, absent 2nd receiver (rx2) + * 1, rx2 present + * 2, rx2 which under counts IR carrier cycles + */ + u32 rx2; int ir_intfnum; @@ -209,9 +216,11 @@ static const struct mceusb_model mceusb_model[] = { [MCE_GEN1] = { .mce_gen1 = 1, .tx_mask_normal = 1, + .rx2 = 2, }, [MCE_GEN2] = { .mce_gen2 = 1, + .rx2 = 2, }, [MCE_GEN2_NO_TX] = { .mce_gen2 = 1, @@ -220,10 +229,12 @@ static const struct mceusb_model mceusb_model[] = { [MCE_GEN2_TX_INV] = { .mce_gen2 = 1, .tx_mask_normal = 1, + .rx2 = 1, }, [MCE_GEN3] = { .mce_gen3 = 1, .tx_mask_normal = 1, + .rx2 = 2, }, [POLARIS_EVK] = { /* @@ -232,6 +243,7 @@ static const struct mceusb_model mceusb_model[] = { * to allow testing it */ .name = "Conexant Hybrid TV (cx231xx) MCE IR", + .rx2 = 2, }, [CX_HYBRID_TV] = { .no_tx = 1, /* tx isn't wired up at all */ @@ -244,10 +256,12 @@ static const struct mceusb_model mceusb_model[] = { [MULTIFUNCTION] = { .mce_gen2 = 1, .ir_intfnum = 2, + .rx2 = 2, }, [TIVO_KIT] = { .mce_gen2 = 1, .rc_map = RC_MAP_TIVO, + .rx2 = 2, }, [EVROMEDIA_FULL_HYBRID_FULLHD] = { .name = "Evromedia USB Full Hybrid Full HD", @@ -427,7 +441,8 @@ struct mceusb_dev { struct rc_dev *rc; /* optional features we can enable */ - bool learning_enabled; + bool carrier_report_enabled; + bool wideband_rx_enabled; /* aka learning mode, short-range rx */ /* core device bits */ struct device *dev; @@ -458,6 +473,7 @@ struct mceusb_dev { u32 tx_mask_normal:1; u32 microsoft_gen1:1; u32 no_tx:1; + u32 rx2; } flags; /* transmit support */ @@ -474,6 +490,11 @@ struct mceusb_dev { u8 num_rxports; /* number of receive sensors */ u8 txports_cabled; /* bitmask of transmitters with cable */ u8 rxports_active; /* bitmask of active receive sensors */ + bool learning_active; /* wideband rx is active */ + + /* receiver carrier frequency detection support */ + u32 pulse_tunit; /* IR pulse "on" cumulative time units */ + u32 pulse_count; /* pulse "on" count in measurement interval */ /* * support for async error handler mceusb_deferred_kevent() @@ -684,8 +705,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, /* aka MCE_RSP_EQIRRXCFCNT */ if (out) dev_dbg(dev, "Get receive sensor"); - else if (ir->learning_enabled) - dev_dbg(dev, "RX pulse count: %d", + else + dev_dbg(dev, "RX carrier cycle count: %d", ((data[0] << 8) | data[1])); break; case MCE_RSP_EQIRNUMPORTS: @@ -955,6 +976,67 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } +/* + * Select or deselect the 2nd receiver port. + * Second receiver is learning mode, wide-band, short-range receiver. + * Only one receiver (long or short range) may be active at a time. + */ +static int mceusb_set_rx_wideband(struct rc_dev *dev, int enable) +{ + struct mceusb_dev *ir = dev->priv; + unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR, + MCE_CMD_SETIRRXPORTEN, 0x00 }; + + dev_dbg(ir->dev, "select %s-range receive sensor", + enable ? "short" : "long"); + if (enable) { + ir->wideband_rx_enabled = true; + cmdbuf[2] = 2; /* port 2 is short range receiver */ + } else { + ir->wideband_rx_enabled = false; + cmdbuf[2] = 1; /* port 1 is long range receiver */ + } + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + /* response from device sets ir->learning_active */ + + return 0; +} + +/* + * Enable/disable receiver carrier frequency pass through reporting. + * Only the short-range receiver has carrier frequency measuring capability. + * Implicitly select this receiver when enabling carrier frequency reporting. + */ +static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable) +{ + struct mceusb_dev *ir = dev->priv; + unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR, + MCE_CMD_SETIRRXPORTEN, 0x00 }; + + dev_dbg(ir->dev, "%s short-range receiver carrier reporting", + enable ? "enable" : "disable"); + if (enable) { + ir->carrier_report_enabled = true; + if (!ir->learning_active) { + cmdbuf[2] = 2; /* port 2 is short range receiver */ + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + } + } else { + ir->carrier_report_enabled = false; + /* + * Revert to normal (long-range) receiver only if the + * wideband (short-range) receiver wasn't explicitly + * enabled. + */ + if (ir->learning_active && !ir->wideband_rx_enabled) { + cmdbuf[2] = 1; /* port 1 is long range receiver */ + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + } + } + + return 0; +} + /* * We don't do anything but print debug spew for many of the command bits * we receive from the hardware, but some of them are useful information @@ -962,8 +1044,11 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) */ static void mceusb_handle_command(struct mceusb_dev *ir, int index) { + DEFINE_IR_RAW_EVENT(rawir); u8 hi = ir->buf_in[index + 1] & 0xff; u8 lo = ir->buf_in[index + 2] & 0xff; + u32 carrier_cycles; + u32 cycles_fix; switch (ir->buf_in[index]) { /* the one and only 5-byte return value command */ @@ -980,6 +1065,33 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) ir->num_txports = hi; ir->num_rxports = lo; break; + case MCE_RSP_EQIRRXCFCNT: + /* + * The carrier cycle counter can overflow and wrap around + * without notice from the device. So frequency measurement + * will be inaccurate with long duration IR. + * + * The long-range (non learning) receiver always reports + * zero count so we always ignore its report. + */ + if (ir->carrier_report_enabled && ir->learning_active && + ir->pulse_tunit > 0) { + carrier_cycles = (hi << 8 | lo); + /* + * Adjust carrier cycle count by adding + * 1 missed count per pulse "on" + */ + cycles_fix = ir->flags.rx2 == 2 ? ir->pulse_count : 0; + rawir.carrier_report = 1; + rawir.carrier = (1000000u / MCE_TIME_UNIT) * + (carrier_cycles + cycles_fix) / + ir->pulse_tunit; + dev_dbg(ir->dev, "RX carrier frequency %u Hz (pulse count = %u, cycles = %u, duration = %u, rx2 = %u)", + rawir.carrier, ir->pulse_count, carrier_cycles, + ir->pulse_tunit, ir->flags.rx2); + ir_raw_event_store(ir->rc, &rawir); + } + break; /* 1-byte return value commands */ case MCE_RSP_EQEMVER: @@ -989,8 +1101,12 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) ir->tx_mask = hi; break; case MCE_RSP_EQIRRXPORTEN: - ir->learning_enabled = ((hi & 0x02) == 0x02); - ir->rxports_active = hi; + ir->learning_active = ((hi & 0x02) == 0x02); + if (ir->rxports_active != hi) { + dev_info(ir->dev, "%s-range (0x%x) receiver active", + ir->learning_active ? "short" : "long", hi); + ir->rxports_active = hi; + } break; case MCE_RSP_CMD_ILLEGAL: ir->need_reset = true; @@ -1027,12 +1143,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem--; init_ir_raw_event(&rawir); rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); - rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * US_TO_NS(MCE_TIME_UNIT); + rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK); + if (rawir.pulse) { + ir->pulse_tunit += rawir.duration; + ir->pulse_count++; + } + rawir.duration *= US_TO_NS(MCE_TIME_UNIT); - dev_dbg(ir->dev, "Storing %s with duration %u", + dev_dbg(ir->dev, "Storing %s %u ns (%02x)", rawir.pulse ? "pulse" : "space", - rawir.duration); + rawir.duration, ir->buf_in[i]); if (ir_raw_event_store_with_filter(ir->rc, &rawir)) event = true; @@ -1053,10 +1173,13 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); mceusb_dev_printdata(ir, ir->buf_in, buf_len, i, ir->rem + 1, false); - if (ir->rem) + if (ir->rem) { ir->parser_state = PARSE_IRDATA; - else + } else { ir_raw_event_reset(ir->rc); + ir->pulse_tunit = 0; + ir->pulse_count = 0; + } break; } @@ -1292,6 +1415,10 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->s_tx_carrier = mceusb_set_tx_carrier; rc->tx_ir = mceusb_tx_ir; } + if (ir->flags.rx2 > 0) { + rc->s_learning_mode = mceusb_set_rx_wideband; + rc->s_carrier_report = mceusb_set_rx_carrier_report; + } rc->driver_name = DRIVER_NAME; switch (le16_to_cpu(udev->descriptor.idVendor)) { @@ -1406,6 +1533,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, ir->flags.microsoft_gen1 = is_microsoft_gen1; ir->flags.tx_mask_normal = tx_mask_normal; ir->flags.no_tx = mceusb_model[model].no_tx; + ir->flags.rx2 = mceusb_model[model].rx2; ir->model = model; /* Saving usb interface data for use by the transmitter routine */ -- cgit From 35ecf2b4d24adf944b1cdce4941b3e82d0713111 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 18 Mar 2018 06:46:02 -0400 Subject: media: rc: mceusb: pid 0x0609 vid 0x031d does not under report carrier cycles This mceusb does not need the carrier count quirk, with it set it reports the carrier higher than it is. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index f8c23d577493..69ba57372c05 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -182,6 +182,7 @@ enum mceusb_model_type { MCE_GEN1, MCE_GEN3, MCE_GEN2_TX_INV, + MCE_GEN2_TX_INV_RX_GOOD, POLARIS_EVK, CX_HYBRID_TV, MULTIFUNCTION, @@ -231,6 +232,11 @@ static const struct mceusb_model mceusb_model[] = { .tx_mask_normal = 1, .rx2 = 1, }, + [MCE_GEN2_TX_INV_RX_GOOD] = { + .mce_gen2 = 1, + .tx_mask_normal = 1, + .rx2 = 2, + }, [MCE_GEN3] = { .mce_gen3 = 1, .tx_mask_normal = 1, @@ -304,7 +310,7 @@ static const struct usb_device_id mceusb_dev_table[] = { .driver_info = MULTIFUNCTION }, /* SMK/Toshiba G83C0004D410 */ { USB_DEVICE(VENDOR_SMK, 0x031d), - .driver_info = MCE_GEN2_TX_INV }, + .driver_info = MCE_GEN2_TX_INV_RX_GOOD }, /* SMK eHome Infrared Transceiver (Sony VAIO) */ { USB_DEVICE(VENDOR_SMK, 0x0322), .driver_info = MCE_GEN2_TX_INV }, -- cgit From 7903fbe3a636dbee04e5623931013feb80aab817 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 21 Jun 2017 11:02:42 -0400 Subject: media: af9013: change lock detection slightly Whilst rewritten largely, the basic logic remains same with one exception: do not return immediately on success case. We are going to add statistics that function and cannot return too early. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 55 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b8f3ebfc3e27..30cf837058da 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -752,45 +752,44 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; int ret; - unsigned int utmp; + unsigned int utmp, utmp1; /* * Return status from the cache if it is younger than 2000ms with the * exception of last tune is done during 4000ms. */ - if (time_is_after_jiffies( - state->read_status_jiffies + msecs_to_jiffies(2000)) && - time_is_before_jiffies( - state->set_frontend_jiffies + msecs_to_jiffies(4000)) - ) { - *status = state->fe_status; - return 0; + if (time_is_after_jiffies(state->read_status_jiffies + msecs_to_jiffies(2000)) && + time_is_before_jiffies(state->set_frontend_jiffies + msecs_to_jiffies(4000))) { + *status = state->fe_status; } else { - *status = 0; - } + /* MPEG2 lock */ + ret = regmap_read(state->regmap, 0xd507, &utmp); + if (ret) + goto err; - /* MPEG2 lock */ - ret = regmap_read(state->regmap, 0xd507, &utmp); - if (ret) - goto err; + if ((utmp >> 6) & 0x01) { + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else { + /* TPS lock */ + ret = regmap_read(state->regmap, 0xd330, &utmp); + if (ret) + goto err; - if ((utmp >> 6) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; + if ((utmp >> 3) & 0x01) + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + else + utmp1 = 0; + } - if (!*status) { - /* TPS lock */ - ret = regmap_read(state->regmap, 0xd330, &utmp); - if (ret) - goto err; + dev_dbg(&client->dev, "fe_status %02x\n", utmp1); - if ((utmp >> 3) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; - } + state->read_status_jiffies = jiffies; - state->fe_status = *status; - state->read_status_jiffies = jiffies; + state->fe_status = utmp1; + *status = utmp1; + } return 0; err: -- cgit From 943a720f5c5c970e3961ccbf43b94cdcb645696a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 18 Jun 2017 01:17:49 -0400 Subject: media: af9013: dvbv5 signal strength Implement dvbv5 signal strength estimate. We know tuner dependent -80dBm and -50dBm agc values, construct line equation and use it to map agc value to signal strength estimate. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 83 +++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 30cf837058da..4cb6371572c5 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -41,8 +41,11 @@ struct af9013_state { u16 snr; u32 bandwidth_hz; enum fe_status fe_status; + /* RF and IF AGC limits used for signal strength calc */ + u8 strength_en, rf_agc_50, rf_agc_80, if_agc_50, if_agc_80; unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; + unsigned long strength_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -751,8 +754,12 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; - int ret; - unsigned int utmp, utmp1; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, stmp1; + unsigned int utmp, utmp1, utmp2, utmp3, utmp4; + u8 buf[2]; + + dev_dbg(&client->dev, "\n"); /* * Return status from the cache if it is younger than 2000ms with the @@ -791,6 +798,77 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) *status = utmp1; } + /* Signal strength */ + switch (state->strength_en) { + case 0: + /* Check if we support signal strength */ + ret = regmap_read(state->regmap, 0x9bee, &utmp); + if (ret) + goto err; + + if ((utmp >> 0) & 0x01) { + /* Read agc values for signal strength estimation */ + ret = regmap_read(state->regmap, 0x9bbd, &utmp1); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9bd0, &utmp2); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be2, &utmp3); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be4, &utmp4); + if (ret) + goto err; + + state->rf_agc_50 = utmp1; + state->rf_agc_80 = utmp2; + state->if_agc_50 = utmp3; + state->if_agc_80 = utmp4; + dev_dbg(&client->dev, + "rf_agc_50 %u, rf_agc_80 %u, if_agc_50 %u, if_agc_80 %u\n", + utmp1, utmp2, utmp3, utmp4); + + state->strength_en = 1; + } else { + /* Signal strength is not supported */ + state->strength_en = 2; + break; + } + /* Fall through */ + case 1: + if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000))) + break; + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); + if (ret) + goto err; + + /* + * Construct line equation from tuner dependent -80/-50 dBm agc + * limits and use it to map current agc value to dBm estimate + */ + #define agc_gain (buf[0] + buf[1]) + #define agc_gain_50dbm (state->rf_agc_50 + state->if_agc_50) + #define agc_gain_80dbm (state->rf_agc_80 + state->if_agc_80) + stmp1 = 30000 * (agc_gain - agc_gain_80dbm) / + (agc_gain_50dbm - agc_gain_80dbm) - 80000; + + dev_dbg(&client->dev, + "strength %d, agc_gain %d, agc_gain_50dbm %d, agc_gain_80dbm %d\n", + stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm); + + state->strength_jiffies = jiffies; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = stmp1; + break; + default: + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -1512,6 +1590,7 @@ static int af9013_probe(struct i2c_client *client, /* Init stats to indicate which stats are supported */ c = &state->fe.dtv_property_cache; + c->strength.len = 1; c->cnr.len = 1; dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); -- cgit From f3bb7e22b1854e7295800bd30b4ae08e5b69e3c3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 18 Jun 2017 06:23:15 -0400 Subject: media: af9013: dvbv5 cnr Implement dvbv5 cnr. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 88 +++++++++++++++++++++++++++++-- drivers/media/dvb-frontends/af9013_priv.h | 1 + 2 files changed, 84 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 4cb6371572c5..b3d08e437478 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -46,6 +46,7 @@ struct af9013_state { unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; unsigned long strength_jiffies; + unsigned long cnr_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -179,7 +180,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; unsigned int utmp; u8 buf[3]; @@ -235,9 +235,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ - c->cnr.stat[0].svalue = 1000 * utmp; - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -757,7 +754,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, stmp1; unsigned int utmp, utmp1, utmp2, utmp3, utmp4; - u8 buf[2]; + u8 buf[3]; dev_dbg(&client->dev, "\n"); @@ -869,6 +866,87 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) break; } + /* CNR */ + switch (state->fe_status & FE_HAS_VITERBI) { + case FE_HAS_VITERBI: + if (time_is_after_jiffies(state->cnr_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if cnr ready */ + ret = regmap_read(state->regmap, 0xd2e1, &utmp); + if (ret) + goto err; + + if (!((utmp >> 3) & 0x01)) { + dev_dbg(&client->dev, "cnr not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); + if (ret) + goto err; + + utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; + + /* Read current modulation */ + ret = regmap_read(state->regmap, 0xd3c1, &utmp); + if (ret) + goto err; + + switch ((utmp >> 6) & 3) { + case 0: + /* + * QPSK + * CNR[dB] 13 * -log10((1690000 - value) / value) + 2.6 + * value [653799, 1689999], 2.6 / 13 = 3355443 + */ + utmp1 = clamp(utmp1, 653799U, 1689999U); + utmp1 = ((u64)(intlog10(utmp1) + - intlog10(1690000 - utmp1) + + 3355443) * 13 * 1000) >> 24; + break; + case 1: + /* + * QAM-16 + * CNR[dB] 6 * log10((value - 370000) / (828000 - value)) + 15.7 + * value [371105, 827999], 15.7 / 6 = 43900382 + */ + utmp1 = clamp(utmp1, 371105U, 827999U); + utmp1 = ((u64)(intlog10(utmp1 - 370000) + - intlog10(828000 - utmp1) + + 43900382) * 6 * 1000) >> 24; + break; + case 2: + /* + * QAM-64 + * CNR[dB] 8 * log10((value - 193000) / (425000 - value)) + 23.8 + * value [193246, 424999], 23.8 / 8 = 49912218 + */ + utmp1 = clamp(utmp1, 193246U, 424999U); + utmp1 = ((u64)(intlog10(utmp1 - 193000) + - intlog10(425000 - utmp1) + + 49912218) * 8 * 1000) >> 24; + break; + default: + dev_dbg(&client->dev, "invalid modulation %u\n", + (utmp >> 6) & 3); + utmp1 = 0; + break; + } + + dev_dbg(&client->dev, "cnr %u\n", utmp1); + + state->cnr_jiffies = jiffies; + + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = utmp1; + break; + default: + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 688fc3472cf6..9c3cb04e3494 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -22,6 +22,7 @@ #define AF9013_PRIV_H #include +#include #include "af9013.h" #include #include -- cgit From 233f3ef71c1abc2f5577e4617c76f4f3168ddd6e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 18 Jun 2017 13:26:35 -0400 Subject: media: af9013: dvbv5 ber and per Implement dvbv5 ber and per. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 73 +++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b3d08e437478..a054e39510e0 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -47,6 +47,7 @@ struct af9013_state { unsigned long read_status_jiffies; unsigned long strength_jiffies; unsigned long cnr_jiffies; + unsigned long ber_ucb_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -754,7 +755,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, stmp1; unsigned int utmp, utmp1, utmp2, utmp3, utmp4; - u8 buf[3]; + u8 buf[7]; dev_dbg(&client->dev, "\n"); @@ -947,6 +948,72 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) break; } + /* BER / PER */ + switch (state->fe_status & FE_HAS_SYNC) { + case FE_HAS_SYNC: + if (time_is_after_jiffies(state->ber_ucb_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if ber / ucb is ready */ + ret = regmap_read(state->regmap, 0xd391, &utmp); + if (ret) + goto err; + + if (!((utmp >> 4) & 0x01)) { + dev_dbg(&client->dev, "ber not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd385, buf, 7); + if (ret) + goto err; + + utmp1 = buf[4] << 16 | buf[3] << 8 | buf[2] << 0; + utmp2 = (buf[1] << 8 | buf[0] << 0) * 204 * 8; + utmp3 = buf[6] << 8 | buf[5] << 0; + utmp4 = buf[1] << 8 | buf[0] << 0; + + /* Use 10000 TS packets for measure */ + if (utmp4 != 10000) { + buf[0] = (10000 >> 0) & 0xff; + buf[1] = (10000 >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); + if (ret) + goto err; + } + + /* Reset ber / ucb counter */ + ret = regmap_update_bits(state->regmap, 0xd391, 0x20, 0x20); + if (ret) + goto err; + + dev_dbg(&client->dev, "post_bit_error %u, post_bit_count %u\n", + utmp1, utmp2); + dev_dbg(&client->dev, "block_error %u, block_count %u\n", + utmp3, utmp4); + + state->ber_ucb_jiffies = jiffies; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += utmp1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += utmp2; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += utmp3; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += utmp4; + break; + default: + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -1670,6 +1737,10 @@ static int af9013_probe(struct i2c_client *client, c = &state->fe.dtv_property_cache; c->strength.len = 1; c->cnr.len = 1; + c->post_bit_error.len = 1; + c->post_bit_count.len = 1; + c->block_error.len = 1; + c->block_count.len = 1; dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", -- cgit From b911fc89e12c0cfc47e7501e7e1d930c98d403a9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 19 Jun 2017 02:31:56 -0400 Subject: media: af9013: wrap dvbv3 statistics via dvbv5 Driver has calculated dvbv5 statistics, so use those as a base for legacy dvbv3 statistics. Wrap and convert needed values to dvbv3, remove old dvbv3 statistic implementations. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 306 +++--------------------------- drivers/media/dvb-frontends/af9013_priv.h | 68 ------- 2 files changed, 22 insertions(+), 352 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a054e39510e0..e81dc827e1b8 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -33,12 +33,6 @@ struct af9013_state { u8 api_version[4]; u8 gpio[4]; - /* tuner/demod RF and IF AGC limits used for signal strength calc */ - u8 signal_strength_en, rf_50, rf_80, if_50, if_80; - u16 signal_strength; - u32 ber; - u32 ucblocks; - u16 snr; u32 bandwidth_hz; enum fe_status fe_status; /* RF and IF AGC limits used for signal strength calc */ @@ -48,10 +42,12 @@ struct af9013_state { unsigned long strength_jiffies; unsigned long cnr_jiffies; unsigned long ber_ucb_jiffies; + u16 dvbv3_snr; + u16 dvbv3_strength; + u32 dvbv3_ber; + u32 dvbv3_ucblocks; bool first_tune; bool i2c_gate_state; - unsigned int statistics_step:3; - struct delayed_work statistics_work; }; static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) @@ -106,228 +102,6 @@ err: return ret; } -static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* reset and start BER counter */ - ret = regmap_update_bits(state->regmap, 0xd391, 0x10, 0x10); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - unsigned int utmp; - u8 buf[5]; - - dev_dbg(&client->dev, "\n"); - - /* check if error bit count is ready */ - ret = regmap_read(state->regmap, 0xd391, &utmp); - if (ret) - goto err; - - if (!((utmp >> 4) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - ret = regmap_bulk_read(state->regmap, 0xd387, buf, 5); - if (ret) - goto err; - - state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - state->ucblocks += (buf[4] << 8) | buf[3]; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* start SNR meas */ - ret = regmap_update_bits(state->regmap, 0xd2e1, 0x08, 0x08); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret, i, len; - unsigned int utmp; - u8 buf[3]; - u32 snr_val; - const struct af9013_snr *uninitialized_var(snr_lut); - - dev_dbg(&client->dev, "\n"); - - /* check if SNR ready */ - ret = regmap_read(state->regmap, 0xd2e1, &utmp); - if (ret) - goto err; - - if (!((utmp >> 3) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - /* read value */ - ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); - if (ret) - goto err; - - snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - - /* read current modulation */ - ret = regmap_read(state->regmap, 0xd3c1, &utmp); - if (ret) - goto err; - - switch ((utmp >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_lut); - snr_lut = qpsk_snr_lut; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_lut); - snr_lut = qam16_snr_lut; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_lut); - snr_lut = qam64_snr_lut; - break; - default: - goto err; - } - - for (i = 0; i < len; i++) { - utmp = snr_lut[i].snr; - - if (snr_val < snr_lut[i].val) - break; - } - state->snr = utmp * 10; /* dB/10 */ - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_signal_strength(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret = 0; - u8 buf[2], rf_gain, if_gain; - int signal_strength; - - dev_dbg(&client->dev, "\n"); - - if (!state->signal_strength_en) - return 0; - - ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); - if (ret) - goto err; - - rf_gain = buf[0]; - if_gain = buf[1]; - - signal_strength = (0xffff / \ - (9 * (state->rf_50 + state->if_50) - \ - 11 * (state->rf_80 + state->if_80))) * \ - (10 * (rf_gain + if_gain) - \ - 11 * (state->rf_80 + state->if_80)); - if (signal_strength < 0) - signal_strength = 0; - else if (signal_strength > 0xffff) - signal_strength = 0xffff; - - state->signal_strength = signal_strength; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static void af9013_statistics_work(struct work_struct *work) -{ - struct af9013_state *state = container_of(work, - struct af9013_state, statistics_work.work); - unsigned int next_msec; - - /* update only signal strength when demod is not locked */ - if (!(state->fe_status & FE_HAS_LOCK)) { - state->statistics_step = 0; - state->ber = 0; - state->snr = 0; - } - - switch (state->statistics_step) { - default: - state->statistics_step = 0; - /* fall-through */ - case 0: - af9013_statistics_signal_strength(&state->fe); - state->statistics_step++; - next_msec = 300; - break; - case 1: - af9013_statistics_snr_start(&state->fe); - state->statistics_step++; - next_msec = 200; - break; - case 2: - af9013_statistics_ber_unc_start(&state->fe); - state->statistics_step++; - next_msec = 1000; - break; - case 3: - af9013_statistics_snr_result(&state->fe); - state->statistics_step++; - next_msec = 400; - break; - case 4: - af9013_statistics_ber_unc_result(&state->fe); - state->statistics_step++; - next_msec = 100; - break; - } - - schedule_delayed_work(&state->statistics_work, - msecs_to_jiffies(next_msec)); -} - static int af9013_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *fesettings) { @@ -858,6 +632,9 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm); state->strength_jiffies = jiffies; + /* Convert [-90, -30] dBm to [0x0000, 0xffff] for dvbv3 */ + utmp1 = clamp(stmp1 + 90000, 0, 60000); + state->dvbv3_strength = div_u64((u64)utmp1 * 0xffff, 60000); c->strength.stat[0].scale = FE_SCALE_DECIBEL; c->strength.stat[0].svalue = stmp1; @@ -939,6 +716,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) dev_dbg(&client->dev, "cnr %u\n", utmp1); state->cnr_jiffies = jiffies; + state->dvbv3_snr = utmp1 / 100; c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = utmp1; @@ -994,6 +772,8 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) utmp3, utmp4); state->ber_ucb_jiffies = jiffies; + state->dvbv3_ber = utmp1; + state->dvbv3_ucblocks += utmp3; c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[0].uvalue += utmp1; @@ -1023,28 +803,36 @@ err: static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9013_state *state = fe->demodulator_priv; - *snr = state->snr; + + *snr = state->dvbv3_snr; + return 0; } static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct af9013_state *state = fe->demodulator_priv; - *strength = state->signal_strength; + + *strength = state->dvbv3_strength; + return 0; } static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9013_state *state = fe->demodulator_priv; - *ber = state->ber; + + *ber = state->dvbv3_ber; + return 0; } static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct af9013_state *state = fe->demodulator_priv; - *ucblocks = state->ucblocks; + + *ucblocks = state->dvbv3_ucblocks; + return 0; } @@ -1194,50 +982,7 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* check if we support signal strength */ - if (!state->signal_strength_en) { - ret = regmap_read(state->regmap, 0x9bee, &utmp); - if (ret) - goto err; - - state->signal_strength_en = (utmp >> 0) & 0x01; - } - - /* read values needed for signal strength calculation */ - if (state->signal_strength_en && !state->rf_50) { - ret = regmap_bulk_read(state->regmap, 0x9bbd, &state->rf_50, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9bd0, &state->rf_80, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9be2, &state->if_50, 1); - if (ret) - goto err; - ret = regmap_bulk_read(state->regmap, 0x9be4, &state->if_80, 1); - if (ret) - goto err; - } - - /* SNR */ - ret = regmap_write(state->regmap, 0xd2e2, 0x01); - if (ret) - goto err; - - /* BER / UCB */ - buf[0] = (10000 >> 0) & 0xff; - buf[1] = (10000 >> 8) & 0xff; - ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); - if (ret) - goto err; - - /* enable FEC monitor */ - ret = regmap_update_bits(state->regmap, 0xd392, 0x02, 0x02); - if (ret) - goto err; - state->first_tune = true; - schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400)); return 0; err: @@ -1254,9 +999,6 @@ static int af9013_sleep(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); - /* stop statistics polling */ - cancel_delayed_work_sync(&state->statistics_work); - /* disable lock led */ ret = regmap_update_bits(state->regmap, 0xd730, 0x01, 0x00); if (ret) @@ -1696,7 +1438,6 @@ static int af9013_probe(struct i2c_client *client, state->spec_inv = pdata->spec_inv; memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version)); memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio)); - INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work); state->regmap = regmap_init(&client->dev, ®map_bus, client, ®map_config); if (IS_ERR(state->regmap)) { @@ -1762,9 +1503,6 @@ static int af9013_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - /* Stop statistics polling */ - cancel_delayed_work_sync(&state->statistics_work); - regmap_exit(state->regmap); kfree(state); diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 9c3cb04e3494..64f39d3db694 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -37,11 +37,6 @@ struct af9013_reg_bit { u8 val; }; -struct af9013_snr { - u32 val; - u8 snr; -}; - struct af9013_coeff { u32 clock; u32 bandwidth_hz; @@ -92,69 +87,6 @@ static const struct af9013_coeff coeff_lut[] = { 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, }; -/* QPSK SNR lookup table */ -static const struct af9013_snr qpsk_snr_lut[] = { - { 0x000000, 0 }, - { 0x0b4771, 0 }, - { 0x0c1aed, 1 }, - { 0x0d0d27, 2 }, - { 0x0e4d19, 3 }, - { 0x0e5da8, 4 }, - { 0x107097, 5 }, - { 0x116975, 6 }, - { 0x1252d9, 7 }, - { 0x131fa4, 8 }, - { 0x13d5e1, 9 }, - { 0x148e53, 10 }, - { 0x15358b, 11 }, - { 0x15dd29, 12 }, - { 0x168112, 13 }, - { 0x170b61, 14 }, - { 0xffffff, 15 }, -}; - -/* QAM16 SNR lookup table */ -static const struct af9013_snr qam16_snr_lut[] = { - { 0x000000, 0 }, - { 0x05eb62, 5 }, - { 0x05fecf, 6 }, - { 0x060b80, 7 }, - { 0x062501, 8 }, - { 0x064865, 9 }, - { 0x069604, 10 }, - { 0x06f356, 11 }, - { 0x07706a, 12 }, - { 0x0804d3, 13 }, - { 0x089d1a, 14 }, - { 0x093e3d, 15 }, - { 0x09e35d, 16 }, - { 0x0a7c3c, 17 }, - { 0x0afaf8, 18 }, - { 0x0b719d, 19 }, - { 0xffffff, 20 }, -}; - -/* QAM64 SNR lookup table */ -static const struct af9013_snr qam64_snr_lut[] = { - { 0x000000, 0 }, - { 0x03109b, 12 }, - { 0x0310d4, 13 }, - { 0x031920, 14 }, - { 0x0322d0, 15 }, - { 0x0339fc, 16 }, - { 0x0364a1, 17 }, - { 0x038bcc, 18 }, - { 0x03c7d3, 19 }, - { 0x0408cc, 20 }, - { 0x043bed, 21 }, - { 0x048061, 22 }, - { 0x04be95, 23 }, - { 0x04fa7d, 24 }, - { 0x052405, 25 }, - { 0x05570d, 26 }, - { 0xffffff, 27 }, -}; - static const struct af9013_reg_bit ofsm_init[] = { { 0xd73a, 0, 8, 0xa1 }, { 0xd73b, 0, 8, 0x1f }, -- cgit From 49bade9f0eef207186b240e70d1eab418e4f1678 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 21 Jun 2017 16:55:54 -0400 Subject: media: af9015: fix logging Pass correct device to dev_* logging functions, which allows us to remove redundant KBUILD_MODNAME and __func__ parameters from log format. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 160 +++++++++++++++++----------------- 1 file changed, 81 insertions(+), 79 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8013659c41b1..7e4cce05b911 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -29,6 +29,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret, wlen, rlen; u8 write = 1; @@ -66,8 +67,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) case BOOT: break; default: - dev_err(&d->udev->dev, "%s: unknown command=%d\n", - KBUILD_MODNAME, req->cmd); + dev_err(&intf->dev, "unknown cmd %d\n", req->cmd); ret = -EIO; goto error; } @@ -75,8 +75,8 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) /* buffer overflow check */ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - dev_err(&d->udev->dev, "%s: too much data; cmd=%d len=%d\n", - KBUILD_MODNAME, req->cmd, req->data_len); + dev_err(&intf->dev, "too much data, cmd %u, len %u\n", + req->cmd, req->data_len); ret = -EINVAL; goto error; } @@ -103,8 +103,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) /* check status */ if (rlen && state->buf[1]) { - dev_err(&d->udev->dev, "%s: command failed=%d\n", - KBUILD_MODNAME, state->buf[1]); + dev_err(&intf->dev, "cmd failed %u\n", state->buf[1]); ret = -EIO; goto error; } @@ -206,6 +205,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u16 addr; u8 mbox, addr_len; @@ -307,15 +307,14 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = af9015_ctrl_msg(d, &req); } else { ret = -EOPNOTSUPP; - dev_dbg(&d->udev->dev, "%s: unknown msg, num %u\n", - __func__, num); + dev_dbg(&intf->dev, "unknown msg, num %u\n", num); } if (ret) goto err; return num; err: - dev_dbg(&d->udev->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } @@ -331,6 +330,7 @@ static struct i2c_algorithm af9015_i2c_algo = { static int af9015_identify_state(struct dvb_usb_device *d, const char **name) { + struct usb_interface *intf = d->intf; int ret; u8 reply; struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; @@ -339,7 +339,7 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) if (ret) return ret; - dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply); + dev_dbg(&intf->dev, "reply %02x\n", reply); if (reply == 0x02) ret = WARM; @@ -353,10 +353,12 @@ static int af9015_download_firmware(struct dvb_usb_device *d, const struct firmware *fw) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int i, len, remaining, ret; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; u16 checksum = 0; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); /* calc checksum */ for (i = 0; i < fw->size; i++) @@ -378,9 +380,8 @@ static int af9015_download_firmware(struct dvb_usb_device *d, ret = af9015_ctrl_msg(d, &req); if (ret) { - dev_err(&d->udev->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "firmware download failed %d\n", + ret); goto error; } } @@ -390,8 +391,7 @@ static int af9015_download_firmware(struct dvb_usb_device *d, req.data_len = 0; ret = af9015_ctrl_msg(d, &req); if (ret) { - dev_err(&d->udev->dev, "%s: firmware boot failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "firmware boot failed %d\n", ret); goto error; } @@ -407,6 +407,7 @@ error: static int af9015_eeprom_hash(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret, i; u8 buf[AF9015_EEPROM_SIZE]; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL}; @@ -427,24 +428,24 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d) } for (i = 0; i < AF9015_EEPROM_SIZE; i += 16) - dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 16, buf + i); + dev_dbg(&intf->dev, "%*ph\n", 16, buf + i); - dev_dbg(&d->udev->dev, "%s: eeprom sum=%.8x\n", - __func__, state->eeprom_sum); + dev_dbg(&intf->dev, "eeprom sum %.8x\n", state->eeprom_sum); return 0; err: - dev_err(&d->udev->dev, "%s: eeprom failed=%d\n", KBUILD_MODNAME, ret); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } static int af9015_read_config(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u8 val, i, offset = 0; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&intf->dev, "\n"); /* IR remote controller */ req.addr = AF9015_EEPROM_IR_MODE; @@ -462,7 +463,7 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; state->ir_mode = val; - dev_dbg(&d->udev->dev, "%s: IR mode=%d\n", __func__, val); + dev_dbg(&intf->dev, "ir mode %02x\n", val); /* TS mode - one or two receivers */ req.addr = AF9015_EEPROM_TS_MODE; @@ -471,7 +472,7 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; state->dual_mode = val; - dev_dbg(&d->udev->dev, "%s: TS mode=%d\n", __func__, state->dual_mode); + dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode); /* disable 2nd adapter because we don't have PID-filters */ if (d->udev->speed == USB_SPEED_FULL) @@ -511,9 +512,8 @@ static int af9015_read_config(struct dvb_usb_device *d) state->af9013_config[i].clock = 25000000; break; } - dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n", - __func__, i, val, - state->af9013_config[i].clock); + dev_dbg(&intf->dev, "[%d] xtal %02x, clock %u\n", + i, val, state->af9013_config[i].clock); /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; @@ -530,8 +530,8 @@ static int af9015_read_config(struct dvb_usb_device *d) state->af9013_config[i].if_frequency += val; state->af9013_config[i].if_frequency *= 1000; - dev_dbg(&d->udev->dev, "%s: [%d] IF frequency=%d\n", __func__, - i, state->af9013_config[i].if_frequency); + dev_dbg(&intf->dev, "[%d] if frequency %u\n", + i, state->af9013_config[i].if_frequency); /* MT2060 IF1 */ req.addr = AF9015_EEPROM_MT2060_IF1H + offset; @@ -544,8 +544,8 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; state->mt2060_if1[i] += val; - dev_dbg(&d->udev->dev, "%s: [%d] MT2060 IF1=%d\n", __func__, i, - state->mt2060_if1[i]); + dev_dbg(&intf->dev, "[%d] MT2060 IF1 %u\n", + i, state->mt2060_if1[i]); /* tuner */ req.addr = AF9015_EEPROM_TUNER_ID1 + offset; @@ -574,21 +574,19 @@ static int af9015_read_config(struct dvb_usb_device *d) state->af9013_config[i].spec_inv = 1; break; default: - dev_err(&d->udev->dev, "%s: tuner id=%d not " \ - "supported, please report!\n", - KBUILD_MODNAME, val); + dev_err(&intf->dev, + "tuner id %02x not supported, please report!\n", + val); return -ENODEV; } state->af9013_config[i].tuner = val; - dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n", - __func__, i, val); + dev_dbg(&intf->dev, "[%d] tuner id %02x\n", i, val); } error: if (ret) - dev_err(&d->udev->dev, "%s: eeprom read failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "eeprom read failed %d\n", ret); /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM content :-( Override some wrong values here. Ditto for the @@ -598,9 +596,7 @@ error: USB_PID_AVERMEDIA_A850) || (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) { - dev_dbg(&d->udev->dev, - "%s: AverMedia A850: overriding config\n", - __func__); + dev_dbg(&intf->dev, "AverMedia A850: overriding config\n"); /* disable dual mode */ state->dual_mode = 0; @@ -615,7 +611,9 @@ static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, struct usb_data_stream_properties *stream) { struct dvb_usb_device *d = fe_to_d(fe); - dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id); + struct usb_interface *intf = d->intf; + + dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id); if (d->udev->speed == USB_SPEED_FULL) stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; @@ -729,12 +727,14 @@ static int af9015_tuner_sleep(struct dvb_frontend *fe) static int af9015_copy_firmware(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u8 fw_params[4]; u8 val, i; struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), fw_params }; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); fw_params[0] = state->firmware_size >> 8; fw_params[1] = state->firmware_size & 0xff; @@ -746,8 +746,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) if (ret) goto error; else - dev_dbg(&d->udev->dev, "%s: firmware status=%02x\n", - __func__, val); + dev_dbg(&intf->dev, "firmware status %02x\n", val); if (val == 0x0c) /* fw is running, no need for download */ goto exit; @@ -762,10 +761,9 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) /* copy firmware */ ret = af9015_ctrl_msg(d, &req); if (ret) - dev_err(&d->udev->dev, "%s: firmware copy cmd failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret); - dev_dbg(&d->udev->dev, "%s: firmware copy done\n", __func__); + dev_dbg(&intf->dev, "firmware copy done\n"); /* set I2C master clock back to normal */ ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ @@ -775,8 +773,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) /* request boot firmware */ ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, 0xe205, 1); - dev_dbg(&d->udev->dev, "%s: firmware boot cmd status=%d\n", - __func__, ret); + dev_dbg(&intf->dev, "firmware boot cmd status %d\n", ret); if (ret) goto error; @@ -786,8 +783,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) /* check firmware status */ ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, 0x98be, &val); - dev_dbg(&d->udev->dev, "%s: firmware status cmd status=%d " \ - "firmware status=%02x\n", __func__, ret, val); + dev_dbg(&intf->dev, "firmware status cmd status %d, firmware status %02x\n", + ret, val); if (ret) goto error; @@ -796,13 +793,11 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) } if (val == 0x04) { - dev_err(&d->udev->dev, "%s: firmware did not run\n", - KBUILD_MODNAME); ret = -ETIMEDOUT; + dev_err(&intf->dev, "firmware did not run\n"); } else if (val != 0x0c) { - dev_err(&d->udev->dev, "%s: firmware boot timeout\n", - KBUILD_MODNAME); ret = -ETIMEDOUT; + dev_err(&intf->dev, "firmware boot timeout\n"); } error: @@ -812,8 +807,10 @@ exit: static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { - int ret; struct af9015_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; + int ret; if (adap->id == 0) { state->af9013_config[0].ts_mode = AF9013_TS_USB; @@ -833,10 +830,8 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) ret = af9015_copy_firmware(adap_to_d(adap)); if (ret) { - dev_err(&adap_to_d(adap)->udev->dev, - "%s: firmware copy to 2nd " \ - "frontend failed, will " \ - "disable it\n", KBUILD_MODNAME); + dev_err(&intf->dev, + "firmware copy to 2nd frontend failed, will disable it\n"); state->dual_mode = 0; return -ENODEV; } @@ -944,8 +939,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); switch (state->af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: @@ -999,9 +996,8 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) break; case AF9013_TUNER_UNKNOWN: default: - dev_err(&d->udev->dev, "%s: unknown tuner id=%d\n", - KBUILD_MODNAME, - state->af9013_config[adap->id].tuner); + dev_err(&intf->dev, "unknown tuner, tuner id %02x\n", + state->af9013_config[adap->id].tuner); ret = -ENODEV; } @@ -1023,8 +1019,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; int ret; - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + + dev_dbg(&intf->dev, "onoff %d\n", onoff); if (onoff) ret = af9015_set_reg_bit(d, 0xd503, 0); @@ -1038,10 +1036,12 @@ static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; int ret; u8 idx; - dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); + + dev_dbg(&intf->dev, "index %d, pid %04x, onoff %d\n", + index, pid, onoff); ret = af9015_write_reg(d, 0xd505, (pid & 0xff)); if (ret) @@ -1061,10 +1061,12 @@ error: static int af9015_init_endpoint(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u16 frame_size; u8 packet_size; - dev_dbg(&d->udev->dev, "%s: USB speed=%d\n", __func__, d->udev->speed); + + dev_dbg(&intf->dev, "usb speed %u\n", d->udev->speed); if (d->udev->speed == USB_SPEED_FULL) { frame_size = TS_USB11_FRAME_SIZE/4; @@ -1150,8 +1152,7 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) error: if (ret) - dev_err(&d->udev->dev, "%s: endpoint init failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&intf->dev, "endpoint init failed %d\n", ret); return ret; } @@ -1159,8 +1160,10 @@ error: static int af9015_init(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); mutex_init(&state->fe_mutex); @@ -1212,6 +1215,7 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { static int af9015_rc_query(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u8 buf[17]; @@ -1222,14 +1226,14 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* If any of these are non-zero, assume invalid data */ if (buf[1] || buf[2] || buf[3]) { - dev_dbg(&d->udev->dev, "%s: invalid data\n", __func__); + dev_dbg(&intf->dev, "invalid data\n"); return ret; } /* Check for repeat of previous code */ if ((state->rc_repeat != buf[6] || buf[0]) && !memcmp(&buf[12], state->rc_last, 4)) { - dev_dbg(&d->udev->dev, "%s: key repeated\n", __func__); + dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; return ret; @@ -1238,8 +1242,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Only process key if canary killed */ if (buf[16] != 0xff && buf[0] != 0x01) { enum rc_proto proto; - dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n", - __func__, 4, buf + 12); + dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12); /* Reset the canary */ ret = af9015_write_reg(d, 0x98e9, 0xff); @@ -1271,7 +1274,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) } rc_keydown(d->rc_dev, proto, state->rc_keycode, 0); } else { - dev_dbg(&d->udev->dev, "%s: no key press\n", __func__); + dev_dbg(&intf->dev, "no key press\n"); /* Invalidate last keypress */ /* Not really needed, but helps with debug */ state->rc_last[2] = state->rc_last[3]; @@ -1282,8 +1285,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) error: if (ret) { - dev_warn(&d->udev->dev, "%s: rc query failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&intf->dev, "rc query failed %d\n", ret); /* allow random errors as dvb-usb will stop polling on error */ if (!state->rc_failed) @@ -1376,7 +1378,7 @@ static int af9015_probe(struct usb_interface *intf, if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { if (!strcmp("ITE Technologies, Inc.", manufacturer)) { - dev_dbg(&udev->dev, "%s: rejecting device\n", __func__); + dev_dbg(&intf->dev, "rejecting device\n"); return -ENODEV; } } -- cgit From 3b536127f514217d18c04304cb859841ec63bda7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 22 Jun 2017 04:24:00 -0400 Subject: media: af9013: convert inittabs suitable for regmap_update_bits Convert inttabs to format (reg, mask, val) which are suitable parameters to pass directly for regmap_update_bits. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 62 +- drivers/media/dvb-frontends/af9013_priv.h | 1488 +++++++++++++++-------------- 2 files changed, 782 insertions(+), 768 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index e81dc827e1b8..87a55cd67e03 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -843,7 +843,7 @@ static int af9013_init(struct dvb_frontend *fe) int ret, i, len; unsigned int utmp; u8 buf[3]; - const struct af9013_reg_bit *init; + const struct af9013_reg_mask_val *tab; dev_dbg(&client->dev, "\n"); @@ -898,72 +898,66 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* load OFSM settings */ - dev_dbg(&client->dev, "load ofsm settings\n"); - len = ARRAY_SIZE(ofsm_init); - init = ofsm_init; + /* Demod core settings */ + dev_dbg(&client->dev, "load demod core settings\n"); + len = ARRAY_SIZE(demod_init_tab); + tab = demod_init_tab; for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, + tab[i].val); if (ret) goto err; } - /* load tuner specific settings */ + /* Demod tuner specific settings */ dev_dbg(&client->dev, "load tuner specific settings\n"); switch (state->tuner) { case AF9013_TUNER_MXL5003D: - len = ARRAY_SIZE(tuner_init_mxl5003d); - init = tuner_init_mxl5003d; + len = ARRAY_SIZE(tuner_init_tab_mxl5003d); + tab = tuner_init_tab_mxl5003d; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - len = ARRAY_SIZE(tuner_init_mxl5005); - init = tuner_init_mxl5005; + len = ARRAY_SIZE(tuner_init_tab_mxl5005); + tab = tuner_init_tab_mxl5005; break; case AF9013_TUNER_ENV77H11D5: - len = ARRAY_SIZE(tuner_init_env77h11d5); - init = tuner_init_env77h11d5; + len = ARRAY_SIZE(tuner_init_tab_env77h11d5); + tab = tuner_init_tab_env77h11d5; break; case AF9013_TUNER_MT2060: - len = ARRAY_SIZE(tuner_init_mt2060); - init = tuner_init_mt2060; + len = ARRAY_SIZE(tuner_init_tab_mt2060); + tab = tuner_init_tab_mt2060; break; case AF9013_TUNER_MC44S803: - len = ARRAY_SIZE(tuner_init_mc44s803); - init = tuner_init_mc44s803; + len = ARRAY_SIZE(tuner_init_tab_mc44s803); + tab = tuner_init_tab_mc44s803; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - len = ARRAY_SIZE(tuner_init_qt1010); - init = tuner_init_qt1010; + len = ARRAY_SIZE(tuner_init_tab_qt1010); + tab = tuner_init_tab_qt1010; break; case AF9013_TUNER_MT2060_2: - len = ARRAY_SIZE(tuner_init_mt2060_2); - init = tuner_init_mt2060_2; + len = ARRAY_SIZE(tuner_init_tab_mt2060_2); + tab = tuner_init_tab_mt2060_2; break; case AF9013_TUNER_TDA18271: case AF9013_TUNER_TDA18218: - len = ARRAY_SIZE(tuner_init_tda18271); - init = tuner_init_tda18271; + len = ARRAY_SIZE(tuner_init_tab_tda18271); + tab = tuner_init_tab_tda18271; break; case AF9013_TUNER_UNKNOWN: default: - len = ARRAY_SIZE(tuner_init_unknown); - init = tuner_init_unknown; + len = ARRAY_SIZE(tuner_init_tab_unknown); + tab = tuner_init_tab_unknown; break; } for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, + tab[i].val); if (ret) goto err; } diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 64f39d3db694..ec74edbb6d4d 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -30,10 +30,9 @@ #define AF9013_FIRMWARE "dvb-fe-af9013.fw" -struct af9013_reg_bit { - u16 addr; - u8 pos:4; - u8 len:4; +struct af9013_reg_mask_val { + u16 reg; + u8 mask; u8 val; }; @@ -87,754 +86,775 @@ static const struct af9013_coeff coeff_lut[] = { 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, }; -static const struct af9013_reg_bit ofsm_init[] = { - { 0xd73a, 0, 8, 0xa1 }, - { 0xd73b, 0, 8, 0x1f }, - { 0xd73c, 4, 4, 0x0a }, - { 0xd732, 3, 1, 0x00 }, - { 0xd731, 4, 2, 0x03 }, - { 0xd73d, 7, 1, 0x01 }, - { 0xd740, 0, 1, 0x00 }, - { 0xd740, 1, 1, 0x00 }, - { 0xd740, 2, 1, 0x00 }, - { 0xd740, 3, 1, 0x01 }, - { 0xd3c1, 4, 1, 0x01 }, - { 0x9124, 0, 8, 0x58 }, - { 0x9125, 0, 2, 0x02 }, - { 0xd3a2, 0, 8, 0x00 }, - { 0xd3a3, 0, 8, 0x04 }, - { 0xd305, 0, 8, 0x32 }, - { 0xd306, 0, 8, 0x10 }, - { 0xd304, 0, 8, 0x04 }, - { 0x9112, 0, 1, 0x01 }, - { 0x911d, 0, 1, 0x01 }, - { 0x911a, 0, 1, 0x01 }, - { 0x911b, 0, 1, 0x01 }, - { 0x9bce, 0, 4, 0x02 }, - { 0x9116, 0, 1, 0x01 }, - { 0x9122, 0, 8, 0xd0 }, - { 0xd2e0, 0, 8, 0xd0 }, - { 0xd2e9, 0, 4, 0x0d }, - { 0xd38c, 0, 8, 0xfc }, - { 0xd38d, 0, 8, 0x00 }, - { 0xd38e, 0, 8, 0x7e }, - { 0xd38f, 0, 8, 0x00 }, - { 0xd390, 0, 8, 0x2f }, - { 0xd145, 4, 1, 0x01 }, - { 0xd1a9, 4, 1, 0x01 }, - { 0xd158, 5, 3, 0x01 }, - { 0xd159, 0, 6, 0x06 }, - { 0xd167, 0, 8, 0x00 }, - { 0xd168, 0, 4, 0x07 }, - { 0xd1c3, 5, 3, 0x00 }, - { 0xd1c4, 0, 6, 0x00 }, - { 0xd1c5, 0, 7, 0x10 }, - { 0xd1c6, 0, 3, 0x02 }, - { 0xd080, 2, 5, 0x03 }, - { 0xd081, 4, 4, 0x09 }, - { 0xd098, 4, 4, 0x0f }, - { 0xd098, 0, 4, 0x03 }, - { 0xdbc0, 4, 1, 0x01 }, - { 0xdbc7, 0, 8, 0x08 }, - { 0xdbc8, 4, 4, 0x00 }, - { 0xdbc9, 0, 5, 0x01 }, - { 0xd280, 0, 8, 0xe0 }, - { 0xd281, 0, 8, 0xff }, - { 0xd282, 0, 8, 0xff }, - { 0xd283, 0, 8, 0xc3 }, - { 0xd284, 0, 8, 0xff }, - { 0xd285, 0, 4, 0x01 }, - { 0xd0f0, 0, 7, 0x1a }, - { 0xd0f1, 4, 1, 0x01 }, - { 0xd0f2, 0, 8, 0x0c }, - { 0xd101, 5, 3, 0x06 }, - { 0xd103, 0, 4, 0x08 }, - { 0xd0f8, 0, 7, 0x20 }, - { 0xd111, 5, 1, 0x00 }, - { 0xd111, 6, 1, 0x00 }, - { 0x910b, 0, 8, 0x0a }, - { 0x9115, 0, 8, 0x02 }, - { 0x910c, 0, 8, 0x02 }, - { 0x910d, 0, 8, 0x08 }, - { 0x910e, 0, 8, 0x0a }, - { 0x9bf6, 0, 8, 0x06 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf7, 0, 8, 0x05 }, - { 0x9bf9, 0, 8, 0x0f }, - { 0x9bfc, 0, 8, 0x13 }, - { 0x9bd3, 0, 8, 0xff }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, +/* + * Afatech AF9013 demod init + */ +static const struct af9013_reg_mask_val demod_init_tab[] = { + {0xd73a, 0xff, 0xa1}, + {0xd73b, 0xff, 0x1f}, + {0xd73c, 0xf0, 0xa0}, + {0xd732, 0x08, 0x00}, + {0xd731, 0x30, 0x30}, + {0xd73d, 0x80, 0x80}, + {0xd740, 0x01, 0x00}, + {0xd740, 0x02, 0x00}, + {0xd740, 0x04, 0x00}, + {0xd740, 0x08, 0x08}, + {0xd3c1, 0x10, 0x10}, + {0x9124, 0xff, 0x58}, + {0x9125, 0x03, 0x02}, + {0xd3a2, 0xff, 0x00}, + {0xd3a3, 0xff, 0x04}, + {0xd305, 0xff, 0x32}, + {0xd306, 0xff, 0x10}, + {0xd304, 0xff, 0x04}, + {0x9112, 0x01, 0x01}, + {0x911d, 0x01, 0x01}, + {0x911a, 0x01, 0x01}, + {0x911b, 0x01, 0x01}, + {0x9bce, 0x0f, 0x02}, + {0x9116, 0x01, 0x01}, + {0x9122, 0xff, 0xd0}, + {0xd2e0, 0xff, 0xd0}, + {0xd2e9, 0x0f, 0x0d}, + {0xd38c, 0xff, 0xfc}, + {0xd38d, 0xff, 0x00}, + {0xd38e, 0xff, 0x7e}, + {0xd38f, 0xff, 0x00}, + {0xd390, 0xff, 0x2f}, + {0xd145, 0x10, 0x10}, + {0xd1a9, 0x10, 0x10}, + {0xd158, 0xe0, 0x20}, + {0xd159, 0x3f, 0x06}, + {0xd167, 0xff, 0x00}, + {0xd168, 0x0f, 0x07}, + {0xd1c3, 0xe0, 0x00}, + {0xd1c4, 0x3f, 0x00}, + {0xd1c5, 0x7f, 0x10}, + {0xd1c6, 0x07, 0x02}, + {0xd080, 0x7c, 0x0c}, + {0xd081, 0xf0, 0x90}, + {0xd098, 0xf0, 0xf0}, + {0xd098, 0x0f, 0x03}, + {0xdbc0, 0x10, 0x10}, + {0xdbc7, 0xff, 0x08}, + {0xdbc8, 0xf0, 0x00}, + {0xdbc9, 0x1f, 0x01}, + {0xd280, 0xff, 0xe0}, + {0xd281, 0xff, 0xff}, + {0xd282, 0xff, 0xff}, + {0xd283, 0xff, 0xc3}, + {0xd284, 0xff, 0xff}, + {0xd285, 0x0f, 0x01}, + {0xd0f0, 0x7f, 0x1a}, + {0xd0f1, 0x10, 0x10}, + {0xd0f2, 0xff, 0x0c}, + {0xd101, 0xe0, 0xc0}, + {0xd103, 0x0f, 0x08}, + {0xd0f8, 0x7f, 0x20}, + {0xd111, 0x20, 0x00}, + {0xd111, 0x40, 0x00}, + {0x910b, 0xff, 0x0a}, + {0x9115, 0xff, 0x02}, + {0x910c, 0xff, 0x02}, + {0x910d, 0xff, 0x08}, + {0x910e, 0xff, 0x0a}, + {0x9bf6, 0xff, 0x06}, + {0x9bf8, 0xff, 0x02}, + {0x9bf7, 0xff, 0x05}, + {0x9bf9, 0xff, 0x0f}, + {0x9bfc, 0xff, 0x13}, + {0x9bd3, 0xff, 0xff}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, }; -/* Panasonic ENV77H11D5 tuner init - AF9013_TUNER_ENV77H11D5 = 129 */ -static const struct af9013_reg_bit tuner_init_env77h11d5[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x03 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0xd015, 0, 8, 0x50 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xeb }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf4 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xeb }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0x52 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Panasonic ENV77H11D5 tuner init + * AF9013_TUNER_ENV77H11D5 0x81 + */ +static const struct af9013_reg_mask_val tuner_init_tab_env77h11d5[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x03}, + {0x9bbe, 0xff, 0x01}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0xd015, 0xff, 0x50}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0xeb}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf4}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0xeb}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0x52}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060 = 130 */ -static const struct af9013_reg_bit tuner_init_mt2060[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bbe, 0, 1, 0x00 }, - { 0x9bcc, 0, 1, 0x00 }, - { 0x9bb9, 0, 8, 0x75 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x30 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcc }, - { 0x9be4, 0, 8, 0xa0 }, - { 0x9bbd, 0, 8, 0x8e }, - { 0x9be2, 0, 8, 0x4d }, - { 0x9bee, 0, 1, 0x01 }, +/* + * Microtune MT2060 tuner init + * AF9013_TUNER_MT2060 0x82 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mt2060[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x07}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bbe, 0x01, 0x00}, + {0x9bcc, 0x01, 0x00}, + {0x9bb9, 0xff, 0x75}, + {0x9bcd, 0xff, 0x24}, + {0x9bff, 0xff, 0x30}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x32}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x36}, + {0xd00d, 0x03, 0x03}, + {0xd00a, 0xff, 0x35}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x90}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x36}, + {0x9bc6, 0xff, 0x03}, + {0x9bba, 0xff, 0xc9}, + {0x9bc9, 0xff, 0x79}, + {0xd011, 0xff, 0x10}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0x45}, + {0xd014, 0x03, 0x03}, + {0xd040, 0xff, 0x98}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0xcf}, + {0xd043, 0x03, 0x03}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xcc}, + {0x9be4, 0xff, 0xa0}, + {0x9bbd, 0xff, 0x8e}, + {0x9be2, 0xff, 0x4d}, + {0x9bee, 0x01, 0x01}, }; -/* Microtune MT2060 tuner init - AF9013_TUNER_MT2060_2 = 147 */ -static const struct af9013_reg_bit tuner_init_mt2060_2[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0x9bbe, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x32 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x36 }, - { 0xd00d, 0, 2, 0x03 }, - { 0xd00a, 0, 8, 0x35 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x90 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x36 }, - { 0x9bc6, 0, 8, 0x03 }, - { 0x9bba, 0, 8, 0xc9 }, - { 0x9bc9, 0, 8, 0x79 }, - { 0xd011, 0, 8, 0x10 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0x45 }, - { 0xd014, 0, 2, 0x03 }, - { 0xd040, 0, 8, 0x98 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0xcf }, - { 0xd043, 0, 2, 0x03 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x96 }, - { 0xd054, 0, 8, 0x46 }, - { 0xd045, 7, 1, 0x00 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Microtune MT2060 tuner init + * AF9013_TUNER_MT2060_2 0x93 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mt2060_2[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x06}, + {0x9bbe, 0xff, 0x01}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x32}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x36}, + {0xd00d, 0x03, 0x03}, + {0xd00a, 0xff, 0x35}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x90}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x36}, + {0x9bc6, 0xff, 0x03}, + {0x9bba, 0xff, 0xc9}, + {0x9bc9, 0xff, 0x79}, + {0xd011, 0xff, 0x10}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0x45}, + {0xd014, 0x03, 0x03}, + {0xd040, 0xff, 0x98}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0xcf}, + {0xd043, 0x03, 0x03}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0xff, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x96}, + {0xd054, 0xff, 0x46}, + {0xd045, 0x80, 0x00}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* MaxLinear MXL5003 tuner init - AF9013_TUNER_MXL5003D = 3 */ -static const struct af9013_reg_bit tuner_init_mxl5003d[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bfc, 0, 8, 0x0f }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0xd015, 0, 8, 0x33 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x6c }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x3d }, - { 0xd00d, 0, 2, 0x00 }, - { 0xd00a, 0, 8, 0x45 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x07 }, - { 0x9bc8, 0, 8, 0x52 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x3d }, - { 0x9bc6, 0, 8, 0x00 }, - { 0x9bba, 0, 8, 0xa2 }, - { 0x9bc9, 0, 8, 0xa0 }, - { 0xd011, 0, 8, 0x56 }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x50 }, - { 0xd014, 0, 2, 0x00 }, - { 0xd040, 0, 8, 0x56 }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x50 }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 8, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * MaxLinear MXL5003 tuner init + * AF9013_TUNER_MXL5003D 0x03 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mxl5003d[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x09}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bfc, 0xff, 0x0f}, + {0x9bf6, 0xff, 0x01}, + {0x9bbe, 0x01, 0x01}, + {0xd015, 0xff, 0x33}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x40}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x6c}, + {0xd007, 0x03, 0x00}, + {0xd00c, 0xff, 0x3d}, + {0xd00d, 0x03, 0x00}, + {0xd00a, 0xff, 0x45}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x07}, + {0x9bc8, 0xff, 0x52}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x3d}, + {0x9bc6, 0xff, 0x00}, + {0x9bba, 0xff, 0xa2}, + {0x9bc9, 0xff, 0xa0}, + {0xd011, 0xff, 0x56}, + {0xd012, 0x03, 0x00}, + {0xd013, 0xff, 0x50}, + {0xd014, 0x03, 0x00}, + {0xd040, 0xff, 0x56}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0x50}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0xff, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* MaxLinear MXL5005S & MXL5007T tuner init - AF9013_TUNER_MXL5005D = 13 - AF9013_TUNER_MXL5005R = 30 - AF9013_TUNER_MXL5007T = 177 */ -static const struct af9013_reg_bit tuner_init_mxl5005[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x07 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x40 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x40 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x73 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0xfa }, - { 0xd00d, 0, 2, 0x01 }, - { 0xd00a, 0, 8, 0xff }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x23 }, - { 0x9bc8, 0, 8, 0x55 }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0xfa }, - { 0x9bc6, 0, 8, 0x01 }, - { 0x9bba, 0, 8, 0xff }, - { 0x9bc9, 0, 8, 0xff }, - { 0x9bd3, 0, 8, 0x95 }, - { 0xd011, 0, 8, 0x70 }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xfb }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x70 }, - { 0xd041, 0, 2, 0x01 }, - { 0xd042, 0, 8, 0xfb }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x93 }, - { 0x9be4, 0, 8, 0xfe }, - { 0x9bbd, 0, 8, 0x63 }, - { 0x9be2, 0, 8, 0xfe }, - { 0x9bee, 0, 1, 0x01 }, +/* + * MaxLinear MXL5005S & MXL5007T tuner init + * AF9013_TUNER_MXL5005D 0x0d + * AF9013_TUNER_MXL5005R 0x1e + * AF9013_TUNER_MXL5007T 0xb1 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mxl5005[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x07}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x28}, + {0x9bff, 0xff, 0x24}, + {0xd015, 0xff, 0x40}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x40}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x73}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0xfa}, + {0xd00d, 0x03, 0x01}, + {0xd00a, 0xff, 0xff}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x23}, + {0x9bc8, 0xff, 0x55}, + {0x9bc3, 0xff, 0x01}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0xfa}, + {0x9bc6, 0xff, 0x01}, + {0x9bba, 0xff, 0xff}, + {0x9bc9, 0xff, 0xff}, + {0x9bd3, 0xff, 0x95}, + {0xd011, 0xff, 0x70}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xfb}, + {0xd014, 0x03, 0x01}, + {0xd040, 0xff, 0x70}, + {0xd041, 0x03, 0x01}, + {0xd042, 0xff, 0xfb}, + {0xd043, 0x03, 0x01}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0x93}, + {0x9be4, 0xff, 0xfe}, + {0x9bbd, 0xff, 0x63}, + {0x9be2, 0xff, 0xfe}, + {0x9bee, 0x01, 0x01}, }; -/* Quantek QT1010 tuner init - AF9013_TUNER_QT1010 = 134 - AF9013_TUNER_QT1010A = 162 */ -static const struct af9013_reg_bit tuner_init_qt1010[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x09 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x28 }, - { 0x9bff, 0, 8, 0x20 }, - { 0xd008, 0, 8, 0x0f }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x99 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x0f }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0x50 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x00 }, - { 0x9bc8, 0, 8, 0x00 }, - { 0x9bc3, 0, 8, 0x0f }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x0f }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xc5 }, - { 0x9bc9, 0, 8, 0xff }, - { 0xd011, 0, 8, 0x58 }, - { 0xd012, 0, 2, 0x02 }, - { 0xd013, 0, 8, 0x89 }, - { 0xd014, 0, 2, 0x01 }, - { 0xd040, 0, 8, 0x58 }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x89 }, - { 0xd043, 0, 2, 0x01 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xcd }, - { 0x9be4, 0, 8, 0xbb }, - { 0x9bbd, 0, 8, 0x93 }, - { 0x9be2, 0, 8, 0x80 }, - { 0x9bee, 0, 1, 0x01 }, +/* + * Quantek QT1010 tuner init + * AF9013_TUNER_QT1010 0x86 + * AF9013_TUNER_QT1010A 0xa2 + */ +static const struct af9013_reg_mask_val tuner_init_tab_qt1010[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x09}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x28}, + {0x9bff, 0xff, 0x20}, + {0xd008, 0xff, 0x0f}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x99}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x0f}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0x50}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x00}, + {0x9bc8, 0xff, 0x00}, + {0x9bc3, 0xff, 0x0f}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x0f}, + {0x9bc6, 0xff, 0x02}, + {0x9bba, 0xff, 0xc5}, + {0x9bc9, 0xff, 0xff}, + {0xd011, 0xff, 0x58}, + {0xd012, 0x03, 0x02}, + {0xd013, 0xff, 0x89}, + {0xd014, 0x03, 0x01}, + {0xd040, 0xff, 0x58}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x89}, + {0xd043, 0x03, 0x01}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xcd}, + {0x9be4, 0xff, 0xbb}, + {0x9bbd, 0xff, 0x93}, + {0x9be2, 0xff, 0x80}, + {0x9bee, 0x01, 0x01}, }; -/* Freescale MC44S803 tuner init - AF9013_TUNER_MC44S803 = 133 */ -static const struct af9013_reg_bit tuner_init_mc44s803[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x06 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x00 }, - { 0x9be3, 0, 8, 0x00 }, - { 0x9bf6, 0, 8, 0x01 }, - { 0x9bf8, 0, 8, 0x02 }, - { 0x9bf9, 0, 8, 0x02 }, - { 0x9bfc, 0, 8, 0x1f }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x24 }, - { 0x9bff, 0, 8, 0x24 }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0x01 }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x7b }, - { 0xd007, 0, 2, 0x00 }, - { 0xd00c, 0, 8, 0x7c }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xfe }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bc7, 0, 8, 0x08 }, - { 0x9bc8, 0, 8, 0x9a }, - { 0x9bc3, 0, 8, 0x01 }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x7c }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bba, 0, 8, 0xfc }, - { 0x9bc9, 0, 8, 0xaa }, - { 0xd011, 0, 8, 0x6b }, - { 0xd012, 0, 2, 0x00 }, - { 0xd013, 0, 8, 0x88 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x6b }, - { 0xd041, 0, 2, 0x00 }, - { 0xd042, 0, 8, 0x7c }, - { 0xd043, 0, 2, 0x02 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0x9e }, - { 0x9be4, 0, 8, 0xff }, - { 0x9bbd, 0, 8, 0x9e }, - { 0x9be2, 0, 8, 0x25 }, - { 0x9bee, 0, 1, 0x01 }, - { 0xd73b, 3, 1, 0x00 }, +/* + * Freescale MC44S803 tuner init + * AF9013_TUNER_MC44S803 0x85 + */ +static const struct af9013_reg_mask_val tuner_init_tab_mc44s803[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x06}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x00}, + {0x9be3, 0xff, 0x00}, + {0x9bf6, 0xff, 0x01}, + {0x9bf8, 0xff, 0x02}, + {0x9bf9, 0xff, 0x02}, + {0x9bfc, 0xff, 0x1f}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x24}, + {0x9bff, 0xff, 0x24}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0x01}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x7b}, + {0xd007, 0x03, 0x00}, + {0xd00c, 0xff, 0x7c}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xfe}, + {0xd00b, 0x03, 0x01}, + {0x9bc7, 0xff, 0x08}, + {0x9bc8, 0xff, 0x9a}, + {0x9bc3, 0xff, 0x01}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x7c}, + {0x9bc6, 0xff, 0x02}, + {0x9bba, 0xff, 0xfc}, + {0x9bc9, 0xff, 0xaa}, + {0xd011, 0xff, 0x6b}, + {0xd012, 0x03, 0x00}, + {0xd013, 0xff, 0x88}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x6b}, + {0xd041, 0x03, 0x00}, + {0xd042, 0xff, 0x7c}, + {0xd043, 0x03, 0x02}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0x9e}, + {0x9be4, 0xff, 0xff}, + {0x9bbd, 0xff, 0x9e}, + {0x9be2, 0xff, 0x25}, + {0x9bee, 0x01, 0x01}, + {0xd73b, 0x08, 0x00}, }; -/* unknown, probably for tin can tuner, tuner init - AF9013_TUNER_UNKNOWN = 140 */ -static const struct af9013_reg_bit tuner_init_unknown[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x02 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, +/* + * Unknown, probably for tin can tuner, tuner init + * AF9013_TUNER_UNKNOWN 0x8c + */ +static const struct af9013_reg_mask_val tuner_init_tab_unknown[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x02}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd1a0, 0x02, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x18}, + {0x9bff, 0xff, 0x2c}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x00}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf6}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc8, 0xff, 0xaa}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x00}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0xf0}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, }; -/* NXP TDA18271 & TDA18218 tuner init - AF9013_TUNER_TDA18271 = 156 - AF9013_TUNER_TDA18218 = 179 */ -static const struct af9013_reg_bit tuner_init_tda18271[] = { - { 0x9bd5, 0, 8, 0x01 }, - { 0x9bd6, 0, 8, 0x04 }, - { 0xd1a0, 1, 1, 0x01 }, - { 0xd000, 0, 1, 0x01 }, - { 0xd000, 1, 1, 0x00 }, - { 0xd001, 1, 1, 0x01 }, - { 0xd001, 0, 1, 0x00 }, - { 0xd001, 5, 1, 0x00 }, - { 0xd002, 0, 5, 0x19 }, - { 0xd003, 0, 5, 0x1a }, - { 0xd004, 0, 5, 0x19 }, - { 0xd005, 0, 5, 0x1a }, - { 0xd00e, 0, 5, 0x10 }, - { 0xd00f, 0, 3, 0x04 }, - { 0xd00f, 3, 3, 0x05 }, - { 0xd010, 0, 3, 0x04 }, - { 0xd010, 3, 3, 0x05 }, - { 0xd016, 4, 4, 0x03 }, - { 0xd01f, 0, 6, 0x0a }, - { 0xd020, 0, 6, 0x0a }, - { 0x9bda, 0, 8, 0x01 }, - { 0x9be3, 0, 8, 0x01 }, - { 0xd1a0, 1, 1, 0x00 }, - { 0x9bbe, 0, 1, 0x01 }, - { 0x9bcc, 0, 1, 0x01 }, - { 0x9bb9, 0, 8, 0x00 }, - { 0x9bcd, 0, 8, 0x18 }, - { 0x9bff, 0, 8, 0x2c }, - { 0xd015, 0, 8, 0x46 }, - { 0xd016, 0, 1, 0x00 }, - { 0xd044, 0, 8, 0x46 }, - { 0xd045, 0, 1, 0x00 }, - { 0xd008, 0, 8, 0xdf }, - { 0xd009, 0, 2, 0x02 }, - { 0xd006, 0, 8, 0x44 }, - { 0xd007, 0, 2, 0x01 }, - { 0xd00c, 0, 8, 0x00 }, - { 0xd00d, 0, 2, 0x02 }, - { 0xd00a, 0, 8, 0xf6 }, - { 0xd00b, 0, 2, 0x01 }, - { 0x9bba, 0, 8, 0xf9 }, - { 0x9bc8, 0, 8, 0xaa }, - { 0x9bc3, 0, 8, 0xdf }, - { 0x9bc4, 0, 8, 0x02 }, - { 0x9bc5, 0, 8, 0x00 }, - { 0x9bc6, 0, 8, 0x02 }, - { 0x9bc9, 0, 8, 0xf0 }, - { 0xd011, 0, 8, 0x3c }, - { 0xd012, 0, 2, 0x01 }, - { 0xd013, 0, 8, 0xf7 }, - { 0xd014, 0, 2, 0x02 }, - { 0xd040, 0, 8, 0x0b }, - { 0xd041, 0, 2, 0x02 }, - { 0xd042, 0, 8, 0x4d }, - { 0xd043, 0, 2, 0x00 }, - { 0xd045, 1, 1, 0x00 }, - { 0x9bcf, 0, 1, 0x01 }, - { 0xd045, 2, 1, 0x01 }, - { 0xd04f, 0, 8, 0x9a }, - { 0xd050, 0, 1, 0x01 }, - { 0xd051, 0, 8, 0x5a }, - { 0xd052, 0, 1, 0x01 }, - { 0xd053, 0, 8, 0x50 }, - { 0xd054, 0, 8, 0x46 }, - { 0x9bd7, 0, 8, 0x0a }, - { 0x9bd8, 0, 8, 0x14 }, - { 0x9bd9, 0, 8, 0x08 }, - { 0x9bd0, 0, 8, 0xa8 }, - { 0x9be4, 0, 8, 0x7f }, - { 0x9bbd, 0, 8, 0xa8 }, - { 0x9be2, 0, 8, 0x20 }, - { 0x9bee, 0, 1, 0x01 }, +/* + * NXP TDA18271 & TDA18218 tuner init + * AF9013_TUNER_TDA18271 0x9c + * AF9013_TUNER_TDA18218 0xb3 + */ +static const struct af9013_reg_mask_val tuner_init_tab_tda18271[] = { + {0x9bd5, 0xff, 0x01}, + {0x9bd6, 0xff, 0x04}, + {0xd1a0, 0x02, 0x02}, + {0xd000, 0x01, 0x01}, + {0xd000, 0x02, 0x00}, + {0xd001, 0x02, 0x02}, + {0xd001, 0x01, 0x00}, + {0xd001, 0x20, 0x00}, + {0xd002, 0x1f, 0x19}, + {0xd003, 0x1f, 0x1a}, + {0xd004, 0x1f, 0x19}, + {0xd005, 0x1f, 0x1a}, + {0xd00e, 0x1f, 0x10}, + {0xd00f, 0x07, 0x04}, + {0xd00f, 0x38, 0x28}, + {0xd010, 0x07, 0x04}, + {0xd010, 0x38, 0x28}, + {0xd016, 0xf0, 0x30}, + {0xd01f, 0x3f, 0x0a}, + {0xd020, 0x3f, 0x0a}, + {0x9bda, 0xff, 0x01}, + {0x9be3, 0xff, 0x01}, + {0xd1a0, 0x02, 0x00}, + {0x9bbe, 0x01, 0x01}, + {0x9bcc, 0x01, 0x01}, + {0x9bb9, 0xff, 0x00}, + {0x9bcd, 0xff, 0x18}, + {0x9bff, 0xff, 0x2c}, + {0xd015, 0xff, 0x46}, + {0xd016, 0x01, 0x00}, + {0xd044, 0xff, 0x46}, + {0xd045, 0x01, 0x00}, + {0xd008, 0xff, 0xdf}, + {0xd009, 0x03, 0x02}, + {0xd006, 0xff, 0x44}, + {0xd007, 0x03, 0x01}, + {0xd00c, 0xff, 0x00}, + {0xd00d, 0x03, 0x02}, + {0xd00a, 0xff, 0xf6}, + {0xd00b, 0x03, 0x01}, + {0x9bba, 0xff, 0xf9}, + {0x9bc8, 0xff, 0xaa}, + {0x9bc3, 0xff, 0xdf}, + {0x9bc4, 0xff, 0x02}, + {0x9bc5, 0xff, 0x00}, + {0x9bc6, 0xff, 0x02}, + {0x9bc9, 0xff, 0xf0}, + {0xd011, 0xff, 0x3c}, + {0xd012, 0x03, 0x01}, + {0xd013, 0xff, 0xf7}, + {0xd014, 0x03, 0x02}, + {0xd040, 0xff, 0x0b}, + {0xd041, 0x03, 0x02}, + {0xd042, 0xff, 0x4d}, + {0xd043, 0x03, 0x00}, + {0xd045, 0x02, 0x00}, + {0x9bcf, 0x01, 0x01}, + {0xd045, 0x04, 0x04}, + {0xd04f, 0xff, 0x9a}, + {0xd050, 0x01, 0x01}, + {0xd051, 0xff, 0x5a}, + {0xd052, 0x01, 0x01}, + {0xd053, 0xff, 0x50}, + {0xd054, 0xff, 0x46}, + {0x9bd7, 0xff, 0x0a}, + {0x9bd8, 0xff, 0x14}, + {0x9bd9, 0xff, 0x08}, + {0x9bd0, 0xff, 0xa8}, + {0x9be4, 0xff, 0x7f}, + {0x9bbd, 0xff, 0xa8}, + {0x9be2, 0xff, 0x20}, + {0x9bee, 0x01, 0x01}, }; #endif /* AF9013_PRIV_H */ -- cgit From 22e59e7204a46d9f3c6abc02909927a19640f91f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 22 Jun 2017 12:18:21 -0400 Subject: media: af9013: add i2c mux adapter for tuner bus Add muxed i2c adapter for demod tuner i2c bus gate control. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/af9013.c | 126 +++++++++++++++++++++++++----- drivers/media/dvb-frontends/af9013.h | 1 + drivers/media/dvb-frontends/af9013_priv.h | 1 + 4 files changed, 111 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 687086cdb870..0712069fd9fe 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -462,7 +462,7 @@ config DVB_TDA10048 config DVB_AF9013 tristate "Afatech AF9013 demodulator" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 87a55cd67e03..d55c5f67ce0f 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -23,6 +23,7 @@ struct af9013_state { struct i2c_client *client; struct regmap *regmap; + struct i2c_mux_core *muxc; struct dvb_frontend fe; u32 clk; u8 tuner; @@ -1257,9 +1258,65 @@ static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) return &state->fe; } +static struct i2c_adapter *af9013_get_i2c_adapter(struct i2c_client *client) +{ + struct af9013_state *state = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return state->muxc->adapter[0]; +} + +/* + * XXX: Hackish solution. We use virtual register, reg bit 16, to carry info + * about i2c adapter locking. Own locking is needed because i2c mux call has + * already locked i2c adapter. + */ +static int af9013_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x08); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x04); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x00); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x00); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + /* Own I2C access routines needed for regmap as chip uses extra command byte */ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, - const u8 *val, int len) + const u8 *val, int len, u8 lock) { int ret; u8 buf[21]; @@ -1281,7 +1338,12 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; memcpy(&buf[3], val, len); - ret = i2c_transfer(client->adapter, msg, 1); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 1); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 1) { @@ -1296,7 +1358,7 @@ err: } static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, - u8 *val, int len) + u8 *val, int len, u8 lock) { int ret; u8 buf[3]; @@ -1317,7 +1379,12 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, buf[0] = (reg >> 8) & 0xff; buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; - ret = i2c_transfer(client->adapter, msg, 2); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 2); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 2) { @@ -1337,25 +1404,27 @@ static int af9013_regmap_write(void *context, const void *data, size_t count) struct af9013_state *state = i2c_get_clientdata(client); int ret, i; u8 cmd; - u16 reg = ((u8 *)data)[0] << 8|((u8 *)data)[1] << 0; - u8 *val = &((u8 *)data)[2]; - const unsigned int len = count - 2; + u8 lock = !((u8 *)data)[0]; + u16 reg = ((u8 *)data)[1] << 8 | ((u8 *)data)[2] << 0; + u8 *val = &((u8 *)data)[3]; + const unsigned int len = count - 3; if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0; - ret = af9013_wregs(client, cmd, reg, val, len); + ret = af9013_wregs(client, cmd, reg, val, len, lock); if (ret) goto err; } else if (reg >= 0x5100 && reg < 0x8fff) { /* Firmware download */ cmd = 1 << 7|1 << 6|(len - 1) << 2|1 << 1|1 << 0; - ret = af9013_wregs(client, cmd, reg, val, len); + ret = af9013_wregs(client, cmd, reg, val, len, lock); if (ret) goto err; } else { cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|1 << 0; for (i = 0; i < len; i++) { - ret = af9013_wregs(client, cmd, reg + i, val + i, 1); + ret = af9013_wregs(client, cmd, reg + i, val + i, 1, + lock); if (ret) goto err; } @@ -1374,19 +1443,21 @@ static int af9013_regmap_read(void *context, const void *reg_buf, struct af9013_state *state = i2c_get_clientdata(client); int ret, i; u8 cmd; - u16 reg = ((u8 *)reg_buf)[0] << 8|((u8 *)reg_buf)[1] << 0; + u8 lock = !((u8 *)reg_buf)[0]; + u16 reg = ((u8 *)reg_buf)[1] << 8 | ((u8 *)reg_buf)[2] << 0; u8 *val = &((u8 *)val_buf)[0]; const unsigned int len = val_size; if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0; - ret = af9013_rregs(client, cmd, reg, val_buf, len); + ret = af9013_rregs(client, cmd, reg, val_buf, len, lock); if (ret) goto err; } else { cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|0 << 0; for (i = 0; i < len; i++) { - ret = af9013_rregs(client, cmd, reg + i, val + i, 1); + ret = af9013_rregs(client, cmd, reg + i, val + i, 1, + lock); if (ret) goto err; } @@ -1411,8 +1482,9 @@ static int af9013_probe(struct i2c_client *client, .write = af9013_regmap_write, }; static const struct regmap_config regmap_config = { - .reg_bits = 16, - .val_bits = 8, + /* Actual reg is 16 bits, see i2c adapter lock */ + .reg_bits = 24, + .val_bits = 8, }; state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -1421,6 +1493,8 @@ static int af9013_probe(struct i2c_client *client, goto err; } + dev_dbg(&client->dev, "\n"); + /* Setup the state */ state->client = client; i2c_set_clientdata(client, state); @@ -1438,25 +1512,36 @@ static int af9013_probe(struct i2c_client *client, ret = PTR_ERR(state->regmap); goto err_kfree; } + /* Create mux i2c adapter */ + state->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, + af9013_select, af9013_deselect); + if (!state->muxc) { + ret = -ENOMEM; + goto err_regmap_exit; + } + state->muxc->priv = state; + ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + if (ret) + goto err_regmap_exit; /* Download firmware */ if (state->ts_mode != AF9013_TS_MODE_USB) { ret = af9013_download_firmware(state); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; } /* Firmware version */ ret = regmap_bulk_read(state->regmap, 0x5103, firmware_version, sizeof(firmware_version)); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; /* Set GPIOs */ for (i = 0; i < sizeof(state->gpio); i++) { ret = af9013_set_gpio(state, i, state->gpio[i]); if (ret) - goto err_regmap_exit; + goto err_i2c_mux_del_adapters; } /* Create dvb frontend */ @@ -1467,6 +1552,7 @@ static int af9013_probe(struct i2c_client *client, /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; + pdata->get_i2c_adapter = af9013_get_i2c_adapter; /* Init stats to indicate which stats are supported */ c = &state->fe.dtv_property_cache; @@ -1482,6 +1568,8 @@ static int af9013_probe(struct i2c_client *client, firmware_version[0], firmware_version[1], firmware_version[2], firmware_version[3]); return 0; +err_i2c_mux_del_adapters: + i2c_mux_del_adapters(state->muxc); err_regmap_exit: regmap_exit(state->regmap); err_kfree: @@ -1497,6 +1585,8 @@ static int af9013_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); + i2c_mux_del_adapters(state->muxc); + regmap_exit(state->regmap); kfree(state); diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index a290722c04fd..ea63ff9242f2 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -84,6 +84,7 @@ struct af9013_platform_data { u8 gpio[4]; struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); /* private: For legacy media attach wrapper. Do not set value. */ bool attach_in_use; diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index ec74edbb6d4d..3e95de7dba51 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -25,6 +25,7 @@ #include #include "af9013.h" #include +#include #include #include -- cgit From 04c611e3168e03702350bccaf5f9e83fb8f489db Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 23 Jun 2017 05:17:00 -0400 Subject: media: af9015: attach demod using i2c binding af9013 demod driver has i2c binding. Use it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 158 ++++++++++++++++++++-------------- drivers/media/usb/dvb-usb-v2/af9015.h | 4 +- 2 files changed, 96 insertions(+), 66 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 7e4cce05b911..f07aa42535e5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -148,8 +148,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -161,8 +161,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -258,7 +258,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -276,7 +276,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -293,7 +293,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) { + if (msg[0].addr == state->af9013_i2c_addr[0]) { ret = -EINVAL; goto err; } @@ -478,7 +478,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (d->udev->speed == USB_SPEED_FULL) state->dual_mode = 0; - state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD; + state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; if (state->dual_mode) { /* read 2nd demodulator I2C address */ @@ -487,7 +487,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[1].i2c_addr = val >> 1; + state->af9013_i2c_addr[1] = val >> 1; } for (i = 0; i < state->dual_mode + 1; i++) { @@ -500,20 +500,20 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; switch (val) { case 0: - state->af9013_config[i].clock = 28800000; + state->af9013_pdata[i].clk = 28800000; break; case 1: - state->af9013_config[i].clock = 20480000; + state->af9013_pdata[i].clk = 20480000; break; case 2: - state->af9013_config[i].clock = 28000000; + state->af9013_pdata[i].clk = 28000000; break; case 3: - state->af9013_config[i].clock = 25000000; + state->af9013_pdata[i].clk = 25000000; break; } - dev_dbg(&intf->dev, "[%d] xtal %02x, clock %u\n", - i, val, state->af9013_config[i].clock); + dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n", + i, val, state->af9013_pdata[i].clk); /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; @@ -521,17 +521,17 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[i].if_frequency = val << 8; + state->af9013_pdata[i].if_frequency = val << 8; req.addr = AF9015_EEPROM_IF1L + offset; ret = af9015_ctrl_msg(d, &req); if (ret) goto error; - state->af9013_config[i].if_frequency += val; - state->af9013_config[i].if_frequency *= 1000; + state->af9013_pdata[i].if_frequency += val; + state->af9013_pdata[i].if_frequency *= 1000; dev_dbg(&intf->dev, "[%d] if frequency %u\n", - i, state->af9013_config[i].if_frequency); + i, state->af9013_pdata[i].if_frequency); /* MT2060 IF1 */ req.addr = AF9015_EEPROM_MT2060_IF1H + offset; @@ -561,17 +561,17 @@ static int af9015_read_config(struct dvb_usb_device *d) case AF9013_TUNER_TDA18271: case AF9013_TUNER_QT1010A: case AF9013_TUNER_TDA18218: - state->af9013_config[i].spec_inv = 1; + state->af9013_pdata[i].spec_inv = 1; break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - state->af9013_config[i].spec_inv = 0; + state->af9013_pdata[i].spec_inv = 0; break; case AF9013_TUNER_MC44S803: - state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; - state->af9013_config[i].spec_inv = 1; + state->af9013_pdata[i].gpio[1] = AF9013_GPIO_LO; + state->af9013_pdata[i].spec_inv = 1; break; default: dev_err(&intf->dev, @@ -580,7 +580,7 @@ static int af9015_read_config(struct dvb_usb_device *d) return -ENODEV; } - state->af9013_config[i].tuner = val; + state->af9013_pdata[i].tuner = val; dev_dbg(&intf->dev, "[%d] tuner id %02x\n", i, val); } @@ -601,7 +601,7 @@ error: state->dual_mode = 0; /* set correct IF */ - state->af9013_config[0].if_frequency = 4570000; + state->af9013_pdata[0].if_frequency = 4570000; } return ret; @@ -741,7 +741,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) fw_params[2] = state->firmware_checksum >> 8; fw_params[3] = state->firmware_checksum & 0xff; - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); if (ret) goto error; @@ -771,7 +771,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) goto error; /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, + ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 1); dev_dbg(&intf->dev, "firmware boot cmd status %d\n", ret); if (ret) @@ -781,7 +781,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) msleep(100); /* check firmware status */ - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); dev_dbg(&intf->dev, "firmware status cmd status %d, firmware status %02x\n", ret, val); @@ -810,18 +810,22 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) struct af9015_state *state = adap_to_priv(adap); struct dvb_usb_device *d = adap_to_d(adap); struct usb_interface *intf = d->intf; + struct i2c_client *client; int ret; + dev_dbg(&intf->dev, "adap id %u\n", adap->id); + if (adap->id == 0) { - state->af9013_config[0].ts_mode = AF9013_TS_USB; - memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; - state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; + state->af9013_pdata[0].ts_mode = AF9013_TS_MODE_USB; + memcpy(state->af9013_pdata[0].api_version, "\x0\x1\x9\x0", 4); + state->af9013_pdata[0].gpio[0] = AF9013_GPIO_HI; + state->af9013_pdata[0].gpio[3] = AF9013_GPIO_TUNER_ON; } else if (adap->id == 1) { - state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; - memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); - state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; - state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; + state->af9013_pdata[1].ts_mode = AF9013_TS_MODE_SERIAL; + state->af9013_pdata[1].ts_output_pin = 7; + memcpy(state->af9013_pdata[1].api_version, "\x0\x1\x9\x0", 4); + state->af9013_pdata[1].gpio[0] = AF9013_GPIO_TUNER_ON; + state->af9013_pdata[1].gpio[1] = AF9013_GPIO_LO; /* copy firmware to 2nd demodulator */ if (state->dual_mode) { @@ -833,16 +837,24 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) dev_err(&intf->dev, "firmware copy to 2nd frontend failed, will disable it\n"); state->dual_mode = 0; - return -ENODEV; + goto err; } } else { - return -ENODEV; + ret = -ENODEV; + goto err; } } - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9013_attach, - &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); + /* Add I2C demod */ + client = dvb_module_probe("af9013", NULL, &d->i2c_adap, + state->af9013_i2c_addr[adap->id], + &state->af9013_pdata[adap->id]); + if (!client) { + ret = -ENODEV; + goto err; + } + adap->fe[0] = state->af9013_pdata[adap->id].get_dvb_frontend(client); + state->demod_i2c_client[adap->id] = client; /* * AF9015 firmware does not like if it gets interrupted by I2C adapter @@ -869,7 +881,26 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) adap->fe[0]->ops.sleep = af9015_af9013_sleep; } - return adap->fe[0] == NULL ? -ENODEV : 0; + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_frontend_detach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + struct usb_interface *intf = d->intf; + struct i2c_client *client; + + dev_dbg(&intf->dev, "adap id %u\n", adap->id); + + /* Remove I2C demod */ + client = state->demod_i2c_client[adap->id]; + dvb_module_release(client); + + return 0; } static struct mt2060_config af9015_mt2060_config = { @@ -940,64 +971,60 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) struct dvb_usb_device *d = adap_to_d(adap); struct af9015_state *state = d_to_priv(d); struct usb_interface *intf = d->intf; + struct i2c_client *client; + struct i2c_adapter *adapter; int ret; - dev_dbg(&intf->dev, "\n"); + dev_dbg(&intf->dev, "adap id %u\n", adap->id); + + client = state->demod_i2c_client[adap->id]; + adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client); - switch (state->af9013_config[adap->id].tuner) { + switch (state->af9013_pdata[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, - state->mt2060_if1[adap->id]) - == NULL ? -ENODEV : 0; + ret = dvb_attach(mt2060_attach, adap->fe[0], adapter, + &af9015_mt2060_config, + state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe[0], adapter, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(tda18218_attach, adap->fe[0], adapter, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe[0], - &adap_to_d(adap)->i2c_adap, + ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter, 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: default: dev_err(&intf->dev, "unknown tuner, tuner id %02x\n", - state->af9013_config[adap->id].tuner); + state->af9013_pdata[adap->id].tuner); ret = -ENODEV; } @@ -1404,6 +1431,7 @@ static struct dvb_usb_device_properties af9015_props = { .i2c_algo = &af9015_i2c_algo, .read_config = af9015_read_config, .frontend_attach = af9015_af9013_frontend_attach, + .frontend_detach = af9015_frontend_detach, .tuner_attach = af9015_tuner_attach, .init = af9015_init, .get_rc_config = af9015_get_rc_config, diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 3a9d9815ab7a..97339bf3749b 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -125,7 +125,9 @@ struct af9015_state { u16 firmware_size; u16 firmware_checksum; u32 eeprom_sum; - struct af9013_config af9013_config[2]; + struct af9013_platform_data af9013_pdata[2]; + struct i2c_client *demod_i2c_client[2]; + u8 af9013_i2c_addr[2]; /* for demod callback override */ int (*set_frontend[2]) (struct dvb_frontend *fe); -- cgit From 12c6b22fbf2379e0b194289227848f4f0439e5c3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 23 Jun 2017 05:31:49 -0400 Subject: media: af9013: remove all legacy media attach releated stuff No one is binding that driver through media attach so remove it and all related dead code. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 80 ------------------------------------ drivers/media/dvb-frontends/af9013.h | 42 ++++--------------- 2 files changed, 7 insertions(+), 115 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index d55c5f67ce0f..15af3e9482df 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -48,7 +48,6 @@ struct af9013_state { u32 dvbv3_ber; u32 dvbv3_ucblocks; bool first_tune; - bool i2c_gate_state; }; static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) @@ -1031,45 +1030,6 @@ err: return ret; } -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "enable %d\n", enable); - - /* gate already open or close */ - if (state->i2c_gate_state == enable) - return 0; - - if (state->ts_mode == AF9013_TS_MODE_USB) - ret = regmap_update_bits(state->regmap, 0xd417, 0x08, - enable << 3); - else - ret = regmap_update_bits(state->regmap, 0xd607, 0x04, - enable << 2); - if (ret) - goto err; - - state->i2c_gate_state = enable; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "\n"); - - i2c_unregister_device(client); -} - static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) @@ -1172,40 +1132,6 @@ err: return ret; } -/* - * XXX: That is wrapper to af9013_probe() via driver core in order to provide - * proper I2C client for legacy media attach binding. - * New users must use I2C client binding directly! - */ -struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c) -{ - struct i2c_client *client; - struct i2c_board_info board_info; - struct af9013_platform_data pdata; - - pdata.clk = config->clock; - pdata.tuner = config->tuner; - pdata.if_frequency = config->if_frequency; - pdata.ts_mode = config->ts_mode; - pdata.ts_output_pin = 7; - pdata.spec_inv = config->spec_inv; - memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version)); - memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio)); - pdata.attach_in_use = true; - - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "af9013", sizeof(board_info.type)); - board_info.addr = config->i2c_addr; - board_info.platform_data = &pdata; - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) - return NULL; - - return pdata.get_dvb_frontend(client); -} -EXPORT_SYMBOL(af9013_attach); - static const struct dvb_frontend_ops af9013_ops = { .delsys = { SYS_DVBT }, .info = { @@ -1231,8 +1157,6 @@ static const struct dvb_frontend_ops af9013_ops = { FE_CAN_MUTE_TS }, - .release = af9013_release, - .init = af9013_init, .sleep = af9013_sleep, @@ -1245,8 +1169,6 @@ static const struct dvb_frontend_ops af9013_ops = { .read_signal_strength = af9013_read_signal_strength, .read_ber = af9013_read_ber, .read_ucblocks = af9013_read_ucblocks, - - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, }; static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) @@ -1546,8 +1468,6 @@ static int af9013_probe(struct i2c_client *client, /* Create dvb frontend */ memcpy(&state->fe.ops, &af9013_ops, sizeof(state->fe.ops)); - if (!pdata->attach_in_use) - state->fe.ops.release = NULL; state->fe.demodulator_priv = state; /* Setup callbacks */ diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index ea63ff9242f2..8144d4270b58 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -38,13 +38,6 @@ * @api_version: Firmware API version. * @gpio: GPIOs. * @get_dvb_frontend: Get DVB frontend callback. - * - * AF9013/5 GPIOs (mostly guessed): - * * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices - * * demod#1-gpio#1 - xtal setting (?) - * * demod#1-gpio#3 - tuner#1 - * * demod#2-gpio#0 - tuner#2 - * * demod#2-gpio#1 - xtal setting (?) */ struct af9013_platform_data { /* @@ -85,36 +78,15 @@ struct af9013_platform_data { struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); - -/* private: For legacy media attach wrapper. Do not set value. */ - bool attach_in_use; - u8 i2c_addr; - u32 clock; }; -#define af9013_config af9013_platform_data -#define AF9013_TS_USB AF9013_TS_MODE_USB -#define AF9013_TS_PARALLEL AF9013_TS_MODE_PARALLEL -#define AF9013_TS_SERIAL AF9013_TS_MODE_SERIAL - -#if IS_REACHABLE(CONFIG_DVB_AF9013) -/** - * Attach an af9013 demod - * - * @config: pointer to &struct af9013_config with demod configuration. - * @i2c: i2c adapter to use. - * - * return: FE pointer on success, NULL on failure. +/* + * AF9013/5 GPIOs (mostly guessed) + * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices + * demod#1-gpio#1 - xtal setting (?) + * demod#1-gpio#3 - tuner#1 + * demod#2-gpio#0 - tuner#2 + * demod#2-gpio#1 - xtal setting (?) */ -extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c); -#else -static inline struct dvb_frontend *af9013_attach( -const struct af9013_config *config, struct i2c_adapter *i2c) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DVB_AF9013 */ #endif /* AF9013_H */ -- cgit From 83d6b7c3276fc056e65957b23c0ef7a3e9a50c18 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 26 Jun 2017 04:57:09 -0400 Subject: media: af9013: add pid filter support af9013 demod has pid filter. Add support for it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 52 ++++++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/af9013.h | 5 ++++ 2 files changed, 57 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 15af3e9482df..482bce49819a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1171,6 +1171,56 @@ static const struct dvb_frontend_ops af9013_ops = { .read_ucblocks = af9013_read_ucblocks, }; +static int af9013_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "onoff %d\n", onoff); + + ret = regmap_update_bits(state->regmap, 0xd503, 0x01, onoff); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, + int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + u8 buf[2]; + + dev_dbg(&client->dev, "index %d, pid %04x, onoff %d\n", + index, pid, onoff); + + if (pid > 0x1fff) { + /* 0x2000 is kernel virtual pid for whole ts (all pids) */ + ret = 0; + goto err; + } + + buf[0] = (pid >> 0) & 0xff; + buf[1] = (pid >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd505, buf, 2); + if (ret) + goto err; + ret = regmap_write(state->regmap, 0xd504, onoff << 5 | index << 0); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) { struct af9013_state *state = i2c_get_clientdata(client); @@ -1473,6 +1523,8 @@ static int af9013_probe(struct i2c_client *client, /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; pdata->get_i2c_adapter = af9013_get_i2c_adapter; + pdata->pid_filter = af9013_pid_filter; + pdata->pid_filter_ctrl = af9013_pid_filter_ctrl; /* Init stats to indicate which stats are supported */ c = &state->fe.dtv_property_cache; diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index 8144d4270b58..165ae29ccac4 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -38,6 +38,9 @@ * @api_version: Firmware API version. * @gpio: GPIOs. * @get_dvb_frontend: Get DVB frontend callback. + * @get_i2c_adapter: Get I2C adapter. + * @pid_filter_ctrl: Control PID filter. + * @pid_filter: Set PID to PID filter. */ struct af9013_platform_data { /* @@ -78,6 +81,8 @@ struct af9013_platform_data { struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + int (*pid_filter_ctrl)(struct dvb_frontend *, int); + int (*pid_filter)(struct dvb_frontend *, u8, u16, int); }; /* -- cgit From ba2d559b29cbaeafe012b642a53fed23b64762ea Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 26 Jun 2017 05:02:50 -0400 Subject: media: af9015: use af9013 demod pid filters PID filters are moved to af9013 demod driver as those are property of demod. As pid filters are now implemented correctly by demod driver, we could enable pid filter support for possible slave demod too on dual tuner configuration. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 49 +++++++++++++---------------------- 1 file changed, 18 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index f07aa42535e5..8e2f704c6ca5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -474,10 +474,6 @@ static int af9015_read_config(struct dvb_usb_device *d) state->dual_mode = val; dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode); - /* disable 2nd adapter because we don't have PID-filters */ - if (d->udev->speed == USB_SPEED_FULL) - state->dual_mode = 0; - state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; if (state->dual_mode) { @@ -1045,43 +1041,28 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - struct usb_interface *intf = d->intf; + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - dev_dbg(&intf->dev, "onoff %d\n", onoff); - - if (onoff) - ret = af9015_set_reg_bit(d, 0xd503, 0); - else - ret = af9015_clear_reg_bit(d, 0xd503, 0); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter_ctrl(adap->fe[0], onoff); + mutex_unlock(&state->fe_mutex); return ret; } -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - struct usb_interface *intf = d->intf; + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - u8 idx; - - dev_dbg(&intf->dev, "index %d, pid %04x, onoff %d\n", - index, pid, onoff); - ret = af9015_write_reg(d, 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(d, 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(d, 0xd504, idx); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter(adap->fe[0], index, pid, onoff); + mutex_unlock(&state->fe_mutex); -error: return ret; } @@ -1448,6 +1429,12 @@ static struct dvb_usb_device_properties af9015_props = { .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), }, }, -- cgit From 2ffb2fa32e5aa7685bbb6d625ad8e418d74aa440 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 26 Jun 2017 06:02:59 -0400 Subject: media: af9015: refactor firmware download Small revise, no functional changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 39 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8e2f704c6ca5..ffd4b225e439 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -350,52 +350,47 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) } static int af9015_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) + const struct firmware *firmware) { struct af9015_state *state = d_to_priv(d); struct usb_interface *intf = d->intf; - int i, len, remaining, ret; + int ret, i, rem; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; + u16 checksum; dev_dbg(&intf->dev, "\n"); - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; + /* Calc checksum, we need it when copy firmware to slave demod */ + for (i = 0, checksum = 0; i < firmware->size; i++) + checksum += firmware->data[i]; - state->firmware_size = fw->size; + state->firmware_size = firmware->size; state->firmware_checksum = checksum; - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - + #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ + for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { + req.data_len = min(LEN_MAX, rem); + req.data = (u8 *) &firmware->data[firmware->size - rem]; + req.addr = 0x5100 + firmware->size - rem; ret = af9015_ctrl_msg(d, &req); if (ret) { dev_err(&intf->dev, "firmware download failed %d\n", ret); - goto error; + goto err; } } - /* firmware loaded, request boot */ req.cmd = BOOT; req.data_len = 0; ret = af9015_ctrl_msg(d, &req); if (ret) { dev_err(&intf->dev, "firmware boot failed %d\n", ret); - goto error; + goto err; } -error: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } -- cgit From 0092293ec7981e9d46fa9103b07cfd63b3824b44 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 26 Jun 2017 07:15:27 -0400 Subject: media: af9015: refactor copy firmware to slave demod Small improvements. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 88 +++++++++++++++++------------------ 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index ffd4b225e439..1f352307a00a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -720,79 +720,79 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) struct af9015_state *state = d_to_priv(d); struct usb_interface *intf = d->intf; int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; + unsigned long timeout; + u8 val, firmware_info[4]; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info}; dev_dbg(&intf->dev, "\n"); - fw_params[0] = state->firmware_size >> 8; - fw_params[1] = state->firmware_size & 0xff; - fw_params[2] = state->firmware_checksum >> 8; - fw_params[3] = state->firmware_checksum & 0xff; + firmware_info[0] = (state->firmware_size >> 8) & 0xff; + firmware_info[1] = (state->firmware_size >> 0) & 0xff; + firmware_info[2] = (state->firmware_checksum >> 8) & 0xff; + firmware_info[3] = (state->firmware_checksum >> 0) & 0xff; - ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], - 0x98be, &val); + /* Check whether firmware is already running */ + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); if (ret) - goto error; - else - dev_dbg(&intf->dev, "firmware status %02x\n", val); + goto err; - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; + dev_dbg(&intf->dev, "firmware status %02x\n", val); - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ - if (ret) - goto error; + if (val == 0x0c) + return 0; - msleep(50); + /* Set i2c clock to 625kHz to speed up firmware copy */ + ret = af9015_write_reg(d, 0xd416, 0x04); + if (ret) + goto err; - /* copy firmware */ + /* Copy firmware from master demod to slave demod */ ret = af9015_ctrl_msg(d, &req); - if (ret) + if (ret) { dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret); + goto err; + } - dev_dbg(&intf->dev, "firmware copy done\n"); - - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + /* Set i2c clock to 125kHz */ + ret = af9015_write_reg(d, 0xd416, 0x14); if (ret) - goto error; + goto err; - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], - 0xe205, 1); - dev_dbg(&intf->dev, "firmware boot cmd status %d\n", ret); + /* Boot firmware */ + ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 0x01); if (ret) - goto error; + goto err; - for (i = 0; i < 15; i++) { - msleep(100); + /* Poll firmware ready */ + for (val = 0x00, timeout = jiffies + msecs_to_jiffies(1000); + !time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) { + msleep(20); - /* check firmware status */ + /* Check firmware status. 0c=OK, 04=fail */ ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], - 0x98be, &val); - dev_dbg(&intf->dev, "firmware status cmd status %d, firmware status %02x\n", - ret, val); + 0x98be, &val); if (ret) - goto error; + goto err; - if (val == 0x0c || val == 0x04) /* success or fail */ - break; + dev_dbg(&intf->dev, "firmware status %02x\n", val); } + dev_dbg(&intf->dev, "firmware boot took %u ms\n", + jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000)); + if (val == 0x04) { - ret = -ETIMEDOUT; + ret = -ENODEV; dev_err(&intf->dev, "firmware did not run\n"); + goto err; } else if (val != 0x0c) { ret = -ETIMEDOUT; dev_err(&intf->dev, "firmware boot timeout\n"); + goto err; } -error: -exit: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } -- cgit From 7772e380efcde7e6a2cdb731cf03b28582d6c51c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 13 Jul 2017 01:56:41 -0400 Subject: media: af9015: enhance streaming config Replace static stream settings by one which enables and disables stream interface when needed (TS streaming control). 1) Configure both TS IF and USB endpoints according to current use case 2) Disable streaming USB endpoints when streaming is stopped and enable when streaming is started. Reduces sleep power consumption slightly. 3) Reduce USB buffersize slightly, from 130848 to 98136 bytes Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 220 ++++++++++++++++++---------------- drivers/media/usb/dvb-usb-v2/af9015.h | 14 +-- 2 files changed, 115 insertions(+), 119 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 1f352307a00a..99e3b14d493e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -607,11 +607,121 @@ static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id); if (d->udev->speed == USB_SPEED_FULL) - stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + stream->u.bulk.buffersize = 5 * 188; return 0; } +static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int utmp1, utmp2, reg1, reg2; + u8 buf[2]; + const unsigned int adap_id = fe_to_adap(fe)->id; + + dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff); + + if (state->usb_ts_if_configured[adap_id] == false) { + dev_dbg(&intf->dev, "set usb and ts interface\n"); + + /* USB IF stream settings */ + utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; + utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; + + buf[0] = (utmp1 >> 0) & 0xff; + buf[1] = (utmp1 >> 8) & 0xff; + if (adap_id == 0) { + /* 1st USB IF (EP4) stream settings */ + reg1 = 0xdd88; + reg2 = 0xdd0c; + } else { + /* 2nd USB IF (EP5) stream settings */ + reg1 = 0xdd8a; + reg2 = 0xdd0d; + } + + ret = af9015_write_regs(d, reg1, buf, 2); + if (ret) + goto err; + ret = af9015_write_reg(d, reg2, utmp2); + if (ret) + goto err; + + /* TS IF settings */ + if (state->dual_mode) { + ret = af9015_set_reg_bit(d, 0xd50b, 0); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xd520, 4); + if (ret) + goto err; + } else { + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd520, 4); + if (ret) + goto err; + } + + state->usb_ts_if_configured[adap_id] = true; + } + + if (adap_id == 0 && onoff) { + /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ + ret = af9015_clear_reg_bit(d, 0xdd13, 5); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd11, 5); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd507, 2); + if (ret) + goto err; + } else if (adap_id == 1 && onoff) { + /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ + ret = af9015_clear_reg_bit(d, 0xdd13, 6); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd11, 6); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd50b, 1); + if (ret) + goto err; + } else if (adap_id == 0 && !onoff) { + /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ + ret = af9015_set_reg_bit(d, 0xd507, 2); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd13, 5); + if (ret) + goto err; + } else if (adap_id == 1 && !onoff) { + /* Adapter 1 stream off. EP5: set reset, disable, set NAK */ + ret = af9015_set_reg_bit(d, 0xd50b, 1); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd13, 6); + if (ret) + goto err; + } + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + static int af9015_get_adapter_count(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); @@ -1061,105 +1171,6 @@ static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, return ret; } -static int af9015_init_endpoint(struct dvb_usb_device *d) -{ - struct af9015_state *state = d_to_priv(d); - struct usb_interface *intf = d->intf; - int ret; - u16 frame_size; - u8 packet_size; - - dev_dbg(&intf->dev, "usb speed %u\n", d->udev->speed); - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (state->dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - - /* enable / disable mp2if2 */ - if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xd50b, 0); - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd520, 4); - if (ret) - goto error; - } else { - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd520, 4); - if (ret) - goto error; - } - -error: - if (ret) - dev_err(&intf->dev, "endpoint init failed %d\n", ret); - - return ret; -} - static int af9015_init(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); @@ -1175,10 +1186,6 @@ static int af9015_init(struct dvb_usb_device *d) if (ret) goto error; - ret = af9015_init_endpoint(d); - if (ret) - goto error; - error: return ret; } @@ -1412,6 +1419,7 @@ static struct dvb_usb_device_properties af9015_props = { .init = af9015_init, .get_rc_config = af9015_get_rc_config, .get_stream_config = af9015_get_stream_config, + .streaming_ctrl = af9015_streaming_ctrl, .get_adapter_count = af9015_get_adapter_count, .adapter = { @@ -1422,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_props = { .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, - .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), }, { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1430,7 +1438,7 @@ static struct dvb_usb_device_properties af9015_props = { .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, - .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), }, }, }; diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 97339bf3749b..28710aaf058a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -34,19 +34,6 @@ #define AF9015_FIRMWARE "dvb-usb-af9015.fw" -/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - #define AF9015_I2C_EEPROM 0x50 #define AF9015_I2C_DEMOD 0x1c #define AF9015_USB_TIMEOUT 2000 @@ -128,6 +115,7 @@ struct af9015_state { struct af9013_platform_data af9013_pdata[2]; struct i2c_client *demod_i2c_client[2]; u8 af9013_i2c_addr[2]; + bool usb_ts_if_configured[2]; /* for demod callback override */ int (*set_frontend[2]) (struct dvb_frontend *fe); -- cgit From 19324414c954e68921271bfc1f4a235c90a557c6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 10 Jul 2017 15:35:59 -0400 Subject: media: dvb-usb-v2: add probe/disconnect callbacks Add probe and disconnect callbacks that behaves similarly than ones used commonly on Linux driver model. We need those to get early / late access to driver in order to use normal probe time stuff, like regmap, extra bus adapters and so. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 4 ++++ drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 24 ++++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index d2e80537b2f7..3fd6cc0d6340 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -203,6 +203,8 @@ struct dvb_usb_adapter_properties { * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for * receive * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @probe: like probe on driver model + * @disconnect: like disconnect on driver model * @identify_state: called to determine the firmware state (cold or warm) and * return possible firmware file name to be loaded * @firmware: name of the firmware file to be loaded @@ -239,6 +241,8 @@ struct dvb_usb_device_properties { u8 generic_bulk_ctrl_endpoint_response; unsigned int generic_bulk_ctrl_delay; + int (*probe)(struct dvb_usb_device *); + void (*disconnect)(struct dvb_usb_device *); #define WARM 0 #define COLD 1 int (*identify_state) (struct dvb_usb_device *, const char **); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 2bf3bd81280a..afdcdbf005e9 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -854,8 +854,6 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) dvb_usbv2_remote_exit(d); dvb_usbv2_adapter_exit(d); dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); return 0; } @@ -934,7 +932,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, if (intf->cur_altsetting->desc.bInterfaceNumber != d->props->bInterfaceNumber) { ret = -ENODEV; - goto err_free_all; + goto err_kfree_d; } mutex_init(&d->usb_mutex); @@ -946,10 +944,16 @@ int dvb_usbv2_probe(struct usb_interface *intf, dev_err(&d->udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; - goto err_free_all; + goto err_kfree_d; } } + if (d->props->probe) { + ret = d->props->probe(d); + if (ret) + goto err_kfree_priv; + } + if (d->props->identify_state) { const char *name = NULL; ret = d->props->identify_state(d, &name); @@ -1001,6 +1005,12 @@ exit: return 0; err_free_all: dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); +err_kfree_priv: + kfree(d->priv); +err_kfree_d: + kfree(d); err: dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); return ret; @@ -1021,6 +1031,12 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); + + kfree(d->priv); + kfree(d); + pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, drvname, devname); kfree(devname); -- cgit From 8b79c7ab11c4de580972042244f078a1bb9ff0cd Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 13 Jul 2017 02:42:52 -0400 Subject: media: af9015: convert to regmap api Use regmap for chip register access. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/af9015.c | 209 ++++++++++++++++++---------------- drivers/media/usb/dvb-usb-v2/af9015.h | 2 + 3 files changed, 115 insertions(+), 97 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 0e4944b2b0f4..09a52aae299a 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -16,6 +16,7 @@ config DVB_USB_V2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" depends on DVB_USB_V2 + select REGMAP select DVB_AF9013 select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 99e3b14d493e..8379ef164fad 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -117,31 +117,6 @@ error: return ret; } -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val) { @@ -168,38 +143,6 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, return af9015_ctrl_msg(d, &req); } -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -642,76 +585,73 @@ static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) reg1 = 0xdd8a; reg2 = 0xdd0d; } - - ret = af9015_write_regs(d, reg1, buf, 2); + ret = regmap_bulk_write(state->regmap, reg1, buf, 2); if (ret) goto err; - ret = af9015_write_reg(d, reg2, utmp2); + ret = regmap_write(state->regmap, reg2, utmp2); if (ret) goto err; /* TS IF settings */ if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xd50b, 0); - if (ret) - goto err; - ret = af9015_set_reg_bit(d, 0xd520, 4); - if (ret) - goto err; + utmp1 = 0x01; + utmp2 = 0x10; } else { - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - if (ret) - goto err; - ret = af9015_clear_reg_bit(d, 0xd520, 4); - if (ret) - goto err; + utmp1 = 0x00; + utmp2 = 0x00; } + ret = regmap_update_bits(state->regmap, 0xd50b, 0x01, utmp1); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xd520, 0x10, utmp2); + if (ret) + goto err; state->usb_ts_if_configured[adap_id] = true; } if (adap_id == 0 && onoff) { /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ - ret = af9015_clear_reg_bit(d, 0xdd13, 5); + ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x00); if (ret) goto err; - ret = af9015_set_reg_bit(d, 0xdd11, 5); + ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x20); if (ret) goto err; - ret = af9015_clear_reg_bit(d, 0xd507, 2); + ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x00); if (ret) goto err; } else if (adap_id == 1 && onoff) { /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ - ret = af9015_clear_reg_bit(d, 0xdd13, 6); + ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x00); if (ret) goto err; - ret = af9015_set_reg_bit(d, 0xdd11, 6); + ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x40); if (ret) goto err; - ret = af9015_clear_reg_bit(d, 0xd50b, 1); + ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x00); if (ret) goto err; } else if (adap_id == 0 && !onoff) { /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ - ret = af9015_set_reg_bit(d, 0xd507, 2); + ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x04); if (ret) goto err; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); + ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x00); if (ret) goto err; - ret = af9015_set_reg_bit(d, 0xdd13, 5); + ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x20); if (ret) goto err; } else if (adap_id == 1 && !onoff) { /* Adapter 1 stream off. EP5: set reset, disable, set NAK */ - ret = af9015_set_reg_bit(d, 0xd50b, 1); + ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x02); if (ret) goto err; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); + ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x00); if (ret) goto err; - ret = af9015_set_reg_bit(d, 0xdd13, 6); + ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x40); if (ret) goto err; } @@ -852,7 +792,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) return 0; /* Set i2c clock to 625kHz to speed up firmware copy */ - ret = af9015_write_reg(d, 0xd416, 0x04); + ret = regmap_write(state->regmap, 0xd416, 0x04); if (ret) goto err; @@ -864,7 +804,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) } /* Set i2c clock to 125kHz */ - ret = af9015_write_reg(d, 0xd416, 0x14); + ret = regmap_write(state->regmap, 0xd416, 0x14); if (ret) goto err; @@ -1182,7 +1122,7 @@ static int af9015_init(struct dvb_usb_device *d) mutex_init(&state->fe_mutex); /* init RC canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); + ret = regmap_write(state->regmap, 0x98e9, 0xff); if (ret) goto error; @@ -1230,7 +1170,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) u8 buf[17]; /* read registers needed to detect remote controller code */ - ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + ret = regmap_bulk_read(state->regmap, 0x98d9, buf, sizeof(buf)); if (ret) goto error; @@ -1255,7 +1195,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12); /* Reset the canary */ - ret = af9015_write_reg(d, 0x98e9, 0xff); + ret = regmap_write(state->regmap, 0x98e9, 0xff); if (ret) goto error; @@ -1359,15 +1299,68 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) #define af9015_get_rc_config NULL #endif -static int af9015_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int af9015_regmap_write(void *context, const void *data, size_t count) +{ + struct dvb_usb_device *d = context; + struct usb_interface *intf = d->intf; + int ret; + u16 reg = ((u8 *)data)[0] << 8 | ((u8 *)data)[1] << 0; + u8 *val = &((u8 *)data)[2]; + const unsigned int len = count - 2; + struct req_t req = {WRITE_MEMORY, 0, reg, 0, 0, len, val}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct dvb_usb_device *d = context; + struct usb_interface *intf = d->intf; + int ret; + u16 reg = ((u8 *)reg_buf)[0] << 8 | ((u8 *)reg_buf)[1] << 0; + u8 *val = &((u8 *)val_buf)[0]; + const unsigned int len = val_size; + struct req_t req = {READ_MEMORY, 0, reg, 0, 0, len, val}; + + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int af9015_probe(struct dvb_usb_device *d) { + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; struct usb_device *udev = interface_to_usbdev(intf); + int ret; char manufacturer[sizeof("ITE Technologies, Inc.")]; + static const struct regmap_config regmap_config = { + .reg_bits = 16, + .val_bits = 8, + }; + static const struct regmap_bus regmap_bus = { + .read = af9015_regmap_read, + .write = af9015_regmap_write, + }; + + dev_dbg(&intf->dev, "\n"); memset(manufacturer, 0, sizeof(manufacturer)); usb_string(udev, udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); + manufacturer, sizeof(manufacturer)); /* * There is two devices having same ID but different chipset. One uses * AF9015 and the other IT9135 chipset. Only difference seen on lsusb @@ -1386,19 +1379,39 @@ static int af9015_probe(struct usb_interface *intf, * iProduct 2 DVB-T TV Stick */ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && - (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { + (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { if (!strcmp("ITE Technologies, Inc.", manufacturer)) { + ret = -ENODEV; dev_dbg(&intf->dev, "rejecting device\n"); - return -ENODEV; + goto err; } } - return dvb_usbv2_probe(intf, id); + state->regmap = regmap_init(&intf->dev, ®map_bus, d, ®map_config); + if (IS_ERR(state->regmap)) { + ret = PTR_ERR(state->regmap); + goto err; + } + + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static void af9015_disconnect(struct dvb_usb_device *d) +{ + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + + dev_dbg(&intf->dev, "\n"); + + regmap_exit(state->regmap); } /* interface 0 is used by DVB-T receiver and interface 1 is for remote controller (HID) */ -static struct dvb_usb_device_properties af9015_props = { +static const struct dvb_usb_device_properties af9015_props = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, .adapter_nr = adapter_nr, @@ -1407,6 +1420,8 @@ static struct dvb_usb_device_properties af9015_props = { .generic_bulk_ctrl_endpoint = 0x02, .generic_bulk_ctrl_endpoint_response = 0x81, + .probe = af9015_probe, + .disconnect = af9015_disconnect, .identify_state = af9015_identify_state, .firmware = AF9015_FIRMWARE, .download_firmware = af9015_download_firmware, @@ -1529,7 +1544,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table); static struct usb_driver af9015_usb_driver = { .name = KBUILD_MODNAME, .id_table = af9015_id_table, - .probe = af9015_probe, + .probe = dvb_usbv2_probe, .disconnect = dvb_usbv2_disconnect, .suspend = dvb_usbv2_suspend, .resume = dvb_usbv2_resume, diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 28710aaf058a..ad2b045cc39c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -21,6 +21,7 @@ #define AF9015_H #include +#include #include "dvb_usb.h" #include "af9013.h" #include "dvb-pll.h" @@ -100,6 +101,7 @@ enum af9015_ir_mode { #define BUF_LEN 63 struct af9015_state { + struct regmap *regmap; u8 buf[BUF_LEN]; /* bulk USB control message */ u8 ir_mode; u8 rc_repeat; -- cgit From b2d109f24aa3062b2082d93ec1771d6e92ef8032 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 13 Mar 2018 19:27:57 -0400 Subject: media: af9015: correct some coding style issues Correct coding style issues reported mostly by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 172 +++++++++++++++++----------------- 1 file changed, 88 insertions(+), 84 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8379ef164fad..39f9ffce3caa 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -72,17 +72,19 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) goto error; } - /* buffer overflow check */ + /* Buffer overflow check */ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { dev_err(&intf->dev, "too much data, cmd %u, len %u\n", req->cmd, req->data_len); ret = -EINVAL; goto error; } - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ + /* + * Write receives seq + status = 2 bytes + * Read receives seq + status + data = 2 + N bytes + */ wlen = REQ_HDR_LEN; rlen = ACK_HDR_LEN; if (write) { @@ -96,8 +98,8 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) rlen = 0; - ret = dvb_usbv2_generic_rw_locked(d, - state->buf, wlen, state->buf, rlen); + ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, + state->buf, rlen); if (ret) goto error; @@ -118,7 +120,7 @@ error: } static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) + u8 val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; @@ -131,7 +133,7 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, } static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) + u8 *val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; @@ -144,7 +146,7 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, } static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); @@ -154,28 +156,29 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], u8 mbox, addr_len; struct req_t req; -/* -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - -................................................ -. AF9015 includes integrated AF9013 demodulator. -. ____________ ____________ . ____________ -.| uC | | demod | . | tuner | -.|------------| |------------| . |------------| -.| AF9015 | | AF9013/5 | . | MXL5003 | -.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | -.| | | | addr 0x38 | . | addr 0xc6 | -.|____________| | |____________| . |____________| -.................|.............................. - | ____________ ____________ - | | demod | | tuner | - | |------------| |------------| - | | AF9013 | | MXL5003 | - +----I2C-------|-----/ -----|-------I2C-------| | - | addr 0x3a | | addr 0xc6 | - |____________| |____________| -*/ + /* + * I2C multiplexing: + * There could be two tuners, both using same I2C address. Demodulator + * I2C-gate is only possibility to select correct tuner. + * + * ........................................... + * . AF9015 integrates AF9013 demodulator . + * . ____________ ____________ . ____________ + * .| USB IF | | demod |. | tuner | + * .|------------| |------------|. |------------| + * .| AF9015 | | AF9013 |. | MXL5003 | + * .| |--+--I2C-----|-----/ -----|.----I2C-----| | + * .| | | | addr 0x1c |. | addr 0x63 | + * .|____________| | |____________|. |____________| + * .................|......................... + * | ____________ ____________ + * | | demod | | tuner | + * | |------------| |------------| + * | | AF9013 | | MXL5003 | + * +--I2C-----|-----/ -----|-----I2C-----| | + * | addr 0x1d | | addr 0x63 | + * |____________| |____________| + */ if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { addr = 0x0000; @@ -186,11 +189,11 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. mbox = 0; addr_len = 1; } else if (msg[0].len == 2) { - addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; mbox = 0; addr_len = 2; } else { - addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0; mbox = msg[0].buf[2]; addr_len = 3; } @@ -209,7 +212,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. req.addr = addr; req.mbox = mbox; req.addr_len = addr_len; - req.data_len = msg[0].len-addr_len; + req.data_len = msg[0].len - addr_len; req.data = &msg[0].buf[addr_len]; ret = af9015_ctrl_msg(d, &req); } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && @@ -313,7 +316,7 @@ static int af9015_download_firmware(struct dvb_usb_device *d, #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { req.data_len = min(LEN_MAX, rem); - req.data = (u8 *) &firmware->data[firmware->size - rem]; + req.data = (u8 *)&firmware->data[firmware->size - rem]; req.addr = 0x5100 + firmware->size - rem; ret = af9015_ctrl_msg(d, &req); if (ret) { @@ -522,14 +525,14 @@ error: if (ret) dev_err(&intf->dev, "eeprom read failed %d\n", ret); - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ + /* + * AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + * content :-( Override some wrong values here. Ditto for the + * AVerTV Red HD+ (A850T) device. + */ if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(d->udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { + ((le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) { dev_dbg(&intf->dev, "AverMedia A850: overriding config\n"); /* disable dual mode */ state->dual_mode = 0; @@ -542,7 +545,7 @@ error: } static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) + struct usb_data_stream_properties *stream) { struct dvb_usb_device *d = fe_to_d(fe); struct usb_interface *intf = d->intf; @@ -567,7 +570,7 @@ static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff); - if (state->usb_ts_if_configured[adap_id] == false) { + if (!state->usb_ts_if_configured[adap_id]) { dev_dbg(&intf->dev, "set usb and ts interface\n"); /* USB IF stream settings */ @@ -665,6 +668,7 @@ err: static int af9015_get_adapter_count(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); + return state->dual_mode + 1; } @@ -686,7 +690,7 @@ static int af9015_af9013_set_frontend(struct dvb_frontend *fe) /* override demod callbacks for resource locking */ static int af9015_af9013_read_status(struct dvb_frontend *fe, - enum fe_status *status) + enum fe_status *status) { int ret; struct af9015_state *state = fe_to_priv(fe); @@ -905,19 +909,12 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) * those "critical" paths to keep AF9015 happy. */ if (adap->fe[0]) { - state->set_frontend[adap->id] = - adap->fe[0]->ops.set_frontend; - adap->fe[0]->ops.set_frontend = - af9015_af9013_set_frontend; - - state->read_status[adap->id] = - adap->fe[0]->ops.read_status; - adap->fe[0]->ops.read_status = - af9015_af9013_read_status; - + state->set_frontend[adap->id] = adap->fe[0]->ops.set_frontend; + adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend; + state->read_status[adap->id] = adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = af9015_af9013_read_status; state->init[adap->id] = adap->fe[0]->ops.init; adap->fe[0]->ops.init = af9015_af9013_init; - state->sleep[adap->id] = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = af9015_af9013_sleep; } @@ -1025,42 +1022,42 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: ret = dvb_attach(mt2060_attach, adap->fe[0], adapter, - &af9015_mt2060_config, - state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; + &af9015_mt2060_config, + state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: ret = dvb_attach(qt1010_attach, adap->fe[0], adapter, - &af9015_qt1010_config) == NULL ? -ENODEV : 0; + &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter, - &af9015_tda18271_config) == NULL ? -ENODEV : 0; + &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: ret = dvb_attach(tda18218_attach, adap->fe[0], adapter, - &af9015_tda18218_config) == NULL ? -ENODEV : 0; + &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, - &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter, - &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter, - DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter, - &af9015_mc44s803_config) == NULL ? -ENODEV : 0; + &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter, - 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: default: @@ -1137,7 +1134,7 @@ struct af9015_rc_setup { }; static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) + const struct af9015_rc_setup *table) { for (; table->rc_codes; table++) if (table->id == id) @@ -1182,7 +1179,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Check for repeat of previous code */ if ((state->rc_repeat != buf[6] || buf[0]) && - !memcmp(&buf[12], state->rc_last, 4)) { + !memcmp(&buf[12], state->rc_last, 4)) { dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; @@ -1192,6 +1189,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Only process key if canary killed */ if (buf[16] != 0xff && buf[0] != 0x01) { enum rc_proto proto; + dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12); /* Reset the canary */ @@ -1201,8 +1199,8 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Remember this key */ memcpy(state->rc_last, &buf[12], 4); - if (buf[14] == (u8) ~buf[15]) { - if (buf[12] == (u8) ~buf[13]) { + if (buf[14] == (u8)~buf[15]) { + if (buf[12] == (u8)~buf[13]) { /* NEC */ state->rc_keycode = RC_SCANCODE_NEC(buf[12], buf[14]); @@ -1258,29 +1256,33 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) /* try to load remote based module param */ if (!rc->map_name) rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, - af9015_rc_setup_modparam); + af9015_rc_setup_modparam); /* try to load remote based eeprom hash */ if (!rc->map_name) rc->map_name = af9015_rc_setup_match(state->eeprom_sum, - af9015_rc_setup_hashes); + af9015_rc_setup_hashes); /* try to load remote based USB iManufacturer string */ if (!rc->map_name && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + /* + * Check USB manufacturer and product strings and try + * to determine correct remote in case of chip vendor + * reference IDs are used. + * DO NOT ADD ANYTHING NEW HERE. Use hashes instead. + */ char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); usb_string(d->udev, d->udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); + manufacturer, sizeof(manufacturer)); if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - rc->map_name = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); + /* + * iManufacturer 1 MSI + * iProduct 2 MSI K-VOX + */ + rc->map_name = af9015_rc_setup_match(AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); } } @@ -1409,8 +1411,10 @@ static void af9015_disconnect(struct dvb_usb_device *d) regmap_exit(state->regmap); } -/* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ +/* + * Interface 0 is used by DVB-T receiver and + * interface 1 is for remote controller (HID) + */ static const struct dvb_usb_device_properties af9015_props = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, -- cgit From 7641b04421954ea092b8fa7edbf904c3852875b5 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 12 Mar 2018 09:43:02 -0400 Subject: media: i2c: Copy mt9t112 soc_camera sensor driver Copy the soc_camera based driver in v4l2 sensor driver directory. This commit just copies the original file without modifying it. No modification to KConfig and Makefile as soc_camera framework dependencies need to be removed first in next commit. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9t112.c | 1163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1163 insertions(+) create mode 100644 drivers/media/i2c/mt9t112.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c new file mode 100644 index 000000000000..297d22ebcb18 --- /dev/null +++ b/drivers/media/i2c/mt9t112.c @@ -0,0 +1,1163 @@ +/* + * mt9t112 Camera Driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov772x driver, mt9m111 driver, + * + * Copyright (C) 2008 Kuninori Morimoto + * Copyright (C) 2008, Robert Jarzmik + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* you can check PLL/clock info */ +/* #define EXT_CLOCK 24000000 */ + +/************************************************************************ + macro +************************************************************************/ +/* + * frame size + */ +#define MAX_WIDTH 2048 +#define MAX_HEIGHT 1536 + +/* + * macro of read/write + */ +#define ECHECKER(ret, x) \ + do { \ + (ret) = (x); \ + if ((ret) < 0) \ + return (ret); \ + } while (0) + +#define mt9t112_reg_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_reg_write(client, a, b)) +#define mt9t112_mcu_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) + +#define mt9t112_reg_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) +#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) + +#define mt9t112_reg_read(ret, client, a) \ + ECHECKER(ret, __mt9t112_reg_read(client, a)) + +/* + * Logical address + */ +#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) +#define VAR(id, offset) _VAR(id, offset, 0x0000) +#define VAR8(id, offset) _VAR(id, offset, 0x8000) + +/************************************************************************ + struct +************************************************************************/ +struct mt9t112_format { + u32 code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +struct mt9t112_priv { + struct v4l2_subdev subdev; + struct mt9t112_camera_info *info; + struct i2c_client *client; + struct v4l2_rect frame; + struct v4l2_clk *clk; + const struct mt9t112_format *format; + int num_formats; + u32 flags; +/* for flags */ +#define INIT_DONE (1 << 0) +#define PCLK_RISING (1 << 1) +}; + +/************************************************************************ + supported format +************************************************************************/ + +static const struct mt9t112_format mt9t112_cfmts[] = { + { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 0, + }, { + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 1, + }, { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 2, + }, { + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 1, + .order = 3, + }, { + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 8, + .order = 2, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 4, + .order = 2, + }, +}; + +/************************************************************************ + general function +************************************************************************/ +static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), + struct mt9t112_priv, + subdev); +} + +static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + command = swab16(command); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = (u8 *)&command; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = buf; + + /* + * if return value of this function is < 0, + * it mean error. + * else, under 16bit is valid data. + */ + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + + memcpy(&ret, buf, 2); + return swab16(ret); +} + +static int __mt9t112_reg_write(const struct i2c_client *client, + u16 command, u16 data) +{ + struct i2c_msg msg; + u8 buf[4]; + int ret; + + command = swab16(command); + data = swab16(data); + + memcpy(buf + 0, &command, 2); + memcpy(buf + 2, &data, 2); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 4; + msg.buf = buf; + + /* + * i2c_transfer return message length, + * but this function should return 0 if correct case + */ + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + ret = 0; + + return ret; +} + +static int __mt9t112_reg_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_reg_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_reg_write(client, command, val); +} + +/* mcu access */ +static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_read(client, 0x0990); +} + +static int __mt9t112_mcu_write(const struct i2c_client *client, + u16 command, u16 data) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_write(client, 0x0990, data); +} + +static int __mt9t112_mcu_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_mcu_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_mcu_write(client, command, val); +} + +static int mt9t112_reset(const struct i2c_client *client) +{ + int ret; + + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); + msleep(1); + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); + + return ret; +} + +#ifndef EXT_CLOCK +#define CLOCK_INFO(a, b) +#else +#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) +static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) +{ + int m, n, p1, p2, p3, p4, p5, p6, p7; + u32 vco, clk; + char *enable; + + ext /= 1000; /* kbyte order */ + + mt9t112_reg_read(n, client, 0x0012); + p1 = n & 0x000f; + n = n >> 4; + p2 = n & 0x000f; + n = n >> 4; + p3 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002a); + p4 = n & 0x000f; + n = n >> 4; + p5 = n & 0x000f; + n = n >> 4; + p6 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002c); + p7 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x0010); + m = n & 0x00ff; + n = (n >> 8) & 0x003f; + + enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; + dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + + vco = 2 * m * ext / (n+1); + enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; + dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); + + clk = vco / (p1+1) / (p2+1); + enable = (96000 < clk) ? "X" : ""; + dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + + clk = vco / (p3+1); + enable = (768000 < clk) ? "X" : ""; + dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + + clk = vco / (p6+1); + enable = (96000 < clk) ? "X" : ""; + dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + + clk = vco / (p5+1); + enable = (54000 < clk) ? "X" : ""; + dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + + clk = vco / (p4+1); + enable = (70000 < clk) ? "X" : ""; + dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + + clk = vco / (p7+1); + dev_dbg(&client->dev, "External sensor : %10u K\n", clk); + + clk = ext / (n+1); + enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; + dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); + + return 0; +} +#endif + +static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) +{ + soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); + soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); +} + +static int mt9t112_set_a_frame_size(const struct i2c_client *client, + u16 width, + u16 height) +{ + int ret; + u16 wstart = (MAX_WIDTH - width) / 2; + u16 hstart = (MAX_HEIGHT - height) / 2; + + /* (Context A) Image Width/Height */ + mt9t112_mcu_write(ret, client, VAR(26, 0), width); + mt9t112_mcu_write(ret, client, VAR(26, 2), height); + + /* (Context A) Output Width/Height */ + mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); + mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); + + /* (Context A) Start Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); + + /* (Context A) End Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + return ret; +} + +static int mt9t112_set_pll_dividers(const struct i2c_client *client, + u8 m, u8 n, + u8 p1, u8 p2, u8 p3, + u8 p4, u8 p5, u8 p6, + u8 p7) +{ + int ret; + u16 val; + + /* N/M */ + val = (n << 8) | + (m << 0); + mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); + + /* P1/P2/P3 */ + val = ((p3 & 0x0F) << 8) | + ((p2 & 0x0F) << 4) | + ((p1 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); + + /* P4/P5/P6 */ + val = (0x7 << 12) | + ((p6 & 0x0F) << 8) | + ((p5 & 0x0F) << 4) | + ((p4 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); + + /* P7 */ + val = (0x1 << 12) | + ((p7 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); + + return ret; +} + +static int mt9t112_init_pll(const struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int data, i, ret; + + mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); + + /* PLL control: BYPASS PLL = 8517 */ + mt9t112_reg_write(ret, client, 0x0014, 0x2145); + + /* Replace these registers when new timing parameters are generated */ + mt9t112_set_pll_dividers(client, + priv->info->divider.m, + priv->info->divider.n, + priv->info->divider.p1, + priv->info->divider.p2, + priv->info->divider.p3, + priv->info->divider.p4, + priv->info->divider.p5, + priv->info->divider.p6, + priv->info->divider.p7); + + /* + * TEST_BYPASS on + * PLL_ENABLE on + * SEL_LOCK_DET on + * TEST_BYPASS off + */ + mt9t112_reg_write(ret, client, 0x0014, 0x2525); + mt9t112_reg_write(ret, client, 0x0014, 0x2527); + mt9t112_reg_write(ret, client, 0x0014, 0x3427); + mt9t112_reg_write(ret, client, 0x0014, 0x3027); + + mdelay(10); + + /* + * PLL_BYPASS off + * Reference clock count + * I2C Master Clock Divider + */ + mt9t112_reg_write(ret, client, 0x0014, 0x3046); + mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */ + mt9t112_reg_write(ret, client, 0x0022, 0x0190); + mt9t112_reg_write(ret, client, 0x3B84, 0x0212); + + /* External sensor clock is PLL bypass */ + mt9t112_reg_write(ret, client, 0x002E, 0x0500); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); + mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); + + /* MCU disabled */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); + + /* out of standby */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); + + mdelay(50); + + /* + * Standby Workaround + * Disable Secondary I2C Pads + */ + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + + /* poll to verify out of standby. Must Poll this bit */ + for (i = 0; i < 100; i++) { + mt9t112_reg_read(data, client, 0x0018); + if (!(0x4000 & data)) + break; + + mdelay(10); + } + + return ret; +} + +static int mt9t112_init_setting(const struct i2c_client *client) +{ + + int ret; + + /* Adaptive Output Clock (A) */ + mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); + + /* Read Mode (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); + + /* Fine Correction (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); + + /* Fine IT Min (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); + + /* Fine IT Max Margin (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); + + /* Base Frame Lines (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); + + /* Min Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); + + /* Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); + + /* Adaptive Output Clock (B) */ + mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); + + /* Row Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); + + /* Column Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); + + /* Row End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); + + /* Column End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); + + /* Fine Correction (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); + + /* Fine IT Min (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); + + /* Fine IT Max Margin (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); + + /* Base Frame Lines (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); + + /* Min Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); + + /* Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); + + /* + * Flicker Dectection registers + * This section should be replaced whenever new Timing file is generated + * All the following registers need to be replaced + * Following registers are generated from Register Wizard but user can + * modify them. For detail see auto flicker detection tuning + */ + + /* FD_FDPERIOD_SELECT */ + mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); + + /* PRI_B_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); + + /* PRI_A_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); + + /* + * AFD range detection tuning registers + */ + + /* search_f1_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); + + /* search_f2_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); + + /* search_f1_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); + + /* search_f2_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); + + /* period_50Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); + + /* secret register by aptina */ + /* period_50Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); + + /* period_60Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); + + /* secret register by aptina */ + /* period_60Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); + + /* period_50Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); + + /* secret register by aptina */ + /* period_50Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); + + /* period_60Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); + + /* secret register by aptina */ + /* period_60Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); + + /* FD Mode */ + mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); + + /* Stat_min */ + mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); + + /* Stat_max */ + mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); + + /* Min_amplitude */ + mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); + + /* RX FIFO Watermark (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); + + /* RX FIFO Watermark (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); + + /* MCLK: 16MHz + * PCLK: 73MHz + * CorePixCLK: 36.5 MHz + */ + mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); + mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); + + mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); + + return ret; +} + +static int mt9t112_auto_focus_setting(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); + mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_reg_write(ret, client, 0x0614, 0x0000); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); + mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); + mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); + mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); + mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); + mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + + return ret; +} + +static int mt9t112_auto_focus_trigger(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); + + return ret; +} + +static int mt9t112_init_camera(const struct i2c_client *client) +{ + int ret; + + ECHECKER(ret, mt9t112_reset(client)); + + ECHECKER(ret, mt9t112_init_pll(client)); + + ECHECKER(ret, mt9t112_init_setting(client)); + + ECHECKER(ret, mt9t112_auto_focus_setting(client)); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); + + /* Analog setting B */ + mt9t112_reg_write(ret, client, 0x3084, 0x2409); + mt9t112_reg_write(ret, client, 0x3092, 0x0A49); + mt9t112_reg_write(ret, client, 0x3094, 0x4949); + mt9t112_reg_write(ret, client, 0x3096, 0x4950); + + /* + * Disable adaptive clock + * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); + mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); + + /* Configure STatus in Status_before_length Format and enable header */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); + + /* Enable JPEG in context B */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); + + /* Disable Dac_TXLO */ + mt9t112_reg_write(ret, client, 0x316C, 0x350F); + + /* Set max slew rates */ + mt9t112_reg_write(ret, client, 0x1E, 0x777); + + return ret; +} + +/************************************************************************ + v4l2_subdev_core_ops +************************************************************************/ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9t112_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 2; + mt9t112_reg_read(ret, client, reg->reg); + + reg->val = (__u64)ret; + + return 0; +} + +static int mt9t112_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mt9t112_reg_write(ret, client, reg->reg, reg->val); + + return ret; +} +#endif + +static int mt9t112_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct mt9t112_priv *priv = to_mt9t112(client); + + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); +} + +static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9t112_g_register, + .s_register = mt9t112_s_register, +#endif + .s_power = mt9t112_s_power, +}; + + +/************************************************************************ + v4l2_subdev_video_ops +************************************************************************/ +static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + int ret = 0; + + if (!enable) { + /* FIXME + * + * If user selected large output size, + * and used it long time, + * mt9t112 camera will be very warm. + * + * But current driver can not stop mt9t112 camera. + * So, set small size here to solve this problem. + */ + mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); + return ret; + } + + if (!(priv->flags & INIT_DONE)) { + u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; + + ECHECKER(ret, mt9t112_init_camera(client)); + + /* Invert PCLK (Data sampled on falling edge of pixclk) */ + mt9t112_reg_write(ret, client, 0x3C20, param); + + mdelay(5); + + priv->flags |= INIT_DONE; + } + + mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); + mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_set_a_frame_size(client, + priv->frame.width, + priv->frame.height); + + ECHECKER(ret, mt9t112_auto_focus_trigger(client)); + + dev_dbg(&client->dev, "format : %d\n", priv->format->code); + dev_dbg(&client->dev, "size : %d x %d\n", + priv->frame.width, + priv->frame.height); + + CLOCK_INFO(client, EXT_CLOCK); + + return ret; +} + +static int mt9t112_set_params(struct mt9t112_priv *priv, + const struct v4l2_rect *rect, + u32 code) +{ + int i; + + /* + * get color format + */ + for (i = 0; i < priv->num_formats; i++) + if (mt9t112_cfmts[i].code == code) + break; + + if (i == priv->num_formats) + return -EINVAL; + + priv->frame = *rect; + + /* + * frame size check + */ + mt9t112_frame_check(&priv->frame.width, &priv->frame.height, + &priv->frame.left, &priv->frame.top); + + priv->format = mt9t112_cfmts + i; + + return 0; +} + +static int mt9t112_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = MAX_WIDTH; + sel->r.height = MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = VGA_WIDTH; + sel->r.height = VGA_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->frame; + return 0; + default: + return -EINVAL; + } +} + +static int mt9t112_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + const struct v4l2_rect *rect = &sel->r; + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || + sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + return mt9t112_set_params(priv, rect, priv->format->code); +} + +static int mt9t112_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (format->pad) + return -EINVAL; + + mf->width = priv->frame.width; + mf->height = priv->frame.height; + mf->colorspace = priv->format->colorspace; + mf->code = priv->format->code; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + struct v4l2_rect rect = { + .width = mf->width, + .height = mf->height, + .left = priv->frame.left, + .top = priv->frame.top, + }; + int ret; + + ret = mt9t112_set_params(priv, &rect, mf->code); + + if (!ret) + mf->colorspace = priv->format->colorspace; + + return ret; +} + +static int mt9t112_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + unsigned int top, left; + int i; + + if (format->pad) + return -EINVAL; + + for (i = 0; i < priv->num_formats; i++) + if (mt9t112_cfmts[i].code == mf->code) + break; + + if (i == priv->num_formats) { + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->colorspace = V4L2_COLORSPACE_JPEG; + } else { + mf->colorspace = mt9t112_cfmts[i].colorspace; + } + + mt9t112_frame_check(&mf->width, &mf->height, &left, &top); + + mf->field = V4L2_FIELD_NONE; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9t112_s_fmt(sd, mf); + cfg->try_fmt = *mf; + return 0; +} + +static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (code->pad || code->index >= priv->num_formats) + return -EINVAL; + + code->code = mt9t112_cfmts[code->index].code; + + return 0; +} + +static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); + + return 0; +} + +static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, + const struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct mt9t112_priv *priv = to_mt9t112(client); + + if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) + priv->flags |= PCLK_RISING; + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { + .s_stream = mt9t112_s_stream, + .g_mbus_config = mt9t112_g_mbus_config, + .s_mbus_config = mt9t112_s_mbus_config, +}; + +static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { + .enum_mbus_code = mt9t112_enum_mbus_code, + .get_selection = mt9t112_get_selection, + .set_selection = mt9t112_set_selection, + .get_fmt = mt9t112_get_fmt, + .set_fmt = mt9t112_set_fmt, +}; + +/************************************************************************ + i2c driver +************************************************************************/ +static const struct v4l2_subdev_ops mt9t112_subdev_ops = { + .core = &mt9t112_subdev_core_ops, + .video = &mt9t112_subdev_video_ops, + .pad = &mt9t112_subdev_pad_ops, +}; + +static int mt9t112_camera_probe(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + const char *devname; + int chipid; + int ret; + + ret = mt9t112_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * check and show chip ID + */ + mt9t112_reg_read(chipid, client, 0x0000); + + switch (chipid) { + case 0x2680: + devname = "mt9t111"; + priv->num_formats = 1; + break; + case 0x2682: + devname = "mt9t112"; + priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); + break; + default: + dev_err(&client->dev, "Product ID error %04x\n", chipid); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); + +done: + mt9t112_s_power(&priv->subdev, 0); + return ret; +} + +static int mt9t112_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t112_priv *priv; + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct v4l2_rect rect = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .left = (MAX_WIDTH - VGA_WIDTH) / 2, + .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, + }; + int ret; + + if (!ssdd || !ssdd->drv_priv) { + dev_err(&client->dev, "mt9t112: missing platform data!\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = ssdd->drv_priv; + + v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); + + priv->clk = v4l2_clk_get(&client->dev, "mclk"); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + ret = mt9t112_camera_probe(client); + + /* Cannot fail: using the default supported pixel code */ + if (!ret) + mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8); + else + v4l2_clk_put(priv->clk); + + return ret; +} + +static int mt9t112_remove(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + + v4l2_clk_put(priv->clk); + return 0; +} + +static const struct i2c_device_id mt9t112_id[] = { + { "mt9t112", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t112_id); + +static struct i2c_driver mt9t112_i2c_driver = { + .driver = { + .name = "mt9t112", + }, + .probe = mt9t112_probe, + .remove = mt9t112_remove, + .id_table = mt9t112_id, +}; + +module_i2c_driver(mt9t112_i2c_driver); + +MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); -- cgit From 6a26f141bf6200a1b3537c24bd4a8d37f23fbe57 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 12 Mar 2018 09:43:03 -0400 Subject: media: i2c: mt9t112: Remove soc_camera dependencies Remove soc_camera framework dependencies from mt9t112 sensor driver. - Handle clk, gpios and power routines - Register async subdev - Remove deprecated g/s_mbus_config operations - Remove driver flags - Change driver interface and add kernel doc - Adjust build system - Fix code style issues reported by checkpatch in strict mode This commit does not remove the original soc_camera based driver as long as other platforms depends on soc_camera framework. As I don't have access to a working camera module, this change has only been compile tested. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/mt9t112.c | 403 ++++++++++++++++----------------- drivers/media/i2c/soc_camera/mt9t112.c | 2 +- 4 files changed, 203 insertions(+), 214 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index d7bba0e3f30e..541f0d28afd8 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -788,6 +788,17 @@ config VIDEO_MT9T001 This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt0t001 3 Mpixel camera. +config VIDEO_MT9T112 + tristate "Aptina MT9T111/MT9T112 support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the Aptina + (Micron) MT9T111 and MT9T112 3 Mpixel camera. + + To compile this driver as a module, choose M here: the + module will be called mt9t112. + config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index cc30178e3347..ea34aee1a85a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o +obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 297d22ebcb18..af8cca984215 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1,6 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * mt9t112 Camera Driver * + * Copyright (C) 2018 Jacopo Mondi + * * Copyright (C) 2009 Renesas Solutions Corp. * Kuninori Morimoto * @@ -12,12 +15,14 @@ * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * TODO: This driver lacks support for frame rate control due to missing + * register level documentation and suitable hardware for testing. + * v4l-utils compliance tools will report errors. */ +#include #include +#include #include #include #include @@ -26,17 +31,16 @@ #include #include -#include -#include #include #include +#include /* you can check PLL/clock info */ /* #define EXT_CLOCK 24000000 */ /************************************************************************ - macro -************************************************************************/ + * macro + ***********************************************************************/ /* * frame size */ @@ -74,8 +78,8 @@ #define VAR8(id, offset) _VAR(id, offset, 0x8000) /************************************************************************ - struct -************************************************************************/ + * struct + ***********************************************************************/ struct mt9t112_format { u32 code; enum v4l2_colorspace colorspace; @@ -85,21 +89,19 @@ struct mt9t112_format { struct mt9t112_priv { struct v4l2_subdev subdev; - struct mt9t112_camera_info *info; + struct mt9t112_platform_data *info; struct i2c_client *client; struct v4l2_rect frame; - struct v4l2_clk *clk; + struct clk *clk; + struct gpio_desc *standby_gpio; const struct mt9t112_format *format; int num_formats; - u32 flags; -/* for flags */ -#define INIT_DONE (1 << 0) -#define PCLK_RISING (1 << 1) + bool init_done; }; /************************************************************************ - supported format -************************************************************************/ + * supported format + ***********************************************************************/ static const struct mt9t112_format mt9t112_cfmts[] = { { @@ -136,8 +138,8 @@ static const struct mt9t112_format mt9t112_cfmts[] = { }; /************************************************************************ - general function -************************************************************************/ + * general function + ***********************************************************************/ static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) { return container_of(i2c_get_clientdata(client), @@ -164,15 +166,15 @@ static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) msg[1].buf = buf; /* - * if return value of this function is < 0, - * it mean error. - * else, under 16bit is valid data. + * If return value of this function is < 0, it means error, else, + * below 16bit is valid data. */ ret = i2c_transfer(client->adapter, msg, 2); if (ret < 0) return ret; memcpy(&ret, buf, 2); + return swab16(ret); } @@ -195,22 +197,19 @@ static int __mt9t112_reg_write(const struct i2c_client *client, msg.buf = buf; /* - * i2c_transfer return message length, - * but this function should return 0 if correct case + * i2c_transfer return message length, but this function should + * return 0 if correct case. */ ret = i2c_transfer(client->adapter, &msg, 1); - if (ret >= 0) - ret = 0; - return ret; + return ret >= 0 ? 0 : ret; } static int __mt9t112_reg_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) + u16 command, u16 mask, u16 set) { int val = __mt9t112_reg_read(client, command); + if (val < 0) return val; @@ -245,11 +244,10 @@ static int __mt9t112_mcu_write(const struct i2c_client *client, } static int __mt9t112_mcu_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) + u16 command, u16 mask, u16 set) { int val = __mt9t112_mcu_read(client, command); + if (val < 0) return val; @@ -264,7 +262,7 @@ static int mt9t112_reset(const struct i2c_client *client) int ret; mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); - msleep(1); + usleep_range(1000, 5000); mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); return ret; @@ -303,71 +301,64 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) m = n & 0x00ff; n = (n >> 8) & 0x003f; - enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; + enable = ((ext < 6000) || (ext > 54000)) ? "X" : ""; dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); - vco = 2 * m * ext / (n+1); - enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; + vco = 2 * m * ext / (n + 1); + enable = ((vco < 384000) || (vco > 768000)) ? "X" : ""; dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); - clk = vco / (p1+1) / (p2+1); - enable = (96000 < clk) ? "X" : ""; + clk = vco / (p1 + 1) / (p2 + 1); + enable = (clk > 96000) ? "X" : ""; dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); - clk = vco / (p3+1); - enable = (768000 < clk) ? "X" : ""; + clk = vco / (p3 + 1); + enable = (clk > 768000) ? "X" : ""; dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); - clk = vco / (p6+1); - enable = (96000 < clk) ? "X" : ""; + clk = vco / (p6 + 1); + enable = (clk > 96000) ? "X" : ""; dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); - clk = vco / (p5+1); - enable = (54000 < clk) ? "X" : ""; + clk = vco / (p5 + 1); + enable = (clk > 54000) ? "X" : ""; dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); - clk = vco / (p4+1); - enable = (70000 < clk) ? "X" : ""; + clk = vco / (p4 + 1); + enable = (clk > 70000) ? "X" : ""; dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); - clk = vco / (p7+1); + clk = vco / (p7 + 1); dev_dbg(&client->dev, "External sensor : %10u K\n", clk); - clk = ext / (n+1); - enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; + clk = ext / (n + 1); + enable = ((clk < 2000) || (clk > 24000)) ? "X" : ""; dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); return 0; } #endif -static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) -{ - soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); - soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); -} - static int mt9t112_set_a_frame_size(const struct i2c_client *client, - u16 width, - u16 height) + u16 width, u16 height) { int ret; u16 wstart = (MAX_WIDTH - width) / 2; u16 hstart = (MAX_HEIGHT - height) / 2; - /* (Context A) Image Width/Height */ + /* (Context A) Image Width/Height. */ mt9t112_mcu_write(ret, client, VAR(26, 0), width); mt9t112_mcu_write(ret, client, VAR(26, 2), height); - /* (Context A) Output Width/Height */ + /* (Context A) Output Width/Height. */ mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); - /* (Context A) Start Row/Column */ + /* (Context A) Start Row/Column. */ mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); - /* (Context A) End Row/Column */ + /* (Context A) End Row/Column. */ mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); @@ -377,35 +368,27 @@ static int mt9t112_set_a_frame_size(const struct i2c_client *client, } static int mt9t112_set_pll_dividers(const struct i2c_client *client, - u8 m, u8 n, - u8 p1, u8 p2, u8 p3, - u8 p4, u8 p5, u8 p6, - u8 p7) + u8 m, u8 n, u8 p1, u8 p2, u8 p3, u8 p4, + u8 p5, u8 p6, u8 p7) { int ret; u16 val; /* N/M */ - val = (n << 8) | - (m << 0); + val = (n << 8) | (m << 0); mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); /* P1/P2/P3 */ - val = ((p3 & 0x0F) << 8) | - ((p2 & 0x0F) << 4) | - ((p1 & 0x0F) << 0); + val = ((p3 & 0x0F) << 8) | ((p2 & 0x0F) << 4) | ((p1 & 0x0F) << 0); mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); /* P4/P5/P6 */ - val = (0x7 << 12) | - ((p6 & 0x0F) << 8) | - ((p5 & 0x0F) << 4) | + val = (0x7 << 12) | ((p6 & 0x0F) << 8) | ((p5 & 0x0F) << 4) | ((p4 & 0x0F) << 0); mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); /* P7 */ - val = (0x1 << 12) | - ((p7 & 0x0F) << 0); + val = (0x1 << 12) | ((p7 & 0x0F) << 0); mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); return ret; @@ -418,19 +401,15 @@ static int mt9t112_init_pll(const struct i2c_client *client) mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); - /* PLL control: BYPASS PLL = 8517 */ + /* PLL control: BYPASS PLL = 8517. */ mt9t112_reg_write(ret, client, 0x0014, 0x2145); - /* Replace these registers when new timing parameters are generated */ + /* Replace these registers when new timing parameters are generated. */ mt9t112_set_pll_dividers(client, - priv->info->divider.m, - priv->info->divider.n, - priv->info->divider.p1, - priv->info->divider.p2, - priv->info->divider.p3, - priv->info->divider.p4, - priv->info->divider.p5, - priv->info->divider.p6, + priv->info->divider.m, priv->info->divider.n, + priv->info->divider.p1, priv->info->divider.p2, + priv->info->divider.p3, priv->info->divider.p4, + priv->info->divider.p5, priv->info->divider.p6, priv->info->divider.p7); /* @@ -452,20 +431,21 @@ static int mt9t112_init_pll(const struct i2c_client *client) * I2C Master Clock Divider */ mt9t112_reg_write(ret, client, 0x0014, 0x3046); - mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */ + /* JPEG initialization workaround */ + mt9t112_reg_write(ret, client, 0x0016, 0x0400); mt9t112_reg_write(ret, client, 0x0022, 0x0190); mt9t112_reg_write(ret, client, 0x3B84, 0x0212); - /* External sensor clock is PLL bypass */ + /* External sensor clock is PLL bypass. */ mt9t112_reg_write(ret, client, 0x002E, 0x0500); mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); - /* MCU disabled */ + /* MCU disabled. */ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); - /* out of standby */ + /* Out of standby. */ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); mdelay(50); @@ -487,10 +467,10 @@ static int mt9t112_init_pll(const struct i2c_client *client) mt9t112_reg_write(ret, client, 0x0614, 0x0001); mdelay(1); - /* poll to verify out of standby. Must Poll this bit */ + /* Poll to verify out of standby. Must Poll this bit. */ for (i = 0; i < 100; i++) { mt9t112_reg_read(data, client, 0x0018); - if (!(0x4000 & data)) + if (!(data & 0x4000)) break; mdelay(10); @@ -501,7 +481,6 @@ static int mt9t112_init_pll(const struct i2c_client *client) static int mt9t112_init_setting(const struct i2c_client *client) { - int ret; /* Adaptive Output Clock (A) */ @@ -562,11 +541,11 @@ static int mt9t112_init_setting(const struct i2c_client *client) mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); /* - * Flicker Dectection registers - * This section should be replaced whenever new Timing file is generated - * All the following registers need to be replaced + * Flicker Dectection registers. + * This section should be replaced whenever new timing file is + * generated. All the following registers need to be replaced. * Following registers are generated from Register Wizard but user can - * modify them. For detail see auto flicker detection tuning + * modify them. For detail see auto flicker detection tuning. */ /* FD_FDPERIOD_SELECT */ @@ -579,47 +558,47 @@ static int mt9t112_init_setting(const struct i2c_client *client) mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); /* - * AFD range detection tuning registers + * AFD range detection tuning registers. */ - /* search_f1_50 */ + /* Search_f1_50 */ mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); - /* search_f2_50 */ + /* Search_f2_50 */ mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); - /* search_f1_60 */ + /* Search_f1_60 */ mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); - /* search_f2_60 */ + /* Search_f2_60 */ mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); - /* period_50Hz (A) */ + /* Period_50Hz (A) */ mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); - /* secret register by aptina */ - /* period_50Hz (A MSB) */ + /* Secret register by Aptina. */ + /* Period_50Hz (A MSB) */ mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); - /* period_60Hz (A) */ + /* Period_60Hz (A) */ mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); - /* secret register by aptina */ - /* period_60Hz (A MSB) */ + /* Secret register by Aptina. */ + /* Period_60Hz (A MSB) */ mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); - /* period_50Hz (B) */ + /* Period_50Hz (B) */ mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); - /* secret register by aptina */ - /* period_50Hz (B) MSB */ + /* Secret register by Aptina. */ + /* Period_50Hz (B) MSB */ mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); - /* period_60Hz (B) */ + /* Period_60Hz (B) */ mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); - /* secret register by aptina */ - /* period_60Hz (B) MSB */ + /* Secret register by Aptina. */ + /* Period_60Hz (B) MSB */ mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); /* FD Mode */ @@ -693,49 +672,50 @@ static int mt9t112_init_camera(const struct i2c_client *client) int ret; ECHECKER(ret, mt9t112_reset(client)); - ECHECKER(ret, mt9t112_init_pll(client)); - ECHECKER(ret, mt9t112_init_setting(client)); - ECHECKER(ret, mt9t112_auto_focus_setting(client)); mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); - /* Analog setting B */ + /* Analog setting B.*/ mt9t112_reg_write(ret, client, 0x3084, 0x2409); mt9t112_reg_write(ret, client, 0x3092, 0x0A49); mt9t112_reg_write(ret, client, 0x3094, 0x4949); mt9t112_reg_write(ret, client, 0x3096, 0x4950); /* - * Disable adaptive clock + * Disable adaptive clock. * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); - /* Configure STatus in Status_before_length Format and enable header */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + /* + * Configure Status in Status_before_length Format and enable header. + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); - /* Enable JPEG in context B */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + /* + * Enable JPEG in context B. + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); - /* Disable Dac_TXLO */ + /* Disable Dac_TXLO. */ mt9t112_reg_write(ret, client, 0x316C, 0x350F); - /* Set max slew rates */ + /* Set max slew rates. */ mt9t112_reg_write(ret, client, 0x1E, 0x777); return ret; } /************************************************************************ - v4l2_subdev_core_ops -************************************************************************/ + * v4l2_subdev_core_ops + ***********************************************************************/ #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9t112_g_register(struct v4l2_subdev *sd, @@ -764,13 +744,40 @@ static int mt9t112_s_register(struct v4l2_subdev *sd, } #endif +static int mt9t112_power_on(struct mt9t112_priv *priv) +{ + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + if (priv->standby_gpio) { + gpiod_set_value(priv->standby_gpio, 0); + msleep(100); + } + + return 0; +} + +static int mt9t112_power_off(struct mt9t112_priv *priv) +{ + clk_disable_unprepare(priv->clk); + if (priv->standby_gpio) { + gpiod_set_value(priv->standby_gpio, 1); + msleep(100); + } + + return 0; +} + static int mt9t112_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct mt9t112_priv *priv = to_mt9t112(client); - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + return on ? mt9t112_power_on(priv) : + mt9t112_power_off(priv); } static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { @@ -781,10 +788,9 @@ static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { .s_power = mt9t112_s_power, }; - /************************************************************************ - v4l2_subdev_video_ops -************************************************************************/ + * v4l2_subdev_video_ops + **********************************************************************/ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -794,8 +800,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { /* FIXME * - * If user selected large output size, - * and used it long time, + * If user selected large output size, and used it long time, * mt9t112 camera will be very warm. * * But current driver can not stop mt9t112 camera. @@ -805,26 +810,25 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) return ret; } - if (!(priv->flags & INIT_DONE)) { - u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; + if (!priv->init_done) { + u16 param = MT9T112_FLAG_PCLK_RISING_EDGE & priv->info->flags ? + 0x0001 : 0x0000; ECHECKER(ret, mt9t112_init_camera(client)); - /* Invert PCLK (Data sampled on falling edge of pixclk) */ + /* Invert PCLK (Data sampled on falling edge of pixclk). */ mt9t112_reg_write(ret, client, 0x3C20, param); mdelay(5); - priv->flags |= INIT_DONE; + priv->init_done = true; } mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - mt9t112_set_a_frame_size(client, - priv->frame.width, - priv->frame.height); + mt9t112_set_a_frame_size(client, priv->frame.width, priv->frame.height); ECHECKER(ret, mt9t112_auto_focus_trigger(client)); @@ -854,13 +858,13 @@ static int mt9t112_set_params(struct mt9t112_priv *priv, if (i == priv->num_formats) return -EINVAL; - priv->frame = *rect; + priv->frame = *rect; /* * frame size check */ - mt9t112_frame_check(&priv->frame.width, &priv->frame.height, - &priv->frame.left, &priv->frame.top); + v4l_bound_align_image(&priv->frame.width, 0, MAX_WIDTH, 0, + &priv->frame.height, 0, MAX_HEIGHT, 0, 0); priv->format = mt9t112_cfmts + i; @@ -868,7 +872,7 @@ static int mt9t112_set_params(struct mt9t112_priv *priv, } static int mt9t112_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -899,8 +903,8 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd, } static int mt9t112_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); @@ -914,8 +918,8 @@ static int mt9t112_set_selection(struct v4l2_subdev *sd, } static int mt9t112_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -955,13 +959,12 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, } static int mt9t112_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &format->format; struct mt9t112_priv *priv = to_mt9t112(client); - unsigned int top, left; int i; if (format->pad) @@ -975,22 +978,24 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd, mf->code = MEDIA_BUS_FMT_UYVY8_2X8; mf->colorspace = V4L2_COLORSPACE_JPEG; } else { - mf->colorspace = mt9t112_cfmts[i].colorspace; + mf->colorspace = mt9t112_cfmts[i].colorspace; } - mt9t112_frame_check(&mf->width, &mf->height, &left, &top); + v4l_bound_align_image(&mf->width, 0, MAX_WIDTH, 0, + &mf->height, 0, MAX_HEIGHT, 0, 0); mf->field = V4L2_FIELD_NONE; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9t112_s_fmt(sd, mf); cfg->try_fmt = *mf; + return 0; } static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); @@ -1003,42 +1008,12 @@ static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) - priv->flags |= PCLK_RISING; - - return 0; -} - static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_stream = mt9t112_s_stream, - .g_mbus_config = mt9t112_g_mbus_config, - .s_mbus_config = mt9t112_s_mbus_config, }; static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { - .enum_mbus_code = mt9t112_enum_mbus_code, + .enum_mbus_code = mt9t112_enum_mbus_code, .get_selection = mt9t112_get_selection, .set_selection = mt9t112_set_selection, .get_fmt = mt9t112_get_fmt, @@ -1046,8 +1021,8 @@ static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { }; /************************************************************************ - i2c driver -************************************************************************/ + * i2c driver + ***********************************************************************/ static const struct v4l2_subdev_ops mt9t112_subdev_ops = { .core = &mt9t112_subdev_core_ops, .video = &mt9t112_subdev_video_ops, @@ -1065,9 +1040,7 @@ static int mt9t112_camera_probe(struct i2c_client *client) if (ret < 0) return ret; - /* - * check and show chip ID - */ + /* Check and show chip ID. */ mt9t112_reg_read(chipid, client, 0x0000); switch (chipid) { @@ -1089,6 +1062,7 @@ static int mt9t112_camera_probe(struct i2c_client *client) done: mt9t112_s_power(&priv->subdev, 0); + return ret; } @@ -1096,16 +1070,9 @@ static int mt9t112_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t112_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct v4l2_rect rect = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .left = (MAX_WIDTH - VGA_WIDTH) / 2, - .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, - }; int ret; - if (!ssdd || !ssdd->drv_priv) { + if (!client->dev.platform_data) { dev_err(&client->dev, "mt9t112: missing platform data!\n"); return -EINVAL; } @@ -1114,30 +1081,40 @@ static int mt9t112_probe(struct i2c_client *client, if (!priv) return -ENOMEM; - priv->info = ssdd->drv_priv; + priv->info = client->dev.platform_data; + priv->init_done = false; v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) + priv->clk = devm_clk_get(&client->dev, "extclk"); + if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = NULL; + } else if (IS_ERR(priv->clk)) { + dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); return PTR_ERR(priv->clk); + } - ret = mt9t112_camera_probe(client); + priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->standby_gpio)) { + dev_err(&client->dev, "Unable to get gpio \"standby\"\n"); + return PTR_ERR(priv->standby_gpio); + } - /* Cannot fail: using the default supported pixel code */ - if (!ret) - mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8); - else - v4l2_clk_put(priv->clk); + ret = mt9t112_camera_probe(client); + if (ret) + return ret; - return ret; + return v4l2_async_register_subdev(&priv->subdev); } static int mt9t112_remove(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); - v4l2_clk_put(priv->clk); + clk_disable_unprepare(priv->clk); + v4l2_async_unregister_subdev(&priv->subdev); + return 0; } @@ -1158,6 +1135,6 @@ static struct i2c_driver mt9t112_i2c_driver = { module_i2c_driver(mt9t112_i2c_driver); -MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); +MODULE_DESCRIPTION("V4L2 driver for MT9T111/MT9T112 camera sensor"); MODULE_AUTHOR("Kuninori Morimoto"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 297d22ebcb18..b53c36dfa469 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -85,7 +85,7 @@ struct mt9t112_format { struct mt9t112_priv { struct v4l2_subdev subdev; - struct mt9t112_camera_info *info; + struct mt9t112_platform_data *info; struct i2c_client *client; struct v4l2_rect frame; struct v4l2_clk *clk; -- cgit From 2c000f4dbab0fae81ca7717b3fe5d0baa16483d1 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sat, 10 Mar 2018 07:24:43 -0500 Subject: media: ttpci: improve printing of encoded MAC address When loading the budget_av driver for ie. a KNC1 DVB-C TDA10024 card, which makes use of the ttpci eeprom check functionality (that always fails on these cards, but that's no issue at all), this is printed to the kernel log: [ 10.497333] saa7146 (0): dma buffer size 192512 [ 10.497335] dvbdev: DVB: registering new adapter (KNC1 DVB-C TDA10024) [ 10.545007] adapter failed MAC signature check [ 10.545009] encoded MAC from EEPROM was [ 10.545010] ff: [ 10.545011] ff: [ 10.545011] ff: ... [ 10.545021] ff [ 10.832422] budget_av: KNC1-4: MAC addr = 00:09:d6:6d:b3:be with the 'ff' being repeated for a total of 20 times. Improve that by using the %*phC format specifier instead dprintk()'ing every byte of the encoded MAC separately. This obsoletes the int i, and the kernel log looks cleaner: [ 3234.383153] saa7146 (0): dma buffer size 192512 [ 3234.383154] dvbdev: DVB: registering new adapter (KNC1 DVB-C TDA10024) [ 3234.428745] adapter failed MAC signature check [ 3234.428747] encoded MAC from EEPROM was ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff [ 3234.728194] budget_av: KNC1-0: MAC addr = 00:09:d6:6d:b3:be Signed-off-by: Daniel Scheller Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/ttpci-eeprom.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 9534f29c1ffd..78c7a6589be5 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -138,7 +138,7 @@ static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encode int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) { - int ret, i; + int ret; u8 encodedMAC[20]; u8 decodedMAC[6]; @@ -153,11 +153,8 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) ret = getmac_tt(decodedMAC, encodedMAC); if( ret != 0 ) { dprintk("adapter failed MAC signature check\n"); - dprintk("encoded MAC from EEPROM was " ); - for(i=0; i<19; i++) { - dprintk( "%.2x:", encodedMAC[i]); - } - dprintk("%.2x\n", encodedMAC[19]); + dprintk("encoded MAC from EEPROM was %*phC", + (int)sizeof(encodedMAC), &encodedMAC); eth_zero_addr(proposed_mac); return ret; } -- cgit From 9fbc5a3245f8b32ef941e39597ba7b5e15b07376 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Mar 2018 08:05:36 -0400 Subject: media: v4l: omap_vout: vrfb: remove an unused variable We now get a warning after the 'dmadev' variable is no longer used: drivers/media/platform/omap/omap_vout_vrfb.c: In function 'omap_vout_prepare_vrfb': drivers/media/platform/omap/omap_vout_vrfb.c:239:21: error: unused variable 'dmadev' [-Werror=unused-variable] Fixes: 8f0aa38292f2 ("media: v4l: omap_vout: vrfb: Use the wrapper for prep_interleaved_dma()") Signed-off-by: Arnd Bergmann Reviewed-by: Peter Ujfalusi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout_vrfb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 72c0ac2cbf3d..1d8508237220 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -236,7 +236,6 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct dma_async_tx_descriptor *tx; enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_chan *chan = vout->vrfb_dma_tx.chan; - struct dma_device *dmadev = chan->device; struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt; dma_cookie_t cookie; enum dma_status status; -- cgit From 492b183bd7bcaede57381f4d06e19f1983083781 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Mar 2018 09:06:03 -0400 Subject: media: ngene: avoid unused variable warning The newly added pdev variable is only used in an #ifdef, causing a build warning without CONFIG_PCI_MSI, unless we move the declaration inside the same #ifdef: drivers/media/pci/ngene/ngene-core.c: In function 'ngene_start': drivers/media/pci/ngene/ngene-core.c:1328:17: error: unused variable 'pdev' [-Werror=unused-variable] Fixes: 6795bf626482 ("media: ngene: convert kernellog printing from printk() to dev_*() macros") Signed-off-by: Arnd Bergmann Acked-by: Daniel Scheller Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 3b9a1bfaf6c0..25f16833a475 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1325,7 +1325,6 @@ static int ngene_buffer_config(struct ngene *dev) static int ngene_start(struct ngene *dev) { - struct device *pdev = &dev->pci_dev->dev; int stat; int i; @@ -1359,6 +1358,7 @@ static int ngene_start(struct ngene *dev) #ifdef CONFIG_PCI_MSI /* enable MSI if kernel and card support it */ if (pci_msi_enabled() && dev->card_info->msi_supported) { + struct device *pdev = &dev->pci_dev->dev; unsigned long flags; ngwritel(0, NGENE_INT_ENABLE); -- cgit From 6a8ffa8b4c519419f7b926904f02c8d1fec5b488 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 13 Mar 2018 22:49:09 -0400 Subject: media: rcar-vin: allocate a scratch buffer at stream start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before starting a capture, allocate a scratch buffer which can be used by the driver to give to the hardware if no buffers are available from userspace. The buffer is not used in this patch but prepares for future refactoring where the scratch buffer can be used to avoid the need to fallback on single capture mode if userspace can't queue buffers as fast as the VIN driver consumes them. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 19 +++++++++++++++++++ drivers/media/platform/rcar-vin/rcar-vin.h | 4 ++++ 2 files changed, 23 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 23fdff7a7370..1f91b056188e 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -1076,6 +1076,17 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; + /* Allocate scratch buffer. */ + vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, + &vin->scratch_phys, GFP_KERNEL); + if (!vin->scratch) { + spin_lock_irqsave(&vin->qlock, flags); + return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + spin_unlock_irqrestore(&vin->qlock, flags); + vin_err(vin, "Failed to allocate scratch buffer\n"); + return -ENOMEM; + } + sd = vin_to_source(vin); v4l2_subdev_call(sd, video, s_stream, 1); @@ -1091,6 +1102,10 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) spin_unlock_irqrestore(&vin->qlock, flags); + if (ret) + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); + return ret; } @@ -1141,6 +1156,10 @@ static void rvin_stop_streaming(struct vb2_queue *vq) /* disable interrupts */ rvin_disable_interrupts(vin); + + /* Free scratch buffer. */ + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); } static const struct vb2_ops rvin_qops = { diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 5382078143fb..00b405f78d09 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -102,6 +102,8 @@ struct rvin_graph_entity { * * @lock: protects @queue * @queue: vb2 buffers queue + * @scratch: cpu address for scratch buffer + * @scratch_phys: physical address of the scratch buffer * * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence * @state @@ -130,6 +132,8 @@ struct rvin_dev { struct mutex lock; struct vb2_queue queue; + void *scratch; + dma_addr_t scratch_phys; spinlock_t qlock; struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; -- cgit From dc9aec795f53c0cff46ee03e28309f75637b5f60 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 13 Mar 2018 22:49:10 -0400 Subject: media: rcar-vin: use scratch buffer and always run in continuous mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of switching capture mode depending on how many buffers are available use a scratch buffer and always run in continuous mode. By using a scratch buffer the responsiveness of the capture loop is increased as it can keep running even if there are no buffers available from userspace. As soon as a userspace queues a buffer it is inserted into the capture loop and returned as soon as it is filled. This is a improvement on the previous logic where the whole capture loop was stopped and switched to single capture mode if userspace did not feed the VIN driver buffers at the same time it consumed them. To make matters worse it was difficult for the driver to reenter continuous mode if it entered single mode even if userspace started to queue buffers faster. This resulted in suboptimal performance where if userspace where delayed for a short period the ongoing capture would be slowed down and run in single mode until the capturing process where restarted. An additional effect of this change is that the capture logic can be made much simple as we know that continuous mode will always be used. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 187 ++++++++--------------------- drivers/media/platform/rcar-vin/rcar-vin.h | 6 +- 2 files changed, 52 insertions(+), 141 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 1f91b056188e..4a40e6ad1be7 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -168,12 +168,8 @@ static int rvin_setup(struct rvin_dev *vin) break; case V4L2_FIELD_ALTERNATE: case V4L2_FIELD_NONE: - if (vin->continuous) { - vnmc = VNMC_IM_ODD_EVEN; - progressive = true; - } else { - vnmc = VNMC_IM_ODD; - } + vnmc = VNMC_IM_ODD_EVEN; + progressive = true; break; default: vnmc = VNMC_IM_ODD; @@ -298,14 +294,6 @@ static bool rvin_capture_active(struct rvin_dev *vin) return rvin_read(vin, VNMS_REG) & VNMS_CA; } -static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms) -{ - if (vin->continuous) - return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; - - return 0; -} - static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) { if (vin->format.field == V4L2_FIELD_ALTERNATE) { @@ -344,76 +332,47 @@ static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) rvin_write(vin, offset, VNMB_REG(slot)); } -/* Moves a buffer from the queue to the HW slots */ -static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot) +/* + * Moves a buffer from the queue to the HW slot. If no buffer is + * available use the scratch buffer. The scratch buffer is never + * returned to userspace, its only function is to enable the capture + * loop to keep running. + */ +static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) { struct rvin_buffer *buf; struct vb2_v4l2_buffer *vbuf; - dma_addr_t phys_addr_top; - - if (vin->queue_buf[slot] != NULL) - return true; + dma_addr_t phys_addr; - if (list_empty(&vin->buf_list)) - return false; + /* A already populated slot shall never be overwritten. */ + if (WARN_ON(vin->queue_buf[slot] != NULL)) + return; vin_dbg(vin, "Filling HW slot: %d\n", slot); - /* Keep track of buffer we give to HW */ - buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); - vbuf = &buf->vb; - list_del_init(to_buf_list(vbuf)); - vin->queue_buf[slot] = vbuf; - - /* Setup DMA */ - phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); - rvin_set_slot_addr(vin, slot, phys_addr_top); - - return true; -} - -static bool rvin_fill_hw(struct rvin_dev *vin) -{ - int slot, limit; - - limit = vin->continuous ? HW_BUFFER_NUM : 1; - - for (slot = 0; slot < limit; slot++) - if (!rvin_fill_hw_slot(vin, slot)) - return false; - return true; -} - -static void rvin_capture_on(struct rvin_dev *vin) -{ - vin_dbg(vin, "Capture on in %s mode\n", - vin->continuous ? "continuous" : "single"); + if (list_empty(&vin->buf_list)) { + vin->queue_buf[slot] = NULL; + phys_addr = vin->scratch_phys; + } else { + /* Keep track of buffer we give to HW */ + buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); + vbuf = &buf->vb; + list_del_init(to_buf_list(vbuf)); + vin->queue_buf[slot] = vbuf; + + /* Setup DMA */ + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + } - if (vin->continuous) - /* Continuous Frame Capture Mode */ - rvin_write(vin, VNFC_C_FRAME, VNFC_REG); - else - /* Single Frame Capture Mode */ - rvin_write(vin, VNFC_S_FRAME, VNFC_REG); + rvin_set_slot_addr(vin, slot, phys_addr); } static int rvin_capture_start(struct rvin_dev *vin) { - struct rvin_buffer *buf, *node; - int bufs, ret; + int slot, ret; - /* Count number of free buffers */ - bufs = 0; - list_for_each_entry_safe(buf, node, &vin->buf_list, list) - bufs++; - - /* Continuous capture requires more buffers then there are HW slots */ - vin->continuous = bufs > HW_BUFFER_NUM; - - if (!rvin_fill_hw(vin)) { - vin_err(vin, "HW not ready to start, not enough buffers available\n"); - return -EINVAL; - } + for (slot = 0; slot < HW_BUFFER_NUM; slot++) + rvin_fill_hw_slot(vin, slot); rvin_crop_scale_comp(vin); @@ -421,7 +380,10 @@ static int rvin_capture_start(struct rvin_dev *vin) if (ret) return ret; - rvin_capture_on(vin); + vin_dbg(vin, "Starting to capture\n"); + + /* Continuous Frame Capture Mode */ + rvin_write(vin, VNFC_C_FRAME, VNFC_REG); vin->state = RUNNING; @@ -904,7 +866,7 @@ static irqreturn_t rvin_irq(int irq, void *data) struct rvin_dev *vin = data; u32 int_status, vnms; int slot; - unsigned int i, sequence, handled = 0; + unsigned int handled = 0; unsigned long flags; spin_lock_irqsave(&vin->qlock, flags); @@ -930,65 +892,25 @@ static irqreturn_t rvin_irq(int irq, void *data) /* Prepare for capture and update state */ vnms = rvin_read(vin, VNMS_REG); - slot = rvin_get_active_slot(vin, vnms); - sequence = vin->sequence++; - - vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", - sequence, slot, - slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0', - slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0', - slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0', - !list_empty(&vin->buf_list)); - - /* HW have written to a slot that is not prepared we are in trouble */ - if (WARN_ON((vin->queue_buf[slot] == NULL))) - goto done; + slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; /* Capture frame */ - vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); - vin->queue_buf[slot]->sequence = sequence; - vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); - vin->queue_buf[slot] = NULL; - - /* Prepare for next frame */ - if (!rvin_fill_hw(vin)) { - - /* - * Can't supply HW with new buffers fast enough. Halt - * capture until more buffers are available. - */ - vin->state = STALLED; - - /* - * The continuous capturing requires an explicit stop - * operation when there is no buffer to be set into - * the VnMBm registers. - */ - if (vin->continuous) { - rvin_capture_stop(vin); - vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence); - - /* Maybe we can continue in single capture mode */ - for (i = 0; i < HW_BUFFER_NUM; i++) { - if (vin->queue_buf[i]) { - list_add(to_buf_list(vin->queue_buf[i]), - &vin->buf_list); - vin->queue_buf[i] = NULL; - } - } - - if (!list_empty(&vin->buf_list)) - rvin_capture_start(vin); - } + if (vin->queue_buf[slot]) { + vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); + vin->queue_buf[slot]->sequence = vin->sequence; + vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); + vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, + VB2_BUF_STATE_DONE); + vin->queue_buf[slot] = NULL; } else { - /* - * The single capturing requires an explicit capture - * operation to fetch the next frame. - */ - if (!vin->continuous) - rvin_capture_on(vin); + /* Scratch buffer was used, dropping frame. */ + vin_dbg(vin, "Dropping frame %u\n", vin->sequence); } + + vin->sequence++; + + /* Prepare for next frame */ + rvin_fill_hw_slot(vin, slot); done: spin_unlock_irqrestore(&vin->qlock, flags); @@ -1059,13 +981,6 @@ static void rvin_buffer_queue(struct vb2_buffer *vb) list_add_tail(to_buf_list(vbuf), &vin->buf_list); - /* - * If capture is stalled add buffer to HW and restart - * capturing if HW is ready to continue. - */ - if (vin->state == STALLED) - rvin_capture_start(vin); - spin_unlock_irqrestore(&vin->qlock, flags); } @@ -1208,7 +1123,7 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq) q->ops = &rvin_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_buffers_needed = 4; q->dev = vin->dev; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 00b405f78d09..95897127cc41 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -38,13 +38,11 @@ enum chip_id { /** * STOPPED - No operation in progress * RUNNING - Operation in progress have buffers - * STALLED - No operation in progress have no buffers * STOPPING - Stopping operation */ enum rvin_dma_state { STOPPED = 0, RUNNING, - STALLED, STOPPING, }; @@ -105,11 +103,10 @@ struct rvin_graph_entity { * @scratch: cpu address for scratch buffer * @scratch_phys: physical address of the scratch buffer * - * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence + * @qlock: protects @queue_buf, @buf_list, @sequence * @state * @queue_buf: Keeps track of buffers given to HW slot * @buf_list: list of queued buffers - * @continuous: tracks if active operation is continuous or single mode * @sequence: V4L2 buffers sequence number * @state: keeps track of operation state * @@ -138,7 +135,6 @@ struct rvin_dev { spinlock_t qlock; struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; struct list_head buf_list; - bool continuous; unsigned int sequence; enum rvin_dma_state state; -- cgit From 1c791727b73c190494a96789486e282945775d49 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:42 -0500 Subject: media: v4l2-ioctl: add HEVC format description HEVC is a video coding format Signed-off-by: Smitha T Murthy Reviewed-by: Stanimir Varbanov Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f697c235f698..672ab22ccd96 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1273,6 +1273,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; case V4L2_PIX_FMT_VP8: descr = "VP8"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; + case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; -- cgit From 2c02837bd99cda8e4f8b9cb5ea74956242b5c851 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:46 -0500 Subject: media: v4l2: Add v4l2 control IDs for HEVC encoder Add v4l2 controls for HEVC encoder Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 119 +++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ce08b50b8290..d29e45516eb7 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -480,6 +480,57 @@ const char * const *v4l2_ctrl_get_menu(u32 id) NULL, }; + static const char * const hevc_profile[] = { + "Main", + "Main Still Picture", + "Main 10", + NULL, + }; + static const char * const hevc_level[] = { + "1", + "2", + "2.1", + "3", + "3.1", + "4", + "4.1", + "5", + "5.1", + "5.2", + "6", + "6.1", + "6.2", + NULL, + }; + static const char * const hevc_hierarchial_coding_type[] = { + "B", + "P", + NULL, + }; + static const char * const hevc_refresh_type[] = { + "None", + "CRA", + "IDR", + NULL, + }; + static const char * const hevc_size_of_length_field[] = { + "0", + "1", + "2", + "4", + NULL, + }; + static const char * const hevc_tier[] = { + "Main", + "High", + NULL, + }; + static const char * const hevc_loop_filter_mode[] = { + "Disabled", + "Enabled", + "Disabled at slice boundary", + "NULL", + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -575,6 +626,20 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return dv_it_content_type; case V4L2_CID_DETECT_MD_MODE: return detect_md_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + return hevc_profile; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + return hevc_level; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + return hevc_hierarchial_coding_type; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + return hevc_refresh_type; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + return hevc_size_of_length_field; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + return hevc_tier; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + return hevc_loop_filter_mode; default: return NULL; @@ -776,6 +841,53 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: return "VPX Profile"; + /* HEVC controls */ + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile"; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level"; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier"; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding"; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront"; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate"; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB"; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID"; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing"; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split"; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction"; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs"; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode"; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset"; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; + /* CAMERA controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ case V4L2_CID_CAMERA_CLASS: return "Camera Controls"; @@ -1069,6 +1181,13 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_TUNE_DEEMPHASIS: case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: case V4L2_CID_DETECT_MD_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: -- cgit From f1a355bf9e2e32e4c1584ff4e78129bb052a2741 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:37 -0500 Subject: media: s5p-mfc: Rename IS_MFCV8 macro This patch renames macro IS_MFCV8 to IS_MFCV8_PLUS so that the MFCv8 code can be resued for MFCv10.10 support. Since the MFCv8 specific code holds good for MFC v10.10 also. Signed-off-by: Smitha T Murthy Acked-by: Andrzej Hajda Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 18 +++++++++--------- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 76119a8cc477..91090fc5a551 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -714,7 +714,7 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) #define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) #define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) -#define IS_MFCV8(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) #define MFC_V5_BIT BIT(0) #define MFC_V6_BIT BIT(1) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f95cd76af537..a1c729c197d3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -399,7 +399,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Send MFC wakeup command and wait for completion*/ - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ret = s5p_mfc_v8_wait_wakeup(dev); else ret = s5p_mfc_wait_wakeup(dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 8937b0af7cb3..42e9351303a2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -1177,7 +1177,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) struct v4l2_format f; f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; ctx->src_fmt = find_format(&f, MFC_FMT_DEC); - if (IS_MFCV8(ctx->dev)) + if (IS_MFCV8_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; else if (IS_MFCV6_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 88dbb9c341ec..fe144799e304 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -74,7 +74,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size, ctx->chroma_size, ctx->mv_size); mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); } else if (ctx->type == MFCINST_ENCODER) { - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); @@ -89,7 +89,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( ctx->img_width, ctx->img_height, mb_width, mb_height), @@ -110,7 +110,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( mb_width, @@ -167,7 +167,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_VP8_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( mb_width, @@ -182,7 +182,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_H264_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( mb_width, @@ -215,7 +215,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_VP8_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( mb_width, @@ -364,7 +364,7 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); - if (IS_MFCV8(ctx->dev)) { + if (IS_MFCV8_PLUS(ctx->dev)) { /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/ ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; @@ -445,7 +445,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); - if (IS_MFCV8(dev)) { + if (IS_MFCV8_PLUS(dev)) { writel(ctx->img_width, mfc_regs->d_first_plane_dpb_stride_size); writel(ctx->img_width, @@ -2109,7 +2109,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7); R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7); - if (!IS_MFCV8(dev)) + if (!IS_MFCV8_PLUS(dev)) goto done; /* Initialize registers used in MFC v8 only. -- cgit From b1394dc151cba4c50316ea43136b28de541c043b Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:38 -0500 Subject: media: s5p-mfc: Adding initial support for MFC v10.10 Adding the support for MFC v10.10, with new register file and necessary hw control, decoder, encoder and structural changes. Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Rob Herring Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 35 +++++++++++++++++++++++++ drivers/media/platform/s5p-mfc/s5p_mfc.c | 25 ++++++++++++++++++ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 9 ++++++- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 4 +++ drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 32 +++++++++------------- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 16 +++++------ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 9 +++++-- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 2 ++ 8 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 drivers/media/platform/s5p-mfc/regs-mfc-v10.h (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h new file mode 100644 index 000000000000..4422a75db727 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register definition file for Samsung MFC V10.x Interface (FIMV) driver + * + */ + +#ifndef _REGS_MFC_V10_H +#define _REGS_MFC_V10_H + +#include +#include "regs-mfc-v8.h" + +/* MFCv10 register definitions*/ +#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 +#define S5P_FIMV_MFC_STATE_V10 0x7124 + +/* MFCv10 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) +#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) + +/* MFCv10 variant defines */ +#define MAX_FW_SIZE_V10 (SZ_1M) +#define MAX_CPB_SIZE_V10 (3 * SZ_1M) +#define MFC_VERSION_V10 0xA0 +#define MFC_NUM_PORTS_V10 1 + +#endif /*_REGS_MFC_V10_H*/ + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d5b94fc0040e..a653e3a9197a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1607,6 +1607,28 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .num_clocks = 3, }; +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V10, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, +}; + +static struct s5p_mfc_buf_size buf_size_v10 = { + .fw = MAX_FW_SIZE_V10, + .cpb = MAX_CPB_SIZE_V10, + .priv = &mfc_buf_size_v10, +}; + +static struct s5p_mfc_variant mfc_drvdata_v10 = { + .version = MFC_VERSION_V10, + .version_bit = MFC_V10_BIT, + .port_num = MFC_NUM_PORTS_V10, + .buf_size = &buf_size_v10, + .fw_name[0] = "s5p-mfc-v10.fw", +}; + static const struct of_device_id exynos_mfc_match[] = { { .compatible = "samsung,mfc-v5", @@ -1623,6 +1645,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,exynos5433-mfc", .data = &mfc_drvdata_v8_5433, + }, { + .compatible = "samsung,mfc-v10", + .data = &mfc_drvdata_v10, }, {}, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 91090fc5a551..c4f0968534b5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -23,7 +23,7 @@ #include #include #include "regs-mfc.h" -#include "regs-mfc-v8.h" +#include "regs-mfc-v10.h" #define S5P_MFC_NAME "s5p-mfc" @@ -715,11 +715,18 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) #define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) #define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) #define MFC_V5_BIT BIT(0) #define MFC_V6_BIT BIT(1) #define MFC_V7_BIT BIT(2) #define MFC_V8_BIT BIT(3) +#define MFC_V10_BIT BIT(5) +#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \ + MFC_V8_BIT | MFC_V10_BIT) +#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \ + MFC_V10_BIT) +#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT) #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index a1c729c197d3..76405f5b4f7e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -239,6 +239,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } else mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + + if (IS_MFCV10(dev)) + mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10); + mfc_debug(2, "Will now wait for completion of firmware transfer\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 42e9351303a2..81de3029f76c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -54,7 +54,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -62,7 +62,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -70,8 +70,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H264/MVC Encoded Stream", @@ -79,7 +78,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -87,8 +86,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG1 Encoded Stream", @@ -96,8 +94,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG2 Encoded Stream", @@ -105,8 +102,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -114,8 +110,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "XviD Encoded Stream", @@ -123,8 +118,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 Encoded Stream", @@ -132,8 +126,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 RCV Encoded Stream", @@ -141,8 +134,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -150,7 +142,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 0d5d465561be..9a21e8c34112 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -57,8 +57,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -66,7 +65,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -74,8 +73,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -83,8 +81,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -92,8 +89,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -101,7 +97,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V7PLUS_BITS, }, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index fe144799e304..2041d8138c5f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -356,6 +356,7 @@ static int calc_plane(int width, int height) static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) { + struct s5p_mfc_dev *dev = ctx->dev; ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" @@ -372,8 +373,12 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { - ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, - ctx->img_height); + if (IS_MFCV10(dev)) + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, + ctx->img_height); + else + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); ctx->mv_size = ALIGN(ctx->mv_size, 16); } else { ctx->mv_size = 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index 80558484bb40..021b8dbe2244 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -24,6 +24,8 @@ #define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) #define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) +#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) /* Definition */ #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) -- cgit From c8ffbd433a77122501197f456fb4acd59d38456b Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:39 -0500 Subject: media: s5p-mfc: Use min scratch buffer size as provided by F/W After MFC v8.0, mfc f/w lets the driver know how much scratch buffer size is required for decoder. If mfc f/w has the functionality, E_MIN_SCRATCH_BUFFER_SIZE, driver can know how much scratch buffer size is required for encoder too. Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 + drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 5 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | 4 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 68 ++++++++++++++++++------- 6 files changed, 65 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 75f5f7511d72..bd639ae71023 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -17,6 +17,7 @@ /* Additional registers for v8 */ #define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104 +#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108 #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144 #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148 #define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150 @@ -84,6 +85,7 @@ #define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c #define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790 +#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894 #define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c #define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index a653e3a9197a..77dc9e527c41 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -526,6 +526,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index c4f0968534b5..babc1cc36110 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -716,6 +716,7 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) #define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) #define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) +#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev)) #define MFC_V5_BIT BIT(0) #define MFC_V6_BIT BIT(1) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 9a21e8c34112..a846a4d1edbe 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -813,6 +813,11 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) get_enc_dpb_count, dev); if (ctx->pb_count < enc_pb_count) ctx->pb_count = enc_pb_count; + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_e_min_scratch_buf_size, dev); + ctx->bank1.size += ctx->scratch_buf_size; + } ctx->state = MFCINST_HEAD_PRODUCED; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 16d553fcff08..e7a2d463139d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -169,6 +169,7 @@ struct s5p_mfc_regs { void __iomem *d_decoded_third_addr;/* only v7 */ void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_min_scratch_buffer_size; /* v10 */ /* encoder registers */ void __iomem *e_frame_width; @@ -268,6 +269,7 @@ struct s5p_mfc_regs { void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + void __iomem *e_min_scratch_buffer_size; /* v10 */ }; struct s5p_mfc_hw_ops { @@ -311,6 +313,8 @@ struct s5p_mfc_hw_ops { unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); + int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev); + int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev); }; void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 2041d8138c5f..7f17857153f3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -110,7 +110,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: - if (IS_MFCV8_PLUS(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( mb_width, @@ -127,7 +129,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) (ctx->mv_count * ctx->mv_size); break; case S5P_MFC_CODEC_MPEG4_DEC: - if (IS_MFCV7_PLUS(dev)) { + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV7_PLUS(dev)) { ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7( mb_width, @@ -145,10 +149,14 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_VC1RCV_DEC: case S5P_MFC_CODEC_VC1_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; @@ -158,16 +166,21 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_H263_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_VP8_DEC: - if (IS_MFCV8_PLUS(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( mb_width, @@ -182,7 +195,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_H264_ENC: - if (IS_MFCV8_PLUS(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( mb_width, @@ -202,10 +217,13 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + } else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = @@ -215,7 +233,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_VP8_ENC: - if (IS_MFCV8_PLUS(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( mb_width, @@ -1900,6 +1920,16 @@ static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) return readl(dev->mfc_regs->d_min_num_mv); } +static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_scratch_buffer_size); +} + +static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_min_scratch_buffer_size); +} + static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) { return readl(dev->mfc_regs->ret_instance_id); @@ -2158,6 +2188,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8); R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8); R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8); + R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8); /* encoder registers */ R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8); @@ -2173,6 +2204,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8); R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8); R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); + R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); done: return &mfc_regs; @@ -2221,6 +2253,8 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, + .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size, + .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, }; struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) -- cgit From 1c700fa76b8d62c405974192b51f1899d30add17 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:40 -0500 Subject: media: s5p-mfc: Support MFCv10.10 buffer requirements Aligning the luma_dpb_size, chroma_dpb_size, mv_size and me_buffer_size for MFCv10.10. Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Kamil Debski Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 19 +++++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 93 +++++++++++++++++++------ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 2 + 3 files changed, 94 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h index 4422a75db727..7b28313dcc15 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -31,5 +31,24 @@ #define MFC_VERSION_V10 0xA0 #define MFC_NUM_PORTS_V10 1 +/* MFCv10 codec defines*/ +#define S5P_FIMV_CODEC_HEVC_ENC 26 + +/* Encoder buffer size for MFC v10.0 */ +#define ENC_V100_BASE_SIZE(x, y) \ + (((x + 3) * (y + 3) * 8) \ + + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8)) + +#define ENC_V100_H264_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 64) * 32)) + +#define ENC_V100_MPEG4_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 128) * 16)) + +#define ENC_V100_VP8_ME_SIZE(x, y) \ + ENC_V100_BASE_SIZE(x, y) + #endif /*_REGS_MFC_V10_H*/ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 7f17857153f3..55ccccb95219 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -64,6 +64,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; int ret; mb_width = MB_WIDTH(ctx->img_width); @@ -74,7 +75,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size, ctx->chroma_size, ctx->mv_size); mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); } else if (ctx->type == MFCINST_ENCODER) { - if (IS_MFCV8_PLUS(dev)) + if (IS_MFCV10(dev)) { + ctx->tmv_buffer_size = 0; + } else if (IS_MFCV8_PLUS(dev)) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); @@ -82,13 +85,36 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); - - ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_LUMA_MB_TO_PIXEL_V6, - S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); - ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, - S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + if (IS_MFCV10(dev)) { + lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width); + lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height); + if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) { + ctx->luma_dpb_size = + ALIGN((mb_width * 16), 64) + * ALIGN((mb_height * 16), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((mb_width * 16), 64) + * (mb_height * 8) + + 64; + } else { + ctx->luma_dpb_size = + ALIGN((lcu_width * 32), 64) + * ALIGN((lcu_height * 32), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((lcu_width * 32), 64) + * (lcu_height * 16) + + 64; + } + } else { + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + } if (IS_MFCV8_PLUS(dev)) ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( ctx->img_width, ctx->img_height, @@ -197,6 +223,8 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_H264_ENC: if (IS_MFCV10(dev)) { mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16); } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( @@ -219,6 +247,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_H263_ENC: if (IS_MFCV10(dev)) { mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, + mb_height), 16); } else ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( @@ -235,6 +266,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_ENC: if (IS_MFCV10(dev)) { mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), + 16); } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( @@ -393,13 +427,13 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { - if (IS_MFCV10(dev)) + if (IS_MFCV10(dev)) { ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, ctx->img_height); - else + } else { ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, ctx->img_height); - ctx->mv_size = ALIGN(ctx->mv_size, 16); + } } else { ctx->mv_size = 0; } @@ -596,15 +630,34 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; - writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; - writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + - ctx->me_buffer_size); + if (IS_MFCV10(dev)) { + /* start address of per buffer is aligned */ + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + buf_size1 -= ctx->luma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + buf_size1 -= ctx->chroma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= ctx->me_buffer_size; + } + } else { + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } } writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index 021b8dbe2244..b18f5b73c0d0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -26,6 +26,8 @@ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) #define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) +#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) +#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) /* Definition */ #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) -- cgit From c9fcd51c167651a34ab0e0d39f39565a44712f57 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:44 -0500 Subject: media: s5p-mfc: Add support for HEVC decoder Add support for codec definition and corresponding buffer requirements for HEVC decoder. Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 3 +++ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 7 +++++++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 17 +++++++++++++++-- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 3 +++ 6 files changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h index 7b28313dcc15..d9054683ab14 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -32,6 +32,7 @@ #define MFC_NUM_PORTS_V10 1 /* MFCv10 codec defines*/ +#define S5P_FIMV_CODEC_HEVC_DEC 17 #define S5P_FIMV_CODEC_HEVC_ENC 26 /* Encoder buffer size for MFC v10.0 */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index b1b149151d2d..76eca67e0cd5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -101,6 +101,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_DEC: codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; break; + case S5P_MFC_CODEC_HEVC_DEC: + codec_type = S5P_FIMV_CODEC_HEVC_DEC; + break; case S5P_MFC_CODEC_H264_ENC: codec_type = S5P_FIMV_CODEC_H264_ENC_V6; break; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index babc1cc36110..702e136769a2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -72,6 +72,7 @@ #define S5P_MFC_CODEC_H263_DEC 5 #define S5P_MFC_CODEC_VC1RCV_DEC 6 #define S5P_MFC_CODEC_VP8_DEC 7 +#define S5P_MFC_CODEC_HEVC_DEC 17 #define S5P_MFC_CODEC_H264_ENC 20 #define S5P_MFC_CODEC_H264_MVC_ENC 21 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 81de3029f76c..474935540ac8 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -144,6 +144,13 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 1, .versions = MFC_V6PLUS_BITS, }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, }; #define NUM_FORMATS ARRAY_SIZE(formats) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 55ccccb95219..8c47294168b5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -220,6 +220,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; + case S5P_MFC_CODEC_HEVC_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; case S5P_MFC_CODEC_H264_ENC: if (IS_MFCV10(dev)) { mfc_debug(2, "Use min scratch buffer size\n"); @@ -321,6 +327,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: + case S5P_MFC_CODEC_HEVC_DEC: ctx->ctx.size = buf_size->h264_dec_ctx; break; case S5P_MFC_CODEC_MPEG4_DEC: @@ -434,6 +441,10 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, ctx->img_height); } + } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { + ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, + ctx->img_height); + ctx->mv_size = ALIGN(ctx->mv_size, 32); } else { ctx->mv_size = 0; } @@ -515,7 +526,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= ctx->scratch_buf_size; if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) { writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); writel(ctx->mv_count, mfc_regs->d_num_mv); } @@ -538,7 +550,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_regs->d_second_plane_dpb + i * 4); } if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { for (i = 0; i < ctx->mv_count; i++) { /* To test alignment */ align_gap = buf_addr1; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index b18f5b73c0d0..f6cb703e586f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -29,6 +29,9 @@ #define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) #define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) +#define s5p_mfc_dec_hevc_mv_size(x, y) \ + (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512) + /* Definition */ #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) #define ENC_MULTI_SLICE_BIT_MIN 2800 -- cgit From fc92b92a04dd8cffccdc3173361c64e96985f5a1 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:45 -0500 Subject: media: s5p-mfc: Add VP9 decoder support Add support for codec definition and corresponding buffer requirements for VP9 decoder. Signed-off-by: Smitha T Murthy Reviewed-by: Andrzej Hajda Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 6 ++++++ drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 3 +++ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 7 +++++++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | 2 ++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 26 +++++++++++++++++++++++++ 6 files changed, 45 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h index d9054683ab14..bbfa1cf89b10 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -17,6 +17,8 @@ /* MFCv10 register definitions*/ #define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 #define S5P_FIMV_MFC_STATE_V10 0x7124 +#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 +#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 /* MFCv10 Context buffer sizes */ #define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) @@ -33,8 +35,12 @@ /* MFCv10 codec defines*/ #define S5P_FIMV_CODEC_HEVC_DEC 17 +#define S5P_FIMV_CODEC_VP9_DEC 18 #define S5P_FIMV_CODEC_HEVC_ENC 26 +/* Decoder buffer size for MFC v10 */ +#define DEC_VP9_STATIC_BUFFER_SIZE 20480 + /* Encoder buffer size for MFC v10.0 */ #define ENC_V100_BASE_SIZE(x, y) \ (((x + 3) * (y + 3) * 8) \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index 76eca67e0cd5..102b47ef4f7f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -104,6 +104,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_HEVC_DEC: codec_type = S5P_FIMV_CODEC_HEVC_DEC; break; + case S5P_MFC_CODEC_VP9_DEC: + codec_type = S5P_FIMV_CODEC_VP9_DEC; + break; case S5P_MFC_CODEC_H264_ENC: codec_type = S5P_FIMV_CODEC_H264_ENC_V6; break; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 702e136769a2..e748b99e2dec 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -73,6 +73,7 @@ #define S5P_MFC_CODEC_VC1RCV_DEC 6 #define S5P_MFC_CODEC_VP8_DEC 7 #define S5P_MFC_CODEC_HEVC_DEC 17 +#define S5P_MFC_CODEC_VP9_DEC 18 #define S5P_MFC_CODEC_H264_ENC 20 #define S5P_MFC_CODEC_H264_MVC_ENC 21 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 474935540ac8..5cf4d9921264 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -151,6 +151,13 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 1, .versions = MFC_V10_BIT, }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .codec_mode = S5P_FIMV_CODEC_VP9_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, }; #define NUM_FORMATS ARRAY_SIZE(formats) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index e7a2d463139d..57f4560d84b8 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -170,6 +170,8 @@ struct s5p_mfc_regs { void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ void __iomem *d_min_scratch_buffer_size; /* v10 */ + void __iomem *d_static_buffer_addr; /* v10 */ + void __iomem *d_static_buffer_size; /* v10 */ /* encoder registers */ void __iomem *e_frame_width; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 8c47294168b5..f47612c9e579 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -226,6 +226,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->scratch_buf_size + (ctx->mv_count * ctx->mv_size); break; + case S5P_MFC_CODEC_VP9_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + DEC_VP9_STATIC_BUFFER_SIZE; + break; case S5P_MFC_CODEC_H264_ENC: if (IS_MFCV10(dev)) { mfc_debug(2, "Use min scratch buffer size\n"); @@ -336,6 +342,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VC1_DEC: case S5P_MFC_CODEC_MPEG2_DEC: case S5P_MFC_CODEC_VP8_DEC: + case S5P_MFC_CODEC_VP9_DEC: ctx->ctx.size = buf_size->other_dec_ctx; break; case S5P_MFC_CODEC_H264_ENC: @@ -566,6 +573,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= frame_size_mv; } } + if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) { + writel(buf_addr1, mfc_regs->d_static_buffer_addr); + writel(DEC_VP9_STATIC_BUFFER_SIZE, + mfc_regs->d_static_buffer_size); + buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE; + buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE; + } mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", buf_addr1, buf_size1, ctx->total_dpb_count); @@ -2272,6 +2286,18 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); + if (!IS_MFCV10(dev)) + goto done; + + /* Initialize registers used in MFC v10 only. + * Also, over-write the registers which have + * a different offset for MFC v10. + */ + + /* decoder registers */ + R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); + R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); + done: return &mfc_regs; #undef S5P_MFC_REG_ADDR -- cgit From 3ce7f6aaf1fd2b03cd39848c5142c618b062e351 Mon Sep 17 00:00:00 2001 From: Smitha T Murthy Date: Fri, 2 Feb 2018 07:25:47 -0500 Subject: media: s5p-mfc: Add support for HEVC encoder Add HEVC encoder support and necessary registers, V4L2 CIDs, and hevc encoder parameters Signed-off-by: Smitha T Murthy Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 28 +- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 3 + drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 54 ++- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 536 ++++++++++++++++++++++++ drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | 8 + drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 182 ++++++++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 8 + 8 files changed, 818 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h index bbfa1cf89b10..fadd9139b489 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -19,13 +19,35 @@ #define S5P_FIMV_MFC_STATE_V10 0x7124 #define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 #define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 +#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30 +#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4 +#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8 +#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC +#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0 +#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4 +#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8 /* MFCv10 Context buffer sizes */ #define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) #define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) #define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) #define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) -#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) +#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) /* MFCv10 variant defines */ #define MAX_FW_SIZE_V10 (SZ_1M) @@ -57,5 +79,9 @@ #define ENC_V100_VP8_ME_SIZE(x, y) \ ENC_V100_BASE_SIZE(x, y) +#define ENC_V100_HEVC_ME_SIZE(x, y) \ + (((x + 3) * (y + 3) * 32) \ + + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4)) + #endif /*_REGS_MFC_V10_H*/ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 77dc9e527c41..a80251ed3143 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1614,6 +1614,7 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, + .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10, .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index 102b47ef4f7f..7521fceb68f1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -122,6 +122,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_ENC: codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; break; + case S5P_MFC_CODEC_HEVC_ENC: + codec_type = S5P_FIMV_CODEC_HEVC_ENC; + break; default: codec_type = S5P_FIMV_CODEC_NONE_V6; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index e748b99e2dec..20442a9b9f7a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -61,7 +61,7 @@ #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 77 +#define MFC_MAX_CTRLS 128 #define S5P_MFC_CODEC_NONE -1 #define S5P_MFC_CODEC_H264_DEC 0 @@ -80,6 +80,7 @@ #define S5P_MFC_CODEC_MPEG4_ENC 22 #define S5P_MFC_CODEC_H263_ENC 23 #define S5P_MFC_CODEC_VP8_ENC 24 +#define S5P_MFC_CODEC_HEVC_ENC 26 #define S5P_MFC_R2H_CMD_EMPTY 0 #define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 @@ -215,6 +216,7 @@ struct s5p_mfc_buf_size_v6 { unsigned int h264_dec_ctx; unsigned int other_dec_ctx; unsigned int h264_enc_ctx; + unsigned int hevc_enc_ctx; unsigned int other_enc_ctx; }; @@ -432,6 +434,55 @@ struct s5p_mfc_vp8_enc_params { u8 profile; }; +struct s5p_mfc_hevc_enc_params { + enum v4l2_mpeg_video_hevc_profile profile; + int level; + enum v4l2_mpeg_video_h264_level level_v4l2; + u8 tier; + u32 rc_framerate; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_lcu_dark; + u8 rc_lcu_smooth; + u8 rc_lcu_static; + u8 rc_lcu_activity; + u8 rc_frame_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + u8 max_partition_depth; + u8 num_refs_for_p; + u8 refreshtype; + u16 refreshperiod; + s32 lf_beta_offset_div2; + s32 lf_tc_offset_div2; + u8 loopfilter; + u8 loopfilter_disable; + u8 loopfilter_across; + u8 nal_control_length_filed; + u8 nal_control_user_ref; + u8 nal_control_store_ref; + u8 const_intra_period_enable; + u8 lossless_cu_enable; + u8 wavefront_enable; + u8 enable_ltr; + u8 hier_qp_enable; + enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type; + u8 num_hier_layer; + u8 hier_qp_layer[7]; + u32 hier_bit_layer[7]; + u8 sign_data_hiding; + u8 general_pb_enable; + u8 temporal_id_enable; + u8 strong_intra_smooth; + u8 intra_pu_split_disable; + u8 tmv_prediction_disable; + u8 max_num_merge_mv; + u8 eco_mode_enable; + u8 encoding_nostartcode_enable; + u8 size_of_length_field; + u8 prepend_sps_pps_to_idr; +}; + /** * struct s5p_mfc_enc_params - general encoding parameters */ @@ -469,6 +520,7 @@ struct s5p_mfc_enc_params { struct s5p_mfc_h264_enc_params h264; struct s5p_mfc_mpeg4_enc_params mpeg4; struct s5p_mfc_vp8_enc_params vp8; + struct s5p_mfc_hevc_enc_params hevc; } codec; }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index a846a4d1edbe..6c80ebc5dbcc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -99,6 +99,13 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 1, .versions = MFC_V7PLUS_BITS, }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, }; #define NUM_FORMATS ARRAY_SIZE(formats) @@ -692,6 +699,368 @@ static struct mfc_control controls[] = { .step = 1, .default_value = 0, }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC I Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC P Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, .type = V4L2_CTRL_TYPE_INTEGER, @@ -1359,6 +1728,26 @@ static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) return t[lvl]; } +static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl) +{ + static unsigned int t[] = { + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62, + }; + return t[lvl]; +} + static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) { static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { @@ -1635,6 +2024,153 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: p->codec.vp8.profile = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + p->codec.hevc.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p->codec.hevc.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + p->codec.hevc.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: + p->codec.hevc.rc_framerate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + p->codec.hevc.rc_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + p->codec.hevc.rc_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + p->codec.hevc.level_v4l2 = ctrl->val; + p->codec.hevc.level = hevc_level(ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + p->codec.hevc.tier = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: + p->codec.hevc.max_partition_depth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: + p->codec.hevc.num_refs_for_p = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + p->codec.hevc.refreshtype = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + p->codec.hevc.const_intra_period_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + p->codec.hevc.lossless_cu_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + p->codec.hevc.wavefront_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + p->codec.hevc.loopfilter = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: + p->codec.hevc.hier_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + p->codec.hevc.hier_qp_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: + p->codec.hevc.num_hier_layer = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: + p->codec.hevc.hier_qp_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: + p->codec.hevc.hier_qp_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: + p->codec.hevc.hier_qp_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: + p->codec.hevc.hier_qp_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: + p->codec.hevc.hier_qp_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: + p->codec.hevc.hier_qp_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: + p->codec.hevc.hier_qp_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: + p->codec.hevc.hier_bit_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: + p->codec.hevc.hier_bit_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: + p->codec.hevc.hier_bit_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: + p->codec.hevc.hier_bit_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: + p->codec.hevc.hier_bit_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: + p->codec.hevc.hier_bit_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: + p->codec.hevc.hier_bit_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: + p->codec.hevc.general_pb_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: + p->codec.hevc.temporal_id_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + p->codec.hevc.strong_intra_smooth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: + p->codec.hevc.intra_pu_split_disable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + p->codec.hevc.tmv_prediction_disable = !ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + p->codec.hevc.max_num_merge_mv = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: + p->codec.hevc.encoding_nostartcode_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + p->codec.hevc.refreshperiod = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + p->codec.hevc.lf_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + p->codec.hevc.lf_tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + p->codec.hevc.size_of_length_field = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val; + break; default: v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", ctrl->id, ctrl->val); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 57f4560d84b8..8c295f0f9740 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -272,6 +272,14 @@ struct s5p_mfc_regs { void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ void __iomem *e_min_scratch_buffer_size; /* v10 */ + void __iomem *e_num_t_layer; /* v10 */ + void __iomem *e_hier_qp_layer0; /* v10 */ + void __iomem *e_hier_bit_rate_layer0; /* v10 */ + void __iomem *e_hevc_options; /* v10 */ + void __iomem *e_hevc_refresh_period; /* v10 */ + void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */ + void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */ + void __iomem *e_hevc_nal_control; /* v10 */ }; struct s5p_mfc_hw_ops { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index f47612c9e579..7c629be43205 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -299,6 +299,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->chroma_dpb_size + ctx->me_buffer_size)); ctx->bank2.size = 0; break; + case S5P_MFC_CODEC_HEVC_ENC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; default: break; } @@ -348,6 +359,9 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_H264_ENC: ctx->ctx.size = buf_size->h264_enc_ctx; break; + case S5P_MFC_CODEC_HEVC_ENC: + ctx->ctx.size = buf_size->hevc_enc_ctx; + break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: case S5P_MFC_CODEC_VP8_ENC: @@ -1426,6 +1440,162 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) return 0; } +static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + writel(reg, mfc_regs->e_gop_config); + + /* UHD encoding case */ + if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { + p_hevc->level = 51; + p_hevc->tier = 0; + /* this tier can be changed */ + } + + /* tier & level */ + reg = 0; + /* profile */ + reg |= p_hevc->profile & 0x3; + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->level << 8); + /* tier - 0 ~ 1 */ + reg |= (p_hevc->tier << 16); + writel(reg, mfc_regs->e_picture_profile); + + switch (p_hevc->loopfilter) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + p_hevc->loopfilter_disable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 0; + break; + } + + /* max partition depth */ + reg = 0; + reg |= (p_hevc->max_partition_depth & 0x1); + reg |= (p_hevc->num_refs_for_p-1) << 2; + reg |= (p_hevc->refreshtype & 0x3) << 3; + reg |= (p_hevc->const_intra_period_enable & 0x1) << 5; + reg |= (p_hevc->lossless_cu_enable & 0x1) << 6; + reg |= (p_hevc->wavefront_enable & 0x1) << 7; + reg |= (p_hevc->loopfilter_disable & 0x1) << 8; + reg |= (p_hevc->loopfilter_across & 0x1) << 9; + reg |= (p_hevc->enable_ltr & 0x1) << 10; + reg |= (p_hevc->hier_qp_enable & 0x1) << 11; + reg |= (p_hevc->general_pb_enable & 0x1) << 13; + reg |= (p_hevc->temporal_id_enable & 0x1) << 14; + reg |= (p_hevc->strong_intra_smooth & 0x1) << 15; + reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16; + reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17; + reg |= (p_hevc->max_num_merge_mv & 0x7) << 18; + reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23; + reg |= (p_hevc->prepend_sps_pps_to_idr << 26); + + writel(reg, mfc_regs->e_hevc_options); + /* refresh period */ + if (p_hevc->refreshtype) { + reg = 0; + reg |= (p_hevc->refreshperiod & 0xFFFF); + writel(reg, mfc_regs->e_hevc_refresh_period); + } + /* loop filter setting */ + if (!(p_hevc->loopfilter_disable & 0x1)) { + reg = 0; + reg |= (p_hevc->lf_beta_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2); + reg = 0; + reg |= (p_hevc->lf_tc_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2); + } + /* hier qp enable */ + if (p_hevc->num_hier_layer) { + reg = 0; + reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; + reg |= p_hevc->num_hier_layer & 0x7; + writel(reg, mfc_regs->e_num_t_layer); + /* QP value for each layer */ + if (p_hevc->hier_qp_enable) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_qp_layer[i], + mfc_regs->e_hier_qp_layer0 + i * 4); + } + if (p->rc_frame) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_bit_layer[i], + mfc_regs->e_hier_bit_rate_layer0 + + i * 4); + } + } + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + writel(reg, mfc_regs->e_rc_config); + /* frame QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_rc_config); + + /* frame rate */ + if (p->rc_frame) { + reg = 0; + reg &= ~(0xFFFF << 16); + reg |= ((p_hevc->rc_framerate) << 16); + reg &= ~(0xFFFF); + reg |= FRAME_DELTA_DEFAULT; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* max & min value of QP */ + reg = 0; + /* max QP */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_max_qp << 8); + /* min QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_min_qp; + writel(reg, mfc_regs->e_rc_qp_bound); + + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg &= ~(0xFF << 16); + reg |= (p_hevc->rc_b_frame_qp << 16); + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_p_frame_qp << 8); + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + mfc_debug_leave(); + + return 0; +} + /* Initialize decoding */ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) { @@ -1545,6 +1715,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params_h263(ctx); else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC) s5p_mfc_set_enc_params_vp8(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC) + s5p_mfc_set_enc_params_hevc(ctx); else { mfc_err("Unknown codec for encoding (%x).\n", ctx->codec_mode); @@ -2298,6 +2470,16 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); + /* encoder registers */ + R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10); + R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10); + R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10); + R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10); + R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10); + R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10); + R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10); + R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10); + done: return &mfc_regs; #undef S5P_MFC_REG_ADDR diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index f6cb703e586f..f013b291ae5b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -46,6 +46,14 @@ #define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) #define FRAME_DELTA_H264_H263 1 #define TIGHT_CBR_MAX 10 +#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_HEVC_QP_INDEX_MIN -12 +#define ENC_HEVC_QP_INDEX_MAX 12 +#define ENC_HEVC_LOOP_FILTER_MIN -12 +#define ENC_HEVC_LOOP_FILTER_MAX 12 +#define ENC_HEVC_LEVEL_MAX 62 + +#define FRAME_DELTA_DEFAULT 1 struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); -- cgit From c8e6f90d825166c7b41a1da081358bba658c4fad Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 13 Mar 2018 06:27:10 -0400 Subject: media: s5p-mfc: Use real device for request_firmware() call Provide proper (real) struct device to request_firmware() call. This fixes following error messages: (NULL device *): Direct firmware load for s5p-mfc-v6-v2.fw failed with error -2 (NULL device *): Direct firmware load for s5p-mfc-v6.fw failed with error -2 into a bit more meaningful ones: s5p-mfc 11000000.codec: Direct firmware load for s5p-mfc-v6-v2.fw failed with error -2 s5p-mfc 11000000.codec: Direct firmware load for s5p-mfc-v6.fw failed with error -2 Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 76405f5b4f7e..ee7b15b335e0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -62,7 +62,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) if (!dev->variant->fw_name[i]) continue; err = request_firmware((const struct firmware **)&fw_blob, - dev->variant->fw_name[i], dev->v4l2_dev.dev); + dev->variant->fw_name[i], &dev->plat_dev->dev); if (!err) { dev->fw_ver = (enum s5p_mfc_fw_ver) i; break; -- cgit From 11b7090d8088e0ecaec4a48d5477f91b840d585b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 19 Mar 2018 10:29:16 -0400 Subject: media: s5p-mfc: Ensure HEVC QP controls range is properly updated When value of V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP or V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls is changed we should update range of a set of HEVC quantization parameter v4l2 controls as specified in the HEVC controls documentation. Signed-off-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 6c80ebc5dbcc..810dabe2f1b9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1773,6 +1773,42 @@ static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) return t[sar]; } +/* + * Update range of all HEVC quantization parameter controls that depend on the + * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls. + */ +static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx, + int min, int max) +{ + static const int __hevc_qp_ctrls[] = { + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + }; + struct v4l2_ctrl *ctrl = NULL; + int i, j; + + for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) { + for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) { + if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) { + ctrl = ctx->ctrls[j]; + break; + } + } + if (WARN_ON(!ctrl)) + break; + + __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min); + } +} + static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) { struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); @@ -2038,9 +2074,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: p->codec.hevc.rc_min_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val, + p->codec.hevc.rc_max_qp); break; case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: p->codec.hevc.rc_max_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp, + ctrl->val); break; case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: p->codec.hevc.level_v4l2 = ctrl->val; -- cgit From 740ba614c9727660f99d7d924987dfef8a437698 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 19 Mar 2018 10:29:58 -0400 Subject: media: s5p-mfc: Amend initial min, max values of HEVC hierarchical coding QP controls Valid range for those controls is specified in documentation as [0, 51], so initialize the controls to such range rather than [INT_MIN, INT_MAX]. Signed-off-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 810dabe2f1b9..7382b41f4f6d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -856,56 +856,56 @@ static struct mfc_control controls[] = { { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, { .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, + .minimum = 0, + .maximum = 51, .step = 1, .default_value = 0, }, -- cgit From 93eaf301a7d2c992595baf54c1ae8b835c7bf4df Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 07:23:48 -0400 Subject: media: s5p_mfc_enc: get rid of new warnings The values of enc_y_addr and enc_c_addr are initialized by s5p_mfc_hw_call(), but, in thesis, this macro might be doing nothing, if the get_enc_frame_buffer() is not declared. That causes those GCC warnings: drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1242 enc_post_frame_start() error: uninitialized symbol 'enc_y_addr'. drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1243 enc_post_frame_start() error: uninitialized symbol 'enc_c_addr'. drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1256 enc_post_frame_start() error: uninitialized symbol 'enc_y_addr'. drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1257 enc_post_frame_start() error: uninitialized symbol 'enc_c_addr'. Change the logic by initializing those constants to zero, with should hopefully do the right thing. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 7382b41f4f6d..5c0462ca9993 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1220,7 +1220,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *mb_entry; - unsigned long enc_y_addr, enc_c_addr; + unsigned long enc_y_addr = 0, enc_c_addr = 0; unsigned long mb_y_addr, mb_c_addr; int slice_type; unsigned int strm_size; -- cgit From 9ca400c18ff1100a52411952d24bc4c4a15facc3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 31 Oct 2017 09:55:09 -0400 Subject: media: cec: add core error injection support Add two new ops (error_inj_show and error_inj_parse_line) to support error injection functionality for CEC adapters. If both are present, then the core will add a new error-inj debugfs file that can be used to see the current error injection commands and to set error injection commands. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-core.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index e47ea22b3c23..ea3eccfdba15 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -195,6 +195,55 @@ void cec_register_cec_notifier(struct cec_adapter *adap, EXPORT_SYMBOL_GPL(cec_register_cec_notifier); #endif +#ifdef CONFIG_DEBUG_FS +static ssize_t cec_error_inj_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *sf = file->private_data; + struct cec_adapter *adap = sf->private; + char *buf; + char *line; + char *p; + + buf = memdup_user_nul(ubuf, min_t(size_t, PAGE_SIZE, count)); + if (IS_ERR(buf)) + return PTR_ERR(buf); + p = buf; + while (p && *p && count >= 0) { + p = skip_spaces(p); + line = strsep(&p, "\n"); + if (!*line || *line == '#') + continue; + if (!adap->ops->error_inj_parse_line(adap, line)) { + count = -EINVAL; + break; + } + } + kfree(buf); + return count; +} + +static int cec_error_inj_show(struct seq_file *sf, void *unused) +{ + struct cec_adapter *adap = sf->private; + + return adap->ops->error_inj_show(adap, sf); +} + +static int cec_error_inj_open(struct inode *inode, struct file *file) +{ + return single_open(file, cec_error_inj_show, inode->i_private); +} + +static const struct file_operations cec_error_inj_fops = { + .open = cec_error_inj_open, + .write = cec_error_inj_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, void *priv, const char *name, u32 caps, u8 available_las) @@ -334,7 +383,16 @@ int cec_register_adapter(struct cec_adapter *adap, pr_warn("cec-%s: Failed to create status file\n", adap->name); debugfs_remove_recursive(adap->cec_dir); adap->cec_dir = NULL; + return 0; } + if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line) + return 0; + adap->error_inj_file = debugfs_create_file("error-inj", 0644, + adap->cec_dir, adap, + &cec_error_inj_fops); + if (IS_ERR_OR_NULL(adap->error_inj_file)) + pr_warn("cec-%s: Failed to create error-inj file\n", + adap->name); #endif return 0; } -- cgit From 0ee492ad54d779e901133fcf381389e6d1067db6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 31 Oct 2017 09:55:09 -0400 Subject: media: cec-pin: create cec_pin_start_timer() function This function will be needed for injecting a custom pulse. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-pin-priv.h | 2 ++ drivers/media/cec/cec-pin.c | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index cf41c4236efd..4571a0001a9d 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -118,4 +118,6 @@ struct cec_pin { u32 timer_sum_overrun; }; +void cec_pin_start_timer(struct cec_pin *pin); + #endif diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index 8e834b9f72c6..67d6ea9f56b6 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -680,6 +680,18 @@ static int cec_pin_adap_log_addr(struct cec_adapter *adap, u8 log_addr) return 0; } +void cec_pin_start_timer(struct cec_pin *pin) +{ + if (pin->state != CEC_ST_RX_IRQ) + return; + + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); + pin->ops->disable_irq(pin->adap); + cec_pin_high(pin); + cec_pin_to_idle(pin); + hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); +} + static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg) { @@ -689,14 +701,7 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, pin->tx_msg = *msg; pin->work_tx_status = 0; pin->tx_bit = 0; - if (pin->state == CEC_ST_RX_IRQ) { - atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); - pin->ops->disable_irq(adap); - cec_pin_high(pin); - cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, ns_to_ktime(0), - HRTIMER_MODE_REL); - } + cec_pin_start_timer(pin); return 0; } -- cgit From 22712b389e40ae0fa0526db8ca8b34bf8f787abf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 31 Oct 2017 09:55:09 -0400 Subject: media: cec-pin-error-inj: parse/show error injection Add support to the CEC Pin framework to parse error injection commands and to show them. The next patch will do the actual implementation of this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/Kconfig | 6 + drivers/media/cec/Makefile | 4 + drivers/media/cec/cec-pin-error-inj.c | 342 ++++++++++++++++++++++++++++++++++ drivers/media/cec/cec-pin-priv.h | 71 +++++++ drivers/media/cec/cec-pin.c | 6 + 5 files changed, 429 insertions(+) create mode 100644 drivers/media/cec/cec-pin-error-inj.c (limited to 'drivers/media') diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index 43428cec3a01..9c2b108c613a 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -4,3 +4,9 @@ config MEDIA_CEC_RC depends on CEC_CORE=m || RC_CORE=y ---help--- Pass on CEC remote control messages to the RC framework. + +config CEC_PIN_ERROR_INJ + bool "Enable CEC error injection support" + depends on CEC_PIN && DEBUG_FS + ---help--- + This option enables CEC error injection using debugfs. diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile index 41ee3325e1ea..29a2ab9e77c5 100644 --- a/drivers/media/cec/Makefile +++ b/drivers/media/cec/Makefile @@ -9,4 +9,8 @@ ifeq ($(CONFIG_CEC_PIN),y) cec-objs += cec-pin.o endif +ifeq ($(CONFIG_CEC_PIN_ERROR_INJ),y) + cec-objs += cec-pin-error-inj.o +endif + obj-$(CONFIG_CEC_CORE) += cec.o diff --git a/drivers/media/cec/cec-pin-error-inj.c b/drivers/media/cec/cec-pin-error-inj.c new file mode 100644 index 000000000000..aaa899a175ce --- /dev/null +++ b/drivers/media/cec/cec-pin-error-inj.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include + +#include +#include "cec-pin-priv.h" + +struct cec_error_inj_cmd { + unsigned int mode_offset; + int arg_idx; + const char *cmd; +}; + +static const struct cec_error_inj_cmd cec_error_inj_cmds[] = { + { CEC_ERROR_INJ_RX_NACK_OFFSET, -1, "rx-nack" }, + { CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, "rx-low-drive" }, + { CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, "rx-add-byte" }, + { CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, "rx-remove-byte" }, + { CEC_ERROR_INJ_RX_ARB_LOST_OFFSET, + CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, "rx-arb-lost" }, + + { CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, "tx-no-eom" }, + { CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, "tx-early-eom" }, + { CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET, + CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, "tx-add-bytes" }, + { CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, "tx-remove-byte" }, + { CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET, + CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, "tx-short-bit" }, + { CEC_ERROR_INJ_TX_LONG_BIT_OFFSET, + CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, "tx-long-bit" }, + { CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET, + CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, "tx-custom-bit" }, + { CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, "tx-short-start" }, + { CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, "tx-long-start" }, + { CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, -1, "tx-custom-start" }, + { CEC_ERROR_INJ_TX_LAST_BIT_OFFSET, + CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, "tx-last-bit" }, + { CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, "tx-low-drive" }, + { 0, -1, NULL } +}; + +u16 cec_pin_rx_error_inj(struct cec_pin *pin) +{ + u16 cmd = CEC_ERROR_INJ_OP_ANY; + + /* Only when 18 bits have been received do we have a valid cmd */ + if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) && + pin->rx_bit >= 18) + cmd = pin->rx_msg.msg[1]; + return (pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) ? cmd : + CEC_ERROR_INJ_OP_ANY; +} + +u16 cec_pin_tx_error_inj(struct cec_pin *pin) +{ + u16 cmd = CEC_ERROR_INJ_OP_ANY; + + if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) && + pin->tx_msg.len > 1) + cmd = pin->tx_msg.msg[1]; + return (pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) ? cmd : + CEC_ERROR_INJ_OP_ANY; +} + +bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) +{ + static const char *delims = " \t\r"; + struct cec_pin *pin = adap->pin; + unsigned int i; + bool has_pos = false; + char *p = line; + char *token; + char *comma; + u64 *error; + u8 *args; + bool has_op; + u32 op; + u8 mode; + u8 pos; + u8 v; + + p = skip_spaces(p); + token = strsep(&p, delims); + if (!strcmp(token, "clear")) { + memset(pin->error_inj, 0, sizeof(pin->error_inj)); + pin->rx_toggle = pin->tx_toggle = false; + pin->tx_ignore_nack_until_eom = false; + pin->tx_custom_pulse = false; + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + return true; + } + if (!strcmp(token, "rx-clear")) { + for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) + pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; + pin->rx_toggle = false; + return true; + } + if (!strcmp(token, "tx-clear")) { + for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) + pin->error_inj[i] &= ~CEC_ERROR_INJ_TX_MASK; + pin->tx_toggle = false; + pin->tx_ignore_nack_until_eom = false; + pin->tx_custom_pulse = false; + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + return true; + } + if (!strcmp(token, "tx-ignore-nack-until-eom")) { + pin->tx_ignore_nack_until_eom = true; + return true; + } + if (!strcmp(token, "tx-custom-pulse")) { + pin->tx_custom_pulse = true; + cec_pin_start_timer(pin); + return true; + } + if (!p) + return false; + + p = skip_spaces(p); + if (!strcmp(token, "tx-custom-low-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 10000000) + return false; + pin->tx_custom_low_usecs = usecs; + return true; + } + if (!strcmp(token, "tx-custom-high-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 10000000) + return false; + pin->tx_custom_high_usecs = usecs; + return true; + } + + comma = strchr(token, ','); + if (comma) + *comma++ = '\0'; + if (!strcmp(token, "any")) + op = CEC_ERROR_INJ_OP_ANY; + else if (!kstrtou8(token, 0, &v)) + op = v; + else + return false; + mode = CEC_ERROR_INJ_MODE_ONCE; + if (comma) { + if (!strcmp(comma, "off")) + mode = CEC_ERROR_INJ_MODE_OFF; + else if (!strcmp(comma, "once")) + mode = CEC_ERROR_INJ_MODE_ONCE; + else if (!strcmp(comma, "always")) + mode = CEC_ERROR_INJ_MODE_ALWAYS; + else if (!strcmp(comma, "toggle")) + mode = CEC_ERROR_INJ_MODE_TOGGLE; + else + return false; + } + + error = pin->error_inj + op; + args = pin->error_inj_args[op]; + has_op = op <= 0xff; + + token = strsep(&p, delims); + if (p) { + p = skip_spaces(p); + has_pos = !kstrtou8(p, 0, &pos); + } + + if (!strcmp(token, "clear")) { + *error = 0; + return true; + } + if (!strcmp(token, "rx-clear")) { + *error &= ~CEC_ERROR_INJ_RX_MASK; + return true; + } + if (!strcmp(token, "tx-clear")) { + *error &= ~CEC_ERROR_INJ_TX_MASK; + return true; + } + + for (i = 0; cec_error_inj_cmds[i].cmd; i++) { + const char *cmd = cec_error_inj_cmds[i].cmd; + unsigned int mode_offset; + u64 mode_mask; + int arg_idx; + bool is_bit_pos = true; + + if (strcmp(token, cmd)) + continue; + + mode_offset = cec_error_inj_cmds[i].mode_offset; + mode_mask = CEC_ERROR_INJ_MODE_MASK << mode_offset; + arg_idx = cec_error_inj_cmds[i].arg_idx; + + if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET) + is_bit_pos = false; + + if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET) { + if (has_op) + return false; + if (!has_pos) + pos = 0x0f; + } + if (arg_idx >= 0 && is_bit_pos) { + if (!has_pos || pos >= 160) + return false; + if (has_op && pos < 10 + 8) + return false; + /* Invalid bit position may not be the Ack bit */ + if ((mode_offset == CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_LONG_BIT_OFFSET || + mode_offset == CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET) && + (pos % 10) == 9) + return false; + } + *error &= ~mode_mask; + *error |= (u64)mode << mode_offset; + if (arg_idx >= 0) + args[arg_idx] = pos; + return true; + } + return false; +} + +static void cec_pin_show_cmd(struct seq_file *sf, u32 cmd, u8 mode) +{ + if (cmd == CEC_ERROR_INJ_OP_ANY) + seq_puts(sf, "any,"); + else + seq_printf(sf, "0x%02x,", cmd); + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + seq_puts(sf, "once "); + break; + case CEC_ERROR_INJ_MODE_ALWAYS: + seq_puts(sf, "always "); + break; + case CEC_ERROR_INJ_MODE_TOGGLE: + seq_puts(sf, "toggle "); + break; + default: + seq_puts(sf, "off "); + break; + } +} + +int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) +{ + struct cec_pin *pin = adap->pin; + unsigned int i, j; + + seq_puts(sf, "# Clear error injections:\n"); + seq_puts(sf, "# clear clear all rx and tx error injections\n"); + seq_puts(sf, "# rx-clear clear all rx error injections\n"); + seq_puts(sf, "# tx-clear clear all tx error injections\n"); + seq_puts(sf, "# clear clear all rx and tx error injections for \n"); + seq_puts(sf, "# rx-clear clear all rx error injections for \n"); + seq_puts(sf, "# tx-clear clear all tx error injections for \n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# RX error injection:\n"); + seq_puts(sf, "# [,] rx-nack NACK the message instead of sending an ACK\n"); + seq_puts(sf, "# [,] rx-low-drive force a low-drive condition at this bit position\n"); + seq_puts(sf, "# [,] rx-add-byte add a spurious byte to the received CEC message\n"); + seq_puts(sf, "# [,] rx-remove-byte remove the last byte from the received CEC message\n"); + seq_puts(sf, "# [,] rx-arb-lost generate a POLL message to trigger an arbitration lost\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# TX error injection settings:\n"); + seq_puts(sf, "# tx-ignore-nack-until-eom ignore early NACKs until EOM\n"); + seq_puts(sf, "# tx-custom-low-usecs define the 'low' time for the custom pulse\n"); + seq_puts(sf, "# tx-custom-high-usecs define the 'high' time for the custom pulse\n"); + seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# TX error injection:\n"); + seq_puts(sf, "# [,] tx-no-eom don't set the EOM bit\n"); + seq_puts(sf, "# [,] tx-early-eom set the EOM bit one byte too soon\n"); + seq_puts(sf, "# [,] tx-add-bytes append (1-255) spurious bytes to the message\n"); + seq_puts(sf, "# [,] tx-remove-byte drop the last byte from the message\n"); + seq_puts(sf, "# [,] tx-short-bit make this bit shorter than allowed\n"); + seq_puts(sf, "# [,] tx-long-bit make this bit longer than allowed\n"); + seq_puts(sf, "# [,] tx-custom-bit send the custom pulse instead of this bit\n"); + seq_puts(sf, "# [,] tx-short-start send a start pulse that's too short\n"); + seq_puts(sf, "# [,] tx-long-start send a start pulse that's too long\n"); + seq_puts(sf, "# [,] tx-custom-start send the custom pulse instead of the start pulse\n"); + seq_puts(sf, "# [,] tx-last-bit stop sending after this bit\n"); + seq_puts(sf, "# [,] tx-low-drive force a low-drive condition at this bit position\n"); + seq_puts(sf, "#\n"); + seq_puts(sf, "# CEC message opcode (0-255) or 'any'\n"); + seq_puts(sf, "# 'once' (default), 'always', 'toggle' or 'off'\n"); + seq_puts(sf, "# CEC message bit (0-159)\n"); + seq_puts(sf, "# 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK\n"); + seq_puts(sf, "# CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f)\n"); + seq_puts(sf, "# microseconds (0-10000000, default 1000)\n"); + + seq_puts(sf, "\nclear\n"); + + for (i = 0; i < ARRAY_SIZE(pin->error_inj); i++) { + u64 e = pin->error_inj[i]; + + for (j = 0; cec_error_inj_cmds[j].cmd; j++) { + const char *cmd = cec_error_inj_cmds[j].cmd; + unsigned int mode; + unsigned int mode_offset; + int arg_idx; + + mode_offset = cec_error_inj_cmds[j].mode_offset; + arg_idx = cec_error_inj_cmds[j].arg_idx; + mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + if (!mode) + continue; + cec_pin_show_cmd(sf, i, mode); + seq_puts(sf, cmd); + if (arg_idx >= 0) + seq_printf(sf, " %u", + pin->error_inj_args[i][arg_idx]); + seq_puts(sf, "\n"); + } + } + + if (pin->tx_ignore_nack_until_eom) + seq_puts(sf, "tx-ignore-nack-until-eom\n"); + if (pin->tx_custom_pulse) + seq_puts(sf, "tx-custom-pulse\n"); + if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT) + seq_printf(sf, "tx-custom-low-usecs %u\n", + pin->tx_custom_low_usecs); + if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) + seq_printf(sf, "tx-custom-high-usecs %u\n", + pin->tx_custom_high_usecs); + return 0; +} diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index 4571a0001a9d..779384f18689 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -74,6 +74,55 @@ enum cec_pin_state { CEC_PIN_STATES }; +/* Error Injection */ + +/* Error injection modes */ +#define CEC_ERROR_INJ_MODE_OFF 0 +#define CEC_ERROR_INJ_MODE_ONCE 1 +#define CEC_ERROR_INJ_MODE_ALWAYS 2 +#define CEC_ERROR_INJ_MODE_TOGGLE 3 +#define CEC_ERROR_INJ_MODE_MASK 3ULL + +/* Receive error injection options */ +#define CEC_ERROR_INJ_RX_NACK_OFFSET 0 +#define CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET 2 +#define CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET 4 +#define CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET 6 +#define CEC_ERROR_INJ_RX_ARB_LOST_OFFSET 8 +#define CEC_ERROR_INJ_RX_MASK 0xffffULL + +/* Transmit error injection options */ +#define CEC_ERROR_INJ_TX_NO_EOM_OFFSET 16 +#define CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET 18 +#define CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET 20 +#define CEC_ERROR_INJ_TX_LONG_BIT_OFFSET 22 +#define CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET 24 +#define CEC_ERROR_INJ_TX_SHORT_START_OFFSET 26 +#define CEC_ERROR_INJ_TX_LONG_START_OFFSET 28 +#define CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET 30 +#define CEC_ERROR_INJ_TX_LAST_BIT_OFFSET 32 +#define CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET 34 +#define CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET 36 +#define CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET 38 +#define CEC_ERROR_INJ_TX_MASK 0xffffffffffff0000ULL + +#define CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX 0 +#define CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX 1 + +#define CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX 2 +#define CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX 3 +#define CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX 4 +#define CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX 5 +#define CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX 6 +#define CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX 7 +#define CEC_ERROR_INJ_NUM_ARGS 8 + +/* Special CEC op values */ +#define CEC_ERROR_INJ_OP_ANY 0x00000100 + +/* The default for the low/high time of the custom pulse */ +#define CEC_TIM_CUSTOM_DEFAULT 1000 + #define CEC_NUM_PIN_EVENTS 128 #define CEC_PIN_IRQ_UNCHANGED 0 @@ -98,8 +147,10 @@ struct cec_pin { u32 tx_bit; bool tx_nacked; u32 tx_signal_free_time; + bool tx_toggle; struct cec_msg rx_msg; u32 rx_bit; + bool rx_toggle; struct cec_msg work_rx_msg; u8 work_tx_status; @@ -116,8 +167,28 @@ struct cec_pin { u32 timer_300ms_overruns; u32 timer_max_overrun; u32 timer_sum_overrun; + + u32 tx_custom_low_usecs; + u32 tx_custom_high_usecs; + bool tx_ignore_nack_until_eom; + bool tx_custom_pulse; + bool tx_generated_poll; + bool tx_post_eom; + u8 tx_extra_bytes; +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u64 error_inj[CEC_ERROR_INJ_OP_ANY + 1]; + u8 error_inj_args[CEC_ERROR_INJ_OP_ANY + 1][CEC_ERROR_INJ_NUM_ARGS]; +#endif }; void cec_pin_start_timer(struct cec_pin *pin); +#ifdef CONFIG_CEC_PIN_ERROR_INJ +bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line); +int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf); + +u16 cec_pin_rx_error_inj(struct cec_pin *pin); +u16 cec_pin_tx_error_inj(struct cec_pin *pin); +#endif + #endif diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index 67d6ea9f56b6..7920ea1c940b 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -771,6 +771,10 @@ static const struct cec_adap_ops cec_pin_adap_ops = { .adap_transmit = cec_pin_adap_transmit, .adap_status = cec_pin_adap_status, .adap_free = cec_pin_adap_free, +#ifdef CONFIG_CEC_PIN_ERROR_INJ + .error_inj_parse_line = cec_pin_error_inj_parse_line, + .error_inj_show = cec_pin_error_inj_show, +#endif }; struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, @@ -785,6 +789,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pin->timer.function = cec_pin_timer; init_waitqueue_head(&pin->kthread_waitq); + pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, -- cgit From 865463fc03ed6d1685d19dbef847b0e7abcc7fbf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 31 Oct 2017 09:55:09 -0400 Subject: media: cec-pin: add error injection support Implement all the error injection commands. The state machine gets new states for the various error situations, helper functions are added to detect whether an error injection is active and the actual error injections are implemented. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-pin-priv.h | 38 ++- drivers/media/cec/cec-pin.c | 548 +++++++++++++++++++++++++++++++++++---- 2 files changed, 527 insertions(+), 59 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index 779384f18689..c9349f68e554 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -28,14 +28,30 @@ enum cec_pin_state { CEC_ST_TX_START_BIT_LOW, /* Drive CEC high for the start bit */ CEC_ST_TX_START_BIT_HIGH, + /* Generate a start bit period that is too short */ + CEC_ST_TX_START_BIT_HIGH_SHORT, + /* Generate a start bit period that is too long */ + CEC_ST_TX_START_BIT_HIGH_LONG, + /* Drive CEC low for the start bit using the custom timing */ + CEC_ST_TX_START_BIT_LOW_CUSTOM, + /* Drive CEC high for the start bit using the custom timing */ + CEC_ST_TX_START_BIT_HIGH_CUSTOM, /* Drive CEC low for the 0 bit */ CEC_ST_TX_DATA_BIT_0_LOW, /* Drive CEC high for the 0 bit */ CEC_ST_TX_DATA_BIT_0_HIGH, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_0_HIGH_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_0_HIGH_LONG, /* Drive CEC low for the 1 bit */ CEC_ST_TX_DATA_BIT_1_LOW, /* Drive CEC high for the 1 bit */ CEC_ST_TX_DATA_BIT_1_HIGH, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_1_HIGH_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_1_HIGH_LONG, /* * Wait for start of sample time to check for Ack bit or first * four initiator bits to check for Arbitration Lost. @@ -43,6 +59,20 @@ enum cec_pin_state { CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE, /* Wait for end of bit period after sampling */ CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE, + /* Generate a bit period that is too short */ + CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT, + /* Generate a bit period that is too long */ + CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG, + /* Drive CEC low for a data bit using the custom timing */ + CEC_ST_TX_DATA_BIT_LOW_CUSTOM, + /* Drive CEC high for a data bit using the custom timing */ + CEC_ST_TX_DATA_BIT_HIGH_CUSTOM, + /* Drive CEC low for a standalone pulse using the custom timing */ + CEC_ST_TX_PULSE_LOW_CUSTOM, + /* Drive CEC high for a standalone pulse using the custom timing */ + CEC_ST_TX_PULSE_HIGH_CUSTOM, + /* Start low drive */ + CEC_ST_TX_LOW_DRIVE, /* Rx states */ @@ -54,8 +84,8 @@ enum cec_pin_state { CEC_ST_RX_DATA_SAMPLE, /* Wait for earliest end of bit period after sampling */ CEC_ST_RX_DATA_POST_SAMPLE, - /* Wait for CEC to go high (i.e. end of bit period */ - CEC_ST_RX_DATA_HIGH, + /* Wait for CEC to go low (i.e. end of bit period) */ + CEC_ST_RX_DATA_WAIT_FOR_LOW, /* Drive CEC low to send 0 Ack bit */ CEC_ST_RX_ACK_LOW, /* End of 0 Ack time, wait for earliest end of bit period */ @@ -64,9 +94,9 @@ enum cec_pin_state { CEC_ST_RX_ACK_HIGH_POST, /* Wait for earliest end of bit period and end of message */ CEC_ST_RX_ACK_FINISH, - /* Start low drive */ - CEC_ST_LOW_DRIVE, + CEC_ST_RX_LOW_DRIVE, + /* Monitor pin using interrupts */ CEC_ST_RX_IRQ, diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index 7920ea1c940b..d03ed4eefdd6 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -39,11 +39,29 @@ #define CEC_TIM_IDLE_SAMPLE 1000 /* when processing the start bit, sample twice per millisecond */ #define CEC_TIM_START_BIT_SAMPLE 500 -/* when polling for a state change, sample once every 50 micoseconds */ +/* when polling for a state change, sample once every 50 microseconds */ #define CEC_TIM_SAMPLE 50 #define CEC_TIM_LOW_DRIVE_ERROR (1.5 * CEC_TIM_DATA_BIT_TOTAL) +/* + * Total data bit time that is too short/long for a valid bit, + * used for error injection. + */ +#define CEC_TIM_DATA_BIT_TOTAL_SHORT 1800 +#define CEC_TIM_DATA_BIT_TOTAL_LONG 2900 + +/* + * Total start bit time that is too short/long for a valid bit, + * used for error injection. + */ +#define CEC_TIM_START_BIT_TOTAL_SHORT 4100 +#define CEC_TIM_START_BIT_TOTAL_LONG 5000 + +/* Data bits are 0-7, EOM is bit 8 and ACK is bit 9 */ +#define EOM_BIT 8 +#define ACK_BIT 9 + struct cec_state { const char * const name; unsigned int usecs; @@ -56,17 +74,32 @@ static const struct cec_state states[CEC_PIN_STATES] = { { "Tx Wait for High", CEC_TIM_IDLE_SAMPLE }, { "Tx Start Bit Low", CEC_TIM_START_BIT_LOW }, { "Tx Start Bit High", CEC_TIM_START_BIT_TOTAL - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit High Short", CEC_TIM_START_BIT_TOTAL_SHORT - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit High Long", CEC_TIM_START_BIT_TOTAL_LONG - CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit Low Custom", 0 }, + { "Tx Start Bit High Custom", 0 }, { "Tx Data 0 Low", CEC_TIM_DATA_BIT_0_LOW }, { "Tx Data 0 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 0 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 0 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_0_LOW }, { "Tx Data 1 Low", CEC_TIM_DATA_BIT_1_LOW }, { "Tx Data 1 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_1_LOW }, - { "Tx Data 1 Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW }, - { "Tx Data 1 Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Post Sample Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data 1 High Post Sample Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_SAMPLE }, + { "Tx Data Bit Low Custom", 0 }, + { "Tx Data Bit High Custom", 0 }, + { "Tx Pulse Low Custom", 0 }, + { "Tx Pulse High Custom", 0 }, + { "Tx Low Drive", CEC_TIM_LOW_DRIVE_ERROR }, { "Rx Start Bit Low", CEC_TIM_SAMPLE }, { "Rx Start Bit High", CEC_TIM_SAMPLE }, { "Rx Data Sample", CEC_TIM_DATA_BIT_SAMPLE }, { "Rx Data Post Sample", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_SAMPLE }, - { "Rx Data High", CEC_TIM_SAMPLE }, + { "Rx Data Wait for Low", CEC_TIM_SAMPLE }, { "Rx Ack Low", CEC_TIM_DATA_BIT_0_LOW }, { "Rx Ack Low Post", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_0_LOW }, { "Rx Ack High Post", CEC_TIM_DATA_BIT_HIGH }, @@ -111,6 +144,173 @@ static bool cec_pin_high(struct cec_pin *pin) return cec_pin_read(pin); } +static bool rx_error_inj(struct cec_pin *pin, unsigned int mode_offset, + int arg_idx, u8 *arg) +{ +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u16 cmd = cec_pin_rx_error_inj(pin); + u64 e = pin->error_inj[cmd]; + unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + + if (arg_idx >= 0) { + u8 pos = pin->error_inj_args[cmd][arg_idx]; + + if (arg) + *arg = pos; + else if (pos != pin->rx_bit) + return false; + } + + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + pin->error_inj[cmd] &= + ~(CEC_ERROR_INJ_MODE_MASK << mode_offset); + return true; + case CEC_ERROR_INJ_MODE_ALWAYS: + return true; + case CEC_ERROR_INJ_MODE_TOGGLE: + return pin->rx_toggle; + default: + return false; + } +#else + return false; +#endif +} + +static bool rx_nack(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_NACK_OFFSET, -1, NULL); +} + +static bool rx_low_drive(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, NULL); +} + +static bool rx_add_byte(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, NULL); +} + +static bool rx_remove_byte(struct cec_pin *pin) +{ + return rx_error_inj(pin, CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, NULL); +} + +static bool rx_arb_lost(struct cec_pin *pin, u8 *poll) +{ + return pin->tx_msg.len == 0 && + rx_error_inj(pin, CEC_ERROR_INJ_RX_ARB_LOST_OFFSET, + CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, poll); +} + +static bool tx_error_inj(struct cec_pin *pin, unsigned int mode_offset, + int arg_idx, u8 *arg) +{ +#ifdef CONFIG_CEC_PIN_ERROR_INJ + u16 cmd = cec_pin_tx_error_inj(pin); + u64 e = pin->error_inj[cmd]; + unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK; + + if (arg_idx >= 0) { + u8 pos = pin->error_inj_args[cmd][arg_idx]; + + if (arg) + *arg = pos; + else if (pos != pin->tx_bit) + return false; + } + + switch (mode) { + case CEC_ERROR_INJ_MODE_ONCE: + pin->error_inj[cmd] &= + ~(CEC_ERROR_INJ_MODE_MASK << mode_offset); + return true; + case CEC_ERROR_INJ_MODE_ALWAYS: + return true; + case CEC_ERROR_INJ_MODE_TOGGLE: + return pin->tx_toggle; + default: + return false; + } +#else + return false; +#endif +} + +static bool tx_no_eom(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, NULL); +} + +static bool tx_early_eom(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, NULL); +} + +static bool tx_short_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET, + CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, NULL); +} + +static bool tx_long_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_BIT_OFFSET, + CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, NULL); +} + +static bool tx_custom_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET, + CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, NULL); +} + +static bool tx_short_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, NULL); +} + +static bool tx_long_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, NULL); +} + +static bool tx_custom_start(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, + -1, NULL); +} + +static bool tx_last_bit(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LAST_BIT_OFFSET, + CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, NULL); +} + +static u8 tx_add_bytes(struct cec_pin *pin) +{ + u8 bytes; + + if (tx_error_inj(pin, CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET, + CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, &bytes)) + return bytes; + return 0; +} + +static bool tx_remove_byte(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, NULL); +} + +static bool tx_low_drive(struct cec_pin *pin) +{ + return tx_error_inj(pin, CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET, + CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, NULL); +} + static void cec_pin_to_idle(struct cec_pin *pin) { /* @@ -120,8 +320,16 @@ static void cec_pin_to_idle(struct cec_pin *pin) pin->rx_bit = pin->tx_bit = 0; pin->rx_msg.len = 0; memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); - pin->state = CEC_ST_IDLE; pin->ts = ns_to_ktime(0); + pin->tx_generated_poll = false; + pin->tx_post_eom = false; + if (pin->state >= CEC_ST_TX_WAIT && + pin->state <= CEC_ST_TX_LOW_DRIVE) + pin->tx_toggle ^= 1; + if (pin->state >= CEC_ST_RX_START_BIT_LOW && + pin->state <= CEC_ST_RX_LOW_DRIVE) + pin->rx_toggle ^= 1; + pin->state = CEC_ST_IDLE; } /* @@ -162,42 +370,107 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) break; case CEC_ST_TX_START_BIT_LOW: - pin->state = CEC_ST_TX_START_BIT_HIGH; + if (tx_short_start(pin)) { + /* + * Error Injection: send an invalid (too short) + * start pulse. + */ + pin->state = CEC_ST_TX_START_BIT_HIGH_SHORT; + } else if (tx_long_start(pin)) { + /* + * Error Injection: send an invalid (too long) + * start pulse. + */ + pin->state = CEC_ST_TX_START_BIT_HIGH_LONG; + } else { + pin->state = CEC_ST_TX_START_BIT_HIGH; + } + /* Generate start bit */ + cec_pin_high(pin); + break; + + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + pin->state = CEC_ST_TX_START_BIT_HIGH_CUSTOM; /* Generate start bit */ cec_pin_high(pin); break; case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: - /* If the read value is 1, then all is OK */ - if (!cec_pin_read(pin)) { + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG: + if (pin->tx_nacked) { + cec_pin_to_idle(pin); + pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_NACK; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + /* fall through */ + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_0_HIGH_LONG: + case CEC_ST_TX_DATA_BIT_1_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_LONG: + /* + * If the read value is 1, then all is OK, otherwise we have a + * low drive condition. + * + * Special case: when we generate a poll message due to an + * Arbitration Lost error injection, then ignore this since + * the pin can actually be low in that case. + */ + if (!cec_pin_read(pin) && !pin->tx_generated_poll) { /* * It's 0, so someone detected an error and pulled the * line low for 1.5 times the nominal bit period. */ pin->tx_msg.len = 0; + pin->state = CEC_ST_TX_WAIT_FOR_HIGH; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; - pin->state = CEC_ST_TX_WAIT_FOR_HIGH; wake_up_interruptible(&pin->kthread_waitq); break; } - if (pin->tx_nacked) { + /* fall through */ + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + if (tx_last_bit(pin)) { + /* Error Injection: just stop sending after this bit */ cec_pin_to_idle(pin); pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; pin->work_tx_ts = ts; - pin->work_tx_status = CEC_TX_STATUS_NACK; + pin->work_tx_status = CEC_TX_STATUS_OK; wake_up_interruptible(&pin->kthread_waitq); break; } - /* fall through */ - case CEC_ST_TX_DATA_BIT_0_HIGH: - case CEC_ST_TX_DATA_BIT_1_HIGH: pin->tx_bit++; /* fall through */ case CEC_ST_TX_START_BIT_HIGH: - if (pin->tx_bit / 10 >= pin->tx_msg.len) { + case CEC_ST_TX_START_BIT_HIGH_SHORT: + case CEC_ST_TX_START_BIT_HIGH_LONG: + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: + if (tx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_TX_LOW_DRIVE; + pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + if (pin->tx_bit / 10 >= pin->tx_msg.len + pin->tx_extra_bytes) { cec_pin_to_idle(pin); pin->tx_msg.len = 0; + if (pin->tx_generated_poll) + break; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_OK; wake_up_interruptible(&pin->kthread_waitq); @@ -205,39 +478,82 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) } switch (pin->tx_bit % 10) { - default: - v = pin->tx_msg.msg[pin->tx_bit / 10] & - (1 << (7 - (pin->tx_bit % 10))); + default: { + /* + * In the CEC_ERROR_INJ_TX_ADD_BYTES case we transmit + * extra bytes, so pin->tx_bit / 10 can become >= 16. + * Generate bit values for those extra bytes instead + * of reading them from the transmit buffer. + */ + unsigned int idx = (pin->tx_bit / 10); + u8 val = idx; + + if (idx < pin->tx_msg.len) + val = pin->tx_msg.msg[idx]; + v = val & (1 << (7 - (pin->tx_bit % 10))); + pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : - CEC_ST_TX_DATA_BIT_0_LOW; + CEC_ST_TX_DATA_BIT_0_LOW; break; - case 8: - v = pin->tx_bit / 10 == pin->tx_msg.len - 1; + } + case EOM_BIT: { + unsigned int tot_len = pin->tx_msg.len + + pin->tx_extra_bytes; + unsigned int tx_byte_idx = pin->tx_bit / 10; + + v = !pin->tx_post_eom && tx_byte_idx == tot_len - 1; + if (tot_len > 1 && tx_byte_idx == tot_len - 2 && + tx_early_eom(pin)) { + /* Error injection: set EOM one byte early */ + v = true; + pin->tx_post_eom = true; + } else if (v && tx_no_eom(pin)) { + /* Error injection: no EOM */ + v = false; + } pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : - CEC_ST_TX_DATA_BIT_0_LOW; + CEC_ST_TX_DATA_BIT_0_LOW; break; - case 9: + } + case ACK_BIT: pin->state = CEC_ST_TX_DATA_BIT_1_LOW; break; } + if (tx_custom_bit(pin)) + pin->state = CEC_ST_TX_DATA_BIT_LOW_CUSTOM; cec_pin_low(pin); break; case CEC_ST_TX_DATA_BIT_0_LOW: case CEC_ST_TX_DATA_BIT_1_LOW: v = pin->state == CEC_ST_TX_DATA_BIT_1_LOW; - pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH : - CEC_ST_TX_DATA_BIT_0_HIGH; - is_ack_bit = pin->tx_bit % 10 == 9; - if (v && (pin->tx_bit < 4 || is_ack_bit)) + is_ack_bit = pin->tx_bit % 10 == ACK_BIT; + if (v && (pin->tx_bit < 4 || is_ack_bit)) { pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE; + } else if (!is_ack_bit && tx_short_bit(pin)) { + /* Error Injection: send an invalid (too short) bit */ + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_SHORT : + CEC_ST_TX_DATA_BIT_0_HIGH_SHORT; + } else if (!is_ack_bit && tx_long_bit(pin)) { + /* Error Injection: send an invalid (too long) bit */ + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_LONG : + CEC_ST_TX_DATA_BIT_0_HIGH_LONG; + } else { + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH : + CEC_ST_TX_DATA_BIT_0_HIGH; + } + cec_pin_high(pin); + break; + + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + pin->state = CEC_ST_TX_DATA_BIT_HIGH_CUSTOM; cec_pin_high(pin); break; case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: /* Read the CEC value at the sample time */ v = cec_pin_read(pin); - is_ack_bit = pin->tx_bit % 10 == 9; + is_ack_bit = pin->tx_bit % 10 == ACK_BIT; /* * If v == 0 and we're within the first 4 bits * of the initiator, then someone else started @@ -246,7 +562,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) * transmitter has more leading 0 bits in the * initiator). */ - if (!v && !is_ack_bit) { + if (!v && !is_ack_bit && !pin->tx_generated_poll) { pin->tx_msg.len = 0; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_ARB_LOST; @@ -255,18 +571,27 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) pin->tx_bit = 0; memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); pin->rx_msg.msg[0] = pin->tx_msg.msg[0]; - pin->rx_msg.msg[0] &= ~(1 << (7 - pin->rx_bit)); + pin->rx_msg.msg[0] &= (0xff << (8 - pin->rx_bit)); pin->rx_msg.len = 0; + pin->ts = ktime_sub_us(ts, CEC_TIM_DATA_BIT_SAMPLE); pin->state = CEC_ST_RX_DATA_POST_SAMPLE; pin->rx_bit++; break; } pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE; + if (!is_ack_bit && tx_short_bit(pin)) { + /* Error Injection: send an invalid (too short) bit */ + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT; + } else if (!is_ack_bit && tx_long_bit(pin)) { + /* Error Injection: send an invalid (too long) bit */ + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG; + } if (!is_ack_bit) break; /* Was the message ACKed? */ ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v; - if (!ack) { + if (!ack && !pin->tx_ignore_nack_until_eom && + pin->tx_bit / 10 < pin->tx_msg.len && !pin->tx_post_eom) { /* * Note: the CEC spec is ambiguous regarding * what action to take when a NACK appears @@ -283,6 +608,15 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) } break; + case CEC_ST_TX_PULSE_LOW_CUSTOM: + cec_pin_high(pin); + pin->state = CEC_ST_TX_PULSE_HIGH_CUSTOM; + break; + + case CEC_ST_TX_PULSE_HIGH_CUSTOM: + cec_pin_to_idle(pin); + break; + default: break; } @@ -310,6 +644,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) bool ack; bool bcast, for_us; u8 dest; + u8 poll; switch (pin->state) { /* Receive states */ @@ -319,24 +654,44 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) break; pin->state = CEC_ST_RX_START_BIT_HIGH; delta = ktime_us_delta(ts, pin->ts); - pin->ts = ts; /* Start bit low is too short, go back to idle */ - if (delta < CEC_TIM_START_BIT_LOW_MIN - - CEC_TIM_IDLE_SAMPLE) { + if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) { cec_pin_to_idle(pin); + break; + } + if (rx_arb_lost(pin, &poll)) { + cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf); + pin->tx_generated_poll = true; + pin->tx_extra_bytes = 0; + pin->state = CEC_ST_TX_START_BIT_HIGH; + pin->ts = ts; } break; case CEC_ST_RX_START_BIT_HIGH: v = cec_pin_read(pin); delta = ktime_us_delta(ts, pin->ts); - if (v && delta > CEC_TIM_START_BIT_TOTAL_MAX - - CEC_TIM_START_BIT_LOW_MIN) { + /* + * Unfortunately the spec does not specify when to give up + * and go to idle. We just pick TOTAL_LONG. + */ + if (v && delta > CEC_TIM_START_BIT_TOTAL_LONG) { cec_pin_to_idle(pin); break; } if (v) break; + /* Start bit is too short, go back to idle */ + if (delta < CEC_TIM_START_BIT_TOTAL_MIN - CEC_TIM_IDLE_SAMPLE) { + cec_pin_to_idle(pin); + break; + } + if (rx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_RX_LOW_DRIVE; + break; + } pin->state = CEC_ST_RX_DATA_SAMPLE; pin->ts = ts; pin->rx_eom = false; @@ -351,36 +706,48 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) pin->rx_msg.msg[pin->rx_bit / 10] |= v << (7 - (pin->rx_bit % 10)); break; - case 8: + case EOM_BIT: pin->rx_eom = v; pin->rx_msg.len = pin->rx_bit / 10 + 1; break; - case 9: + case ACK_BIT: break; } pin->rx_bit++; break; case CEC_ST_RX_DATA_POST_SAMPLE: - pin->state = CEC_ST_RX_DATA_HIGH; + pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW; break; - case CEC_ST_RX_DATA_HIGH: + case CEC_ST_RX_DATA_WAIT_FOR_LOW: v = cec_pin_read(pin); delta = ktime_us_delta(ts, pin->ts); - if (v && delta > CEC_TIM_DATA_BIT_TOTAL_MAX) { + /* + * Unfortunately the spec does not specify when to give up + * and go to idle. We just pick TOTAL_LONG. + */ + if (v && delta > CEC_TIM_DATA_BIT_TOTAL_LONG) { cec_pin_to_idle(pin); break; } if (v) break; + + if (rx_low_drive(pin)) { + /* Error injection: go to low drive */ + cec_pin_low(pin); + pin->state = CEC_ST_RX_LOW_DRIVE; + break; + } + /* * Go to low drive state when the total bit time is * too short. */ if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { cec_pin_low(pin); - pin->state = CEC_ST_LOW_DRIVE; + pin->state = CEC_ST_RX_LOW_DRIVE; break; } pin->ts = ts; @@ -396,6 +763,11 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) /* ACK bit value */ ack = bcast ? 1 : !for_us; + if (for_us && rx_nack(pin)) { + /* Error injection: toggle the ACK bit */ + ack = !ack; + } + if (ack) { /* No need to write to the bus, just wait */ pin->state = CEC_ST_RX_ACK_HIGH_POST; @@ -422,7 +794,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) break; } pin->rx_bit++; - pin->state = CEC_ST_RX_DATA_HIGH; + pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW; break; case CEC_ST_RX_ACK_FINISH: @@ -444,6 +816,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) struct cec_adapter *adap = pin->adap; ktime_t ts; s32 delta; + u32 usecs; ts = ktime_get(); if (ktime_to_ns(pin->timer_ts)) { @@ -491,13 +864,27 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) /* Transmit states */ case CEC_ST_TX_WAIT_FOR_HIGH: case CEC_ST_TX_START_BIT_LOW: - case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: - case CEC_ST_TX_DATA_BIT_0_HIGH: - case CEC_ST_TX_DATA_BIT_1_HIGH: case CEC_ST_TX_START_BIT_HIGH: + case CEC_ST_TX_START_BIT_HIGH_SHORT: + case CEC_ST_TX_START_BIT_HIGH_LONG: + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: case CEC_ST_TX_DATA_BIT_0_LOW: + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_0_HIGH_LONG: case CEC_ST_TX_DATA_BIT_1_LOW: + case CEC_ST_TX_DATA_BIT_1_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_LONG: case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG: + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + case CEC_ST_TX_PULSE_LOW_CUSTOM: + case CEC_ST_TX_PULSE_HIGH_CUSTOM: cec_pin_tx_states(pin, ts); break; @@ -506,7 +893,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) case CEC_ST_RX_START_BIT_HIGH: case CEC_ST_RX_DATA_SAMPLE: case CEC_ST_RX_DATA_POST_SAMPLE: - case CEC_ST_RX_DATA_HIGH: + case CEC_ST_RX_DATA_WAIT_FOR_LOW: case CEC_ST_RX_ACK_LOW: case CEC_ST_RX_ACK_LOW_POST: case CEC_ST_RX_ACK_HIGH_POST: @@ -533,7 +920,10 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (delta / CEC_TIM_DATA_BIT_TOTAL > pin->tx_signal_free_time) { pin->tx_nacked = false; - pin->state = CEC_ST_TX_START_BIT_LOW; + if (tx_custom_start(pin)) + pin->state = CEC_ST_TX_START_BIT_LOW_CUSTOM; + else + pin->state = CEC_ST_TX_START_BIT_LOW; /* Generate start bit */ cec_pin_low(pin); break; @@ -543,6 +933,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) pin->state = CEC_ST_TX_WAIT; break; } + if (pin->tx_custom_pulse && pin->state == CEC_ST_IDLE) { + pin->tx_custom_pulse = false; + /* Generate custom pulse */ + cec_pin_low(pin); + pin->state = CEC_ST_TX_PULSE_LOW_CUSTOM; + break; + } if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL || pin->enable_irq_failed || adap->is_configuring || adap->is_configured || adap->monitor_all_cnt) @@ -553,21 +950,40 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) wake_up_interruptible(&pin->kthread_waitq); return HRTIMER_NORESTART; - case CEC_ST_LOW_DRIVE: + case CEC_ST_TX_LOW_DRIVE: + case CEC_ST_RX_LOW_DRIVE: + cec_pin_high(pin); cec_pin_to_idle(pin); break; default: break; } - if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) { + + switch (pin->state) { + case CEC_ST_TX_START_BIT_LOW_CUSTOM: + case CEC_ST_TX_DATA_BIT_LOW_CUSTOM: + case CEC_ST_TX_PULSE_LOW_CUSTOM: + usecs = pin->tx_custom_low_usecs; + break; + case CEC_ST_TX_START_BIT_HIGH_CUSTOM: + case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM: + case CEC_ST_TX_PULSE_HIGH_CUSTOM: + usecs = pin->tx_custom_high_usecs; + break; + default: + usecs = states[pin->state].usecs; + break; + } + + if (!adap->monitor_pin_cnt || usecs <= 150) { pin->wait_usecs = 0; - pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs); + pin->timer_ts = ktime_add_us(ts, usecs); hrtimer_forward_now(timer, - ns_to_ktime(states[pin->state].usecs * 1000)); + ns_to_ktime(usecs * 1000)); return HRTIMER_RESTART; } - pin->wait_usecs = states[pin->state].usecs - 100; + pin->wait_usecs = usecs - 100; pin->timer_ts = ktime_add_us(ts, 100); hrtimer_forward_now(timer, ns_to_ktime(100000)); return HRTIMER_RESTART; @@ -587,9 +1003,22 @@ static int cec_pin_thread_func(void *_adap) atomic_read(&pin->work_pin_events)); if (pin->work_rx_msg.len) { - cec_received_msg_ts(adap, &pin->work_rx_msg, + struct cec_msg *msg = &pin->work_rx_msg; + + if (msg->len > 1 && msg->len < CEC_MAX_MSG_SIZE && + rx_add_byte(pin)) { + /* Error injection: add byte to the message */ + msg->msg[msg->len++] = 0x55; + } + if (msg->len > 2 && rx_remove_byte(pin)) { + /* Error injection: remove byte from message */ + msg->len--; + } + if (msg->len > CEC_MAX_MSG_SIZE) + msg->len = CEC_MAX_MSG_SIZE; + cec_received_msg_ts(adap, msg, ns_to_ktime(pin->work_rx_msg.rx_ts)); - pin->work_rx_msg.len = 0; + msg->len = 0; } if (pin->work_tx_status) { unsigned int tx_status = pin->work_tx_status; @@ -698,7 +1127,16 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, struct cec_pin *pin = adap->pin; pin->tx_signal_free_time = signal_free_time; + pin->tx_extra_bytes = 0; pin->tx_msg = *msg; + if (msg->len > 1) { + /* Error injection: add byte to the message */ + pin->tx_extra_bytes = tx_add_bytes(pin); + } + if (msg->len > 2 && tx_remove_byte(pin)) { + /* Error injection: remove byte from the message */ + pin->tx_msg.len--; + } pin->work_tx_status = 0; pin->tx_bit = 0; cec_pin_start_timer(pin); -- cgit From 2b76e5392d0647c35226b464269b87026578ea83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Mar 2018 02:02:24 -0500 Subject: media: cec-pin: improve status log Keep track of the number of short or long start bits, the number of short or long data bits and the number of initiated or detected low drive conditions. Show this information in the status debugfs log. Helpful when debugging, particularly when doing error injection as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-pin-priv.h | 13 +++++++++ drivers/media/cec/cec-pin.c | 58 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index c9349f68e554..dae8ba6f1037 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -181,6 +181,18 @@ struct cec_pin { struct cec_msg rx_msg; u32 rx_bit; bool rx_toggle; + u32 rx_start_bit_low_too_short_cnt; + u64 rx_start_bit_low_too_short_ts; + u32 rx_start_bit_low_too_short_delta; + u32 rx_start_bit_too_short_cnt; + u64 rx_start_bit_too_short_ts; + u32 rx_start_bit_too_short_delta; + u32 rx_start_bit_too_long_cnt; + u32 rx_data_bit_too_short_cnt; + u64 rx_data_bit_too_short_ts; + u32 rx_data_bit_too_short_delta; + u32 rx_data_bit_too_long_cnt; + u32 rx_low_drive_cnt; struct cec_msg work_rx_msg; u8 work_tx_status; @@ -205,6 +217,7 @@ struct cec_pin { bool tx_generated_poll; bool tx_post_eom; u8 tx_extra_bytes; + u32 tx_low_drive_cnt; #ifdef CONFIG_CEC_PIN_ERROR_INJ u64 error_inj[CEC_ERROR_INJ_OP_ANY + 1]; u8 error_inj_args[CEC_ERROR_INJ_OP_ANY + 1][CEC_ERROR_INJ_NUM_ARGS]; diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index d03ed4eefdd6..da8c514c657d 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -432,6 +432,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) pin->state = CEC_ST_TX_WAIT_FOR_HIGH; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; + pin->tx_low_drive_cnt++; wake_up_interruptible(&pin->kthread_waitq); break; } @@ -463,6 +464,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) break; pin->work_tx_ts = ts; pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; + pin->tx_low_drive_cnt++; wake_up_interruptible(&pin->kthread_waitq); break; } @@ -656,6 +658,10 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) delta = ktime_us_delta(ts, pin->ts); /* Start bit low is too short, go back to idle */ if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) { + if (!pin->rx_start_bit_low_too_short_cnt++) { + pin->rx_start_bit_low_too_short_ts = pin->ts; + pin->rx_start_bit_low_too_short_delta = delta; + } cec_pin_to_idle(pin); break; } @@ -676,6 +682,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) * and go to idle. We just pick TOTAL_LONG. */ if (v && delta > CEC_TIM_START_BIT_TOTAL_LONG) { + pin->rx_start_bit_too_long_cnt++; cec_pin_to_idle(pin); break; } @@ -683,6 +690,10 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) break; /* Start bit is too short, go back to idle */ if (delta < CEC_TIM_START_BIT_TOTAL_MIN - CEC_TIM_IDLE_SAMPLE) { + if (!pin->rx_start_bit_too_short_cnt++) { + pin->rx_start_bit_too_short_ts = pin->ts; + pin->rx_start_bit_too_short_delta = delta; + } cec_pin_to_idle(pin); break; } @@ -690,6 +701,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) /* Error injection: go to low drive */ cec_pin_low(pin); pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; break; } pin->state = CEC_ST_RX_DATA_SAMPLE; @@ -728,6 +740,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) * and go to idle. We just pick TOTAL_LONG. */ if (v && delta > CEC_TIM_DATA_BIT_TOTAL_LONG) { + pin->rx_data_bit_too_long_cnt++; cec_pin_to_idle(pin); break; } @@ -738,6 +751,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) /* Error injection: go to low drive */ cec_pin_low(pin); pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; break; } @@ -746,8 +760,13 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) * too short. */ if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { + if (!pin->rx_data_bit_too_short_cnt++) { + pin->rx_data_bit_too_short_ts = pin->ts; + pin->rx_data_bit_too_short_delta = delta; + } cec_pin_low(pin); pin->state = CEC_ST_RX_LOW_DRIVE; + pin->rx_low_drive_cnt++; break; } pin->ts = ts; @@ -1148,9 +1167,9 @@ static void cec_pin_adap_status(struct cec_adapter *adap, { struct cec_pin *pin = adap->pin; - seq_printf(file, "state: %s\n", states[pin->state].name); - seq_printf(file, "tx_bit: %d\n", pin->tx_bit); - seq_printf(file, "rx_bit: %d\n", pin->rx_bit); + seq_printf(file, "state: %s\n", states[pin->state].name); + seq_printf(file, "tx_bit: %d\n", pin->tx_bit); + seq_printf(file, "rx_bit: %d\n", pin->rx_bit); seq_printf(file, "cec pin: %d\n", pin->ops->read(adap)); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); if (pin->timer_100ms_overruns) { @@ -1163,11 +1182,44 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "avg timer overrun: %u usecs\n", pin->timer_sum_overrun / pin->timer_100ms_overruns); } + if (pin->rx_start_bit_low_too_short_cnt) + seq_printf(file, + "rx start bit low too short: %u (delta %u, ts %llu)\n", + pin->rx_start_bit_low_too_short_cnt, + pin->rx_start_bit_low_too_short_delta, + pin->rx_start_bit_low_too_short_ts); + if (pin->rx_start_bit_too_short_cnt) + seq_printf(file, + "rx start bit too short: %u (delta %u, ts %llu)\n", + pin->rx_start_bit_too_short_cnt, + pin->rx_start_bit_too_short_delta, + pin->rx_start_bit_too_short_ts); + if (pin->rx_start_bit_too_long_cnt) + seq_printf(file, "rx start bit too long: %u\n", + pin->rx_start_bit_too_long_cnt); + if (pin->rx_data_bit_too_short_cnt) + seq_printf(file, + "rx data bit too short: %u (delta %u, ts %llu)\n", + pin->rx_data_bit_too_short_cnt, + pin->rx_data_bit_too_short_delta, + pin->rx_data_bit_too_short_ts); + if (pin->rx_data_bit_too_long_cnt) + seq_printf(file, "rx data bit too long: %u\n", + pin->rx_data_bit_too_long_cnt); + seq_printf(file, "rx initiated low drive: %u\n", pin->rx_low_drive_cnt); + seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt); pin->timer_cnt = 0; pin->timer_100ms_overruns = 0; pin->timer_300ms_overruns = 0; pin->timer_max_overrun = 0; pin->timer_sum_overrun = 0; + pin->rx_start_bit_low_too_short_cnt = 0; + pin->rx_start_bit_too_short_cnt = 0; + pin->rx_start_bit_too_long_cnt = 0; + pin->rx_data_bit_too_short_cnt = 0; + pin->rx_data_bit_too_long_cnt = 0; + pin->rx_low_drive_cnt = 0; + pin->tx_low_drive_cnt = 0; if (pin->ops->status) pin->ops->status(adap, file); } -- cgit From 6ec1cbf6b12531a794bbc007fbf6e74edf7fc93c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 6 Mar 2018 16:20:00 -0500 Subject: media: cec: improve CEC pin event handling It turns out that the struct cec_fh event buffer size of 64 events (64 for CEC_EVENT_PIN_CEC_LOW and 64 for _HIGH) is too small. It's about 160 ms worth of events and if the Raspberry Pi is busy, then it might take too long for the application to be scheduled so that it can drain the pending events. Increase these buffers to 800 events which is at least 2 seconds worth of events. There is also a FIFO in between the interrupt and the cec-pin thread. The thread passes the events on to the CEC core. It is important that should this FIFO fill up the cec core will be informed that events have been lost so this can be communicated to the user by setting CEC_EVENT_FL_DROPPED_EVENTS. It is very hard to debug CEC problems if events were lost without informing the user of that fact. If events were dropped due to the FIFO filling up, then the debugfs status file will let you know how many events were dropped. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 8 +++++--- drivers/media/cec/cec-pin-priv.h | 10 +++++++--- drivers/media/cec/cec-pin.c | 31 +++++++++++++++++++++++-------- drivers/media/platform/vivid/vivid-cec.c | 8 ++++---- 4 files changed, 39 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index cf6dc3f3a17e..002ed4c90371 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -73,8 +73,8 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { - static const u8 max_events[CEC_NUM_EVENTS] = { - 1, 1, 64, 64, 8, 8, + static const u16 max_events[CEC_NUM_EVENTS] = { + 1, 1, 800, 800, 8, 8, }; struct cec_event_entry *entry; unsigned int ev_idx = new_ev->event - 1; @@ -142,11 +142,13 @@ static void cec_queue_event(struct cec_adapter *adap, } /* Notify userspace that the CEC pin changed state at the given time. */ -void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts) +void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, + bool dropped_events, ktime_t ts) { struct cec_event ev = { .event = is_high ? CEC_EVENT_PIN_CEC_HIGH : CEC_EVENT_PIN_CEC_LOW, + .flags = dropped_events ? CEC_EVENT_FL_DROPPED_EVENTS : 0, }; struct cec_fh *fh; diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h index dae8ba6f1037..f423db8855d9 100644 --- a/drivers/media/cec/cec-pin-priv.h +++ b/drivers/media/cec/cec-pin-priv.h @@ -153,7 +153,9 @@ enum cec_pin_state { /* The default for the low/high time of the custom pulse */ #define CEC_TIM_CUSTOM_DEFAULT 1000 -#define CEC_NUM_PIN_EVENTS 128 +#define CEC_NUM_PIN_EVENTS 128 +#define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) +#define CEC_PIN_EVENT_FL_DROPPED (1 << 1) #define CEC_PIN_IRQ_UNCHANGED 0 #define CEC_PIN_IRQ_DISABLE 1 @@ -198,11 +200,13 @@ struct cec_pin { u8 work_tx_status; ktime_t work_tx_ts; atomic_t work_irq_change; - atomic_t work_pin_events; + atomic_t work_pin_num_events; unsigned int work_pin_events_wr; unsigned int work_pin_events_rd; ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS]; - bool work_pin_is_high[CEC_NUM_PIN_EVENTS]; + u8 work_pin_events[CEC_NUM_PIN_EVENTS]; + bool work_pin_events_dropped; + u32 work_pin_events_dropped_cnt; ktime_t timer_ts; u32 timer_cnt; u32 timer_100ms_overruns; diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index da8c514c657d..fafe1ebc8aff 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -114,12 +114,21 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) return; pin->adap->cec_pin_is_high = v; - if (atomic_read(&pin->work_pin_events) < CEC_NUM_PIN_EVENTS) { - pin->work_pin_is_high[pin->work_pin_events_wr] = v; + if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { + u8 ev = v; + + if (pin->work_pin_events_dropped) { + pin->work_pin_events_dropped = false; + v |= CEC_PIN_EVENT_FL_DROPPED; + } + pin->work_pin_events[pin->work_pin_events_wr] = ev; pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); pin->work_pin_events_wr = (pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS; - atomic_inc(&pin->work_pin_events); + atomic_inc(&pin->work_pin_num_events); + } else { + pin->work_pin_events_dropped = true; + pin->work_pin_events_dropped_cnt++; } wake_up_interruptible(&pin->kthread_waitq); } @@ -1019,7 +1028,7 @@ static int cec_pin_thread_func(void *_adap) pin->work_rx_msg.len || pin->work_tx_status || atomic_read(&pin->work_irq_change) || - atomic_read(&pin->work_pin_events)); + atomic_read(&pin->work_pin_num_events)); if (pin->work_rx_msg.len) { struct cec_msg *msg = &pin->work_rx_msg; @@ -1047,14 +1056,16 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } - while (atomic_read(&pin->work_pin_events)) { + while (atomic_read(&pin->work_pin_num_events)) { unsigned int idx = pin->work_pin_events_rd; + u8 v = pin->work_pin_events[idx]; cec_queue_pin_cec_event(adap, - pin->work_pin_is_high[idx], + v & CEC_PIN_EVENT_FL_IS_HIGH, + v & CEC_PIN_EVENT_FL_DROPPED, pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS; - atomic_dec(&pin->work_pin_events); + atomic_dec(&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change, @@ -1090,8 +1101,9 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) pin->enabled = enable; if (enable) { - atomic_set(&pin->work_pin_events, 0); + atomic_set(&pin->work_pin_num_events, 0); pin->work_pin_events_rd = pin->work_pin_events_wr = 0; + pin->work_pin_events_dropped = false; cec_pin_read(pin); cec_pin_to_idle(pin); pin->tx_msg.len = 0; @@ -1171,6 +1183,8 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "tx_bit: %d\n", pin->tx_bit); seq_printf(file, "rx_bit: %d\n", pin->rx_bit); seq_printf(file, "cec pin: %d\n", pin->ops->read(adap)); + seq_printf(file, "cec pin events dropped: %u\n", + pin->work_pin_events_dropped_cnt); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); if (pin->timer_100ms_overruns) { seq_printf(file, "timer overruns > 100ms: %u of %u\n", @@ -1208,6 +1222,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap, pin->rx_data_bit_too_long_cnt); seq_printf(file, "rx initiated low drive: %u\n", pin->rx_low_drive_cnt); seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt); + pin->work_pin_events_dropped_cnt = 0; pin->timer_cnt = 0; pin->timer_100ms_overruns = 0; pin->timer_300ms_overruns = 0; diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index c2c889d6dcf5..71105fa4c5f9 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -79,9 +79,9 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, */ ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); - cec_queue_pin_cec_event(adap, false, ts); + cec_queue_pin_cec_event(adap, false, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); for (i = 0; i < 10 * len; i++) { @@ -96,12 +96,12 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, bit = cec_msg_is_broadcast(msg) ^ nacked; break; } - cec_queue_pin_cec_event(adap, false, ts); + cec_queue_pin_cec_event(adap, false, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); else ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); else -- cgit From 39adb4e739050dcdb74c3465d261de8de5f224b7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 09:01:11 -0400 Subject: media: dvbdev: handle ENOMEM error at dvb_module_probe() If allocation of struct board_info fails, return NULL from dvb_module_probe(). Fix this warning: drivers/media/dvb-core/dvbdev.c:958 dvb_module_probe() error: potential null dereference 'board_info'. (kzalloc returns null) Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index cf747d753a79..787fe06df217 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -953,6 +953,8 @@ struct i2c_client *dvb_module_probe(const char *module_name, struct i2c_board_info *board_info; board_info = kzalloc(sizeof(*board_info), GFP_KERNEL); + if (!board_info) + return NULL; if (name) strlcpy(board_info->type, name, I2C_NAME_SIZE); -- cgit From f44d6107f87936c0359358184627fd82e60bd4b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 11:40:15 -0400 Subject: media: dvb_frontend: add proper __user annotations Solves those warnings: drivers/media/dvb-core/dvb_frontend.c:2297:39: warning: incorrect type in argument 1 (different address spaces) drivers/media/dvb-core/dvb_frontend.c:2297:39: expected void const [noderef] * drivers/media/dvb-core/dvb_frontend.c:2297:39: got struct dtv_property *props drivers/media/dvb-core/dvb_frontend.c:2331:39: warning: incorrect type in argument 1 (different address spaces) drivers/media/dvb-core/dvb_frontend.c:2331:39: expected void const [noderef] * drivers/media/dvb-core/dvb_frontend.c:2331:39: got struct dtv_property *props No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index a7ed16e0841d..21a7d4b47e1a 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2294,7 +2294,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); @@ -2328,7 +2328,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); -- cgit From 8395597fa4ecb0cab9241a399d78d5d3a95d928f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 13:19:22 -0400 Subject: media: vpss: fix annotations for vpss_regs_base2 Fix those warnings: drivers/media/platform/davinci/vpss.c:510:25: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/davinci/vpss.c:510:25: expected void volatile [noderef] *addr drivers/media/platform/davinci/vpss.c:510:25: got unsigned int [usertype] *static [toplevel] [assigned] vpss_regs_base2 drivers/media/platform/davinci/vpss.c:520:34: warning: incorrect type in assignment (different address spaces) drivers/media/platform/davinci/vpss.c:520:34: expected unsigned int [usertype] *static [toplevel] [assigned] vpss_regs_base2 drivers/media/platform/davinci/vpss.c:520:34: got void [noderef] * drivers/media/platform/davinci/vpss.c:522:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/davinci/vpss.c:522:54: expected void volatile [noderef] *addr drivers/media/platform/davinci/vpss.c:522:54: got unsigned int [usertype] *static [toplevel] [assigned] vpss_regs_base2 Weird enough, vpss_regs_base0 and vpss_regs_base1 were properly annotated. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index b73886519f4f..19cf6853411e 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -116,7 +116,7 @@ struct vpss_hw_ops { struct vpss_oper_config { __iomem void *vpss_regs_base0; __iomem void *vpss_regs_base1; - resource_size_t *vpss_regs_base2; + __iomem void *vpss_regs_base2; enum vpss_platform_type platform; spinlock_t vpss_lock; struct vpss_hw_ops hw_ops; -- cgit From 43d1ed0811bb2780c49fa17e90a29b27078244a7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 13:22:27 -0400 Subject: media: rca: declare formats var as static As warned: drivers/media/platform/rockchip/rga/rga.c:210:16: warning: symbol 'formats' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 89296de9cf4a..d508a8ba6f89 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -207,7 +207,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx) return 0; } -struct rga_fmt formats[] = { +static struct rga_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB32, .color_swap = RGA_COLOR_RB_SWAP, -- cgit From baa6f19b37cc1aebf6e84ed4c451f1078693bb4b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 13:44:33 -0400 Subject: media: ov5670: get rid of a series of __be warnings There are some troubles on this driver with respect to the usage of __be16 and __b32 macros: drivers/media/i2c/ov5670.c:1857:27: warning: incorrect type in initializer (different base types) drivers/media/i2c/ov5670.c:1857:27: expected unsigned short [unsigned] [usertype] reg_addr_be drivers/media/i2c/ov5670.c:1857:27: got restricted __be16 [usertype] drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1880:16: warning: cast to restricted __be32 drivers/media/i2c/ov5670.c:1901:13: warning: incorrect type in assignment (different base types) drivers/media/i2c/ov5670.c:1901:13: expected unsigned int [unsigned] [usertype] val drivers/media/i2c/ov5670.c:1901:13: got restricted __be32 [usertype] Fix them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 556a95c30781..d2db480da1b9 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1853,8 +1853,8 @@ static int ov5670_read_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); struct i2c_msg msgs[2]; u8 *data_be_p; - u32 data_be = 0; - u16 reg_addr_be = cpu_to_be16(reg); + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); int ret; if (len > 4) @@ -1891,6 +1891,7 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, int val_i; u8 buf[6]; u8 *val_p; + __be32 tmp; if (len > 4) return -EINVAL; @@ -1898,8 +1899,8 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, buf[0] = reg >> 8; buf[1] = reg & 0xff; - val = cpu_to_be32(val); - val_p = (u8 *)&val; + tmp = cpu_to_be32(val); + val_p = (u8 *)&tmp; buf_i = 2; val_i = 4 - len; -- cgit From 1a086879fdd37d9e4c3dd4e49fac62f7e418e17e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 13:54:18 -0400 Subject: media: v4l2-tpg-core: avoid buffer overflows Fix the following warnings: drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:1146 gen_twopix() error: buffer overflow 'buf[1]' 8 <= 8 drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:1152 gen_twopix() error: buffer overflow 'buf[1]' 8 <= 8 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index d248d1fb9d1d..37632bc524d4 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -1143,13 +1143,13 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_NV24: buf[0][offset] = r_y_h; buf[1][2 * offset] = g_u_s; - buf[1][2 * offset + 1] = b_v; + buf[1][(2 * offset + 1) % 8] = b_v; break; case V4L2_PIX_FMT_NV42: buf[0][offset] = r_y_h; buf[1][2 * offset] = b_v; - buf[1][2 * offset + 1] = g_u_s; + buf[1][(2 * offset + 1) %8] = g_u_s; break; case V4L2_PIX_FMT_YUYV: -- cgit From 912d2f8228be077a1743adb797ada1dfcfe99c81 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 14:02:21 -0400 Subject: media: v4l2-ioctl: fix some "too small" warnings While the code there is right, it produces three false positives: drivers/media/v4l2-core/v4l2-ioctl.c:2868 video_usercopy() error: copy_from_user() 'parg' too small (128 vs 16383) drivers/media/v4l2-core/v4l2-ioctl.c:2868 video_usercopy() error: copy_from_user() 'parg' too small (128 vs 16383) drivers/media/v4l2-core/v4l2-ioctl.c:2876 video_usercopy() error: memset() 'parg' too small (128 vs 16383) Store the ioctl size on a cache var, in order to suppress those. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 672ab22ccd96..a5dab16ff2d2 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2833,14 +2833,15 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, size_t array_size = 0; void __user *user_ptr = NULL; void **kernel_ptr = NULL; + size_t size = _IOC_SIZE(cmd); /* Copy arguments into temp kernel buffer */ if (_IOC_DIR(cmd) != _IOC_NONE) { - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + if (size <= sizeof(sbuf)) { parg = sbuf; } else { /* too big to allocate from stack */ - mbuf = kvmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + mbuf = kvmalloc(size, GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; @@ -2848,7 +2849,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned int n = _IOC_SIZE(cmd); + unsigned int n = size; /* * In some cases, only a few fields are used as input, @@ -2869,11 +2870,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, goto out; /* zero out anything we don't copy from userspace */ - if (n < _IOC_SIZE(cmd)) - memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); + if (n < size) + memset((u8 *)parg + n, 0, size - n); } else { /* read-only ioctl */ - memset(parg, 0, _IOC_SIZE(cmd)); + memset(parg, 0, size); } } @@ -2931,7 +2932,7 @@ out_array_args: switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + if (copy_to_user((void __user *)arg, parg, size)) err = -EFAULT; break; } -- cgit From 89d6e45c8af8b6e9351564a15467c90e862bbfcd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 15:13:58 -0400 Subject: media: sp887x: fix a warning drivers/media/dvb-frontends/sp887x.c:179 sp887x_initial_setup() error: memcpy() '&buf[2]' too small (30 vs 16384) This is actually a false alarm, but reverting the check order makes not only for humans to review the code, but also cleans the warning. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/sp887x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index 572a297811fe..f39d566d7d1d 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -136,7 +136,7 @@ static void sp887x_setup_agc (struct sp887x_state* state) static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) { struct sp887x_state* state = fe->demodulator_priv; - u8 buf [BLOCKSIZE+2]; + u8 buf [BLOCKSIZE + 2]; int i; int fw_size = fw->size; const unsigned char *mem = fw->data; @@ -144,7 +144,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware dprintk("%s\n", __func__); /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */ - if (fw_size < FW_SIZE+10) + if (fw_size < FW_SIZE + 10) return -ENODEV; mem = fw->data + 10; @@ -167,7 +167,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware int c = BLOCKSIZE; int err; - if (i+c > FW_SIZE) + if (c > FW_SIZE - i) c = FW_SIZE - i; /* bit 0x8000 in address is set to enable 13bit mode */ -- cgit From b0121ca03865ec5fa46f2ffc9d354cd5e5613023 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:23:23 -0400 Subject: media: tvaudio: improve error handling The error handling logic at tvaudio is broken on several ways, as it doesn't really check right when an error occurs. Change it to return the proper error code from read/write routines and fix the errors on reads. Shuts up the following warnings: drivers/media/i2c/tvaudio.c:222 chip_read() error: uninitialized symbol 'buffer'. drivers/media/i2c/tvaudio.c:223 chip_read() error: uninitialized symbol 'buffer'. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvaudio.c | 92 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 772164b848ef..5919214a56bf 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -156,14 +156,18 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); unsigned char buffer[2]; + int rc; if (subaddr < 0) { v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(c, buffer, 1)) { + rc = i2c_master_send(c, buffer, 1); + if (rc != 1) { v4l2_warn(sd, "I/O error (write 0x%x)\n", val); - return -1; + if (rc < 0) + return rc; + return -EIO; } } else { if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { @@ -178,10 +182,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(c, buffer, 2)) { + rc = i2c_master_send(c, buffer, 2); + if (rc != 2) { v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n", subaddr, val); - return -1; + if (rc < 0) + return rc; + return -EIO; } } return 0; @@ -214,10 +221,14 @@ static int chip_read(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); unsigned char buffer; + int rc; - if (1 != i2c_master_recv(c, &buffer, 1)) { + rc = i2c_master_recv(c, &buffer, 1); + if (rc != 1) { v4l2_warn(sd, "I/O error (read)\n"); - return -1; + if (rc < 0) + return rc; + return -EIO; } v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer); return buffer; @@ -227,6 +238,7 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) { struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); + int rc; unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { @@ -245,9 +257,12 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) write[0] = subaddr; - if (2 != i2c_transfer(c->adapter, msgs, 2)) { + rc = i2c_transfer(c->adapter, msgs, 2); + if (rc != 2) { v4l2_warn(sd, "I/O error (read2)\n"); - return -1; + if (rc < 0) + return rc; + return -EIO; } v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n", subaddr, read[0]); @@ -258,7 +273,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) { struct v4l2_subdev *sd = &chip->sd; struct i2c_client *c = v4l2_get_subdevdata(sd); - int i; + int i, rc; if (0 == cmd->count) return 0; @@ -284,9 +299,12 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk(KERN_CONT "\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) { + rc = i2c_master_send(c, cmd->bytes, cmd->count); + if (rc != cmd->count) { v4l2_warn(sd, "I/O error (%s)\n", name); - return -1; + if (rc < 0) + return rc; + return -EIO; } return 0; } @@ -400,8 +418,12 @@ static int tda9840_getrxsubchans(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int val, mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA9840_DS_DUAL) mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; if (val & TDA9840_ST_STEREO) @@ -445,7 +467,12 @@ static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode) static int tda9840_checkit(struct CHIPSTATE *chip) { int rc; + rc = chip_read(chip); + if (rc < 0) + return 0; + + /* lower 5 bits should be 0 */ return ((rc & 0x1f) == 0) ? 1 : 0; } @@ -563,6 +590,9 @@ static int tda985x_getrxsubchans(struct CHIPSTATE *chip) /* Allows forced mono */ mode = V4L2_TUNER_SUB_MONO; val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA985x_STP) mode = V4L2_TUNER_SUB_STEREO; if (val & TDA985x_SAPP) @@ -720,8 +750,12 @@ static int tda9873_getrxsubchans(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int val,mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TDA9873_STEREO) mode = V4L2_TUNER_SUB_STEREO; if (val & TDA9873_DUAL) @@ -780,7 +814,8 @@ static int tda9873_checkit(struct CHIPSTATE *chip) { int rc; - if (-1 == (rc = chip_read2(chip,254))) + rc = chip_read2(chip, 254); + if (rc < 0) return 0; return (rc & ~0x1f) == 0x80; } @@ -926,11 +961,14 @@ static int tda9874a_getrxsubchans(struct CHIPSTATE *chip) mode = V4L2_TUNER_SUB_MONO; - if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) + dsr = chip_read2(chip, TDA9874A_DSR); + if (dsr < 0) return mode; - if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR))) + nsr = chip_read2(chip, TDA9874A_NSR); + if (nsr < 0) return mode; - if(-1 == (necr = chip_read2(chip,TDA9874A_NECR))) + necr = chip_read2(chip, TDA9874A_NECR); + if (necr < 0) return mode; /* need to store dsr/nsr somewhere */ @@ -1059,9 +1097,11 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) struct v4l2_subdev *sd = &chip->sd; int dic,sic; /* device id. and software id. codes */ - if(-1 == (dic = chip_read2(chip,TDA9874A_DIC))) + dic = chip_read2(chip, TDA9874A_DIC); + if (dic < 0) return 0; - if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) + sic = chip_read2(chip, TDA9874A_SIC); + if (sic < 0) return 0; v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); @@ -1201,7 +1241,11 @@ static int tda9875_checkit(struct CHIPSTATE *chip) int dic, rev; dic = chip_read2(chip, 254); + if (dic < 0) + return 0; rev = chip_read2(chip, 255); + if (rev < 0) + return 0; if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */ v4l2_info(sd, "found tda9875%s rev. %d.\n", @@ -1377,8 +1421,12 @@ static int ta8874z_getrxsubchans(struct CHIPSTATE *chip) { int val, mode; - val = chip_read(chip); mode = V4L2_TUNER_SUB_MONO; + + val = chip_read(chip); + if (val < 0) + return mode; + if (val & TA8874Z_B1){ mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; }else if (!(val & TA8874Z_B0)){ @@ -1431,7 +1479,11 @@ static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode) static int ta8874z_checkit(struct CHIPSTATE *chip) { int rc; + rc = chip_read(chip); + if (rc < 0) + return rc; + return ((rc & 0x1f) == 0x1f) ? 1 : 0; } -- cgit From d3c449e16fc829dba347dc72106f8d28b15896f9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:36:26 -0400 Subject: media: bttv-input: better handle errors at I2C transfer The error handling logic at get_key_pv951() is a little bit akward, with produces this false positive warning: drivers/media/pci/bt8xx/bttv-input.c:344 get_key_pv951() error: uninitialized symbol 'b'. Do a cleanup. As a side effect, it also improves its coding style. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-input.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index da49c5567db5..08266b23826e 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -332,11 +332,15 @@ static void bttv_ir_stop(struct bttv *btv) static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dprintk("read error\n"); + if (rc < 0) + return rc; return -EIO; } -- cgit From 0df305eb50e5dc447ddb9eab71bc7394cb9e76e4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:48:07 -0400 Subject: media: solo6x10: simplify the logic at solo_p2m_dma_desc() The logic with gets a p2m_id is more complex than needed, causing false positives with static analyzers: drivers/media/pci/solo6x10/solo6x10-p2m.c:81 solo_p2m_dma_desc() error: buffer overflow 'solo_dev->p2m_dev' 4 <= s32max Make it simpler and use unsigned int. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-p2m.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c index 8c8484674d2f..46c30430e30b 100644 --- a/drivers/media/pci/solo6x10/solo6x10-p2m.c +++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c @@ -69,14 +69,11 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev, unsigned int timeout; unsigned int config = 0; int ret = 0; - int p2m_id = 0; + unsigned int p2m_id = 0; /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ - if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { + if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; - if (p2m_id < 0) - p2m_id = -p2m_id; - } p2m_dev = &solo_dev->p2m_dev[p2m_id]; -- cgit From aea629c1261f9a8ba06a8ee93b45ac5bd4475943 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 14:56:01 -0400 Subject: media: cx88: fix two warnings drivers/media/pci/cx88/cx88-alsa.c:295 cx88_alsa_dma_init() warn: argument 3 to %08lx specifier is cast from pointer drivers/media/pci/cx88/cx88-alsa.c:669 snd_cx88_wm8775_volume_put() warn: potential negative subtraction from max '65535 - (32768 * left) / right' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-alsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 9740326bc93f..ab09bb55cf45 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -292,8 +292,8 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) return -ENOMEM; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)buf->vaddr, nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + buf->vaddr, nr_pages << PAGE_SHIFT); memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; @@ -656,8 +656,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, { struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - int left = value->value.integer.value[0]; - int right = value->value.integer.value[1]; + u16 left = value->value.integer.value[0]; + u16 right = value->value.integer.value[1]; int v, b; /* Pass volume & balance onto any WM8775 */ -- cgit From 6b65dd4c2c318f8ae666d74ba116b417b5e8263f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 15:16:25 -0400 Subject: media: cx23885: fix a warning drivers/media/pci/cx23885/cx23885-alsa.c:92 cx23885_alsa_dma_init() warn: argument 3 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-alsa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index d8c3637e492e..20b3cb17f97f 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -89,9 +89,8 @@ static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) return -ENOMEM; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)buf->vaddr, - nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + buf->vaddr, nr_pages << PAGE_SHIFT); memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; -- cgit From 42eb523ff59e6591bf21954fe30db555efc695d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:33:36 -0400 Subject: soc_camera: fix a weird cast on printk drivers/media/platform/soc_camera/soc_camera.c:790 soc_camera_mmap() warn: argument 4 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 1318512c8fe3..69f0d8e80bd8 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -787,7 +787,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); int err; - dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + dev_dbg(icd->pdev, "mmap called, vma=%p\n", vma); if (icd->streamer != file) return -EBUSY; -- cgit From b1a5dea69e48c3306e47ac470e3ff9f2fc0bbe28 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Mar 2018 15:00:32 -0400 Subject: media: videobuf-dma-sg: Fix a weird cast Just use %p. Fixes this warning: drivers/media/v4l2-core/videobuf-dma-sg.c:247 videobuf_dma_init_kernel() warn: argument 2 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-sg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index f412429cf5ba..add2edb23eac 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -244,9 +244,8 @@ static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, goto out_free_pages; } - dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vaddr, - nr_pages << PAGE_SHIFT); + dprintk(1, "vmalloc is at addr %p, size=%d\n", + dma->vaddr, nr_pages << PAGE_SHIFT); memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; -- cgit From 057bad7bc9eec71152be1b7bf1f9c2470b7db8e6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:52:25 -0400 Subject: media: ivtvfb: Cleanup some warnings drivers/media/pci/ivtv/ivtvfb.c:349 ivtvfb_prep_frame() warn: argument 3 to %08lx specifier is cast from pointer drivers/media/pci/ivtv/ivtvfb.c:360 ivtvfb_prep_frame() warn: argument 3 to %08lx specifier is cast from pointer drivers/media/pci/ivtv/ivtvfb.c:363 ivtvfb_prep_frame() warn: argument 4 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtvfb.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 621b2f613d81..8e62b8be6529 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -346,8 +346,8 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", - (unsigned long)source); + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (%p)\n", + source); if (dest_offset & 3) IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); @@ -357,12 +357,10 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", - (unsigned long)source); + IVTVFB_WARN("Invalid userspace pointer %p\n", source); - IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", - dest_offset, (unsigned long)source, - count); + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source %p count %d\n", + dest_offset, source, count); return -EINVAL; } -- cgit From 86f181c766218390ed8fff247a6dd4c9c2c1c5ae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 06:56:55 -0400 Subject: media: s2255drv: fix a casting warning drivers/media/usb/s2255/s2255drv.c:651 s2255_fillbuff() warn: argument 3 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a00a15f55d37..82927eb334c4 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -648,8 +648,8 @@ static void s2255_fillbuff(struct s2255_vc *vc, pr_err("s2255: =======no frame\n"); return; } - dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n", - (unsigned long)vbuf, pos); + dprintk(dev, 2, "s2255fill at : Buffer %p size= %d\n", + vbuf, pos); } -- cgit From 5fd46ac9291402ba1d04e2c5ce3b295e1c13143e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:03:51 -0400 Subject: media: saa7134-input: improve error handling Currently, the code produces those false-positives: drivers/media/pci/saa7134/saa7134-input.c:203 get_key_msi_tvanywhere_plus() error: uninitialized symbol 'b'. drivers/media/pci/saa7134/saa7134-input.c:251 get_key_kworld_pc150u() error: uninitialized symbol 'b'. drivers/media/pci/saa7134/saa7134-input.c:275 get_key_purpletv() error: uninitialized symbol 'b'. Improve the error handling code, making it to look like our coding style. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-input.c | 46 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 33ee8322895e..0e28c5021ac4 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -115,7 +115,7 @@ static int build_key(struct saa7134_dev *dev) static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { - int gpio; + int gpio, rc; int attempt = 0; unsigned char b; @@ -153,8 +153,11 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, attempt); return -EIO; } - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -169,7 +172,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *scancode, u8 *toggle) { unsigned char b; - int gpio; + int gpio, rc; /* is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; @@ -193,8 +196,11 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -218,6 +224,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, { unsigned char b; unsigned int gpio; + int rc; /* is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; @@ -241,8 +248,11 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -263,11 +273,15 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -288,11 +302,17 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char buf[5]; /* poll IR chip */ - if (5 != i2c_master_recv(ir->c, buf, 5)) + rc = i2c_master_recv(ir->c, buf, 5); + if (rc != 5) { + ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; + } /* Check if some key were pressed */ if (!(buf[0] & 0x80)) @@ -319,6 +339,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char data[12]; u32 gpio; @@ -335,8 +356,11 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, ir->c->addr = 0x5a >> 1; - if (12 != i2c_master_recv(ir->c, data, 12)) { + rc = i2c_master_recv(ir->c, data, 12); + if (rc != 12) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -356,12 +380,16 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle, int parity_offset, int marker, int code_modulo) { + int rc; unsigned char b[4]; unsigned int start = 0,parity = 0,code = 0; /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, b, 4)) { + rc = i2c_master_recv(ir->c, b, 4); + if (rc != 4) { ir_dbg(ir, "read error\n"); + if (rc < 0) + return rc; return -EIO; } -- cgit From c3902dab05a2a256607764ac0b5688f29ac544c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:10:12 -0400 Subject: media: ir-kbd-i2c: improve error handling code The current I2C error handling logic makes static analyzers confused, and it doesn't follow the coding style we're using: drivers/media/i2c/ir-kbd-i2c.c:180 get_key_pixelview() error: uninitialized symbol 'b'. drivers/media/i2c/ir-kbd-i2c.c:224 get_key_knc1() error: uninitialized symbol 'b'. drivers/media/i2c/ir-kbd-i2c.c:226 get_key_knc1() error: uninitialized symbol 'b'. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 193020d64e51..1d11aab1817a 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -168,11 +168,15 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -185,11 +189,15 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char buf[4]; /* poll IR chip */ - if (4 != i2c_master_recv(ir->c, buf, 4)) { + rc = i2c_master_recv(ir->c, buf, 4); + if (rc != 4) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } @@ -209,11 +217,15 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { + int rc; unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc != 1) { dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; return -EIO; } -- cgit From 9863bc49abade85cad2ef6c1f535f61c2c24f163 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:13:06 -0400 Subject: media: ir-kbd-i2c: change the if logic to avoid a warning While the code is correct, it produces this warning: drivers/media/i2c/ir-kbd-i2c.c:593 zilog_ir_format() error: buffer overflow 'code_block->codes' 61 <= 173 As static analyzers may be tricked by arithmetic expressions on comparisions. So, change the order, in order to shut up this false-positive warning. That also makes easier for humans to understand that it won't be trying to go past buffer size. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 1d11aab1817a..a7e23bcf845c 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -583,7 +583,7 @@ static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf, /* first copy any leading non-repeating */ int leading = c - rep * 3; - if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) { + if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) { dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); return -EINVAL; } -- cgit From 70ae6a049fa9886f3d81bb35b7a806eef72351a2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:17:19 -0400 Subject: media: zoran: don't cast pointers to print them drivers/media/pci/zoran/zoran_driver.c:242 v4l_fbuffer_alloc() warn: argument 5 to %lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 8d4e7d930a66..14f9c0e26a1c 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -241,8 +241,8 @@ static int v4l_fbuffer_alloc(struct zoran_fh *fh) SetPageReserved(virt_to_page(mem + off)); dprintk(4, KERN_INFO - "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n", - ZR_DEVNAME(zr), __func__, i, (unsigned long) mem, + "%s: %s - V4L frame %d mem %p (bus: 0x%llx)\n", + ZR_DEVNAME(zr), __func__, i, mem, (unsigned long long)virt_to_bus(mem)); } -- cgit From 43e69758e6c0cc05adc4d39316f65abb120a00a0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:24:16 -0400 Subject: media: solo6x10: get rid of an address space warning Instead of using an ancillary function to avoid duplicating a small portion of code that copies data either to kernelspace or between userspace-kernelspace, duplicate the code, as it prevents static analyzers to complain about it: drivers/media/pci/solo6x10/solo6x10-g723.c:260:46: warning: cast removes address space of expression The hole idea of using __user is to make sure that the code is doing the right thing with address space, so there's no sense on use casting. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-g723.c | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 81be1b8df758..2ac33b5cc454 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) return idx * G723_FRAMES_PER_PAGE; } -static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, - unsigned long pos, void *dst, - unsigned long count, bool in_kernel) +static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, + unsigned long pos, void __user *dst, + unsigned long count) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo_dev *solo_dev = solo_pcm->solo_dev; @@ -242,10 +242,7 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, if (err) return err; - if (in_kernel) - memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); - else if (copy_to_user((void __user *)dst, - solo_pcm->g723_buf, G723_PERIOD_BYTES)) + if (copy_to_user(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES)) return -EFAULT; dst += G723_PERIOD_BYTES; } @@ -253,18 +250,30 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss, return 0; } -static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel, - unsigned long pos, void __user *dst, - unsigned long count) -{ - return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false); -} - static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel, unsigned long pos, void *dst, unsigned long count) { - return __snd_solo_pcm_copy(ss, pos, dst, count, true); + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + struct solo_dev *solo_dev = solo_pcm->solo_dev; + int err, i; + + for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { + int page = (pos / G723_FRAMES_PER_PAGE) + i; + + err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, + SOLO_G723_EXT_ADDR(solo_dev) + + (page * G723_PERIOD_BLOCK) + + (ss->number * G723_PERIOD_BYTES), + G723_PERIOD_BYTES, 0, 0); + if (err) + return err; + + memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES); + dst += G723_PERIOD_BYTES; + } + + return 0; } static const struct snd_pcm_ops snd_solo_pcm_ops = { -- cgit From 6062ba61567f8e08f1767ae6d1c3788247da81dc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:27:21 -0400 Subject: media: saa7134-alsa: don't use casts to print a buffer address Change the logic there to avoid casting, solving this warning: drivers/media/pci/saa7134/saa7134-alsa.c:276 saa7134_alsa_dma_init() warn: argument 3 to %08lx specifier is cast from pointer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-alsa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index c59b69f1af9d..72311445d13d 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -273,9 +273,8 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages) return -ENOMEM; } - pr_debug("vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vaddr, - nr_pages << PAGE_SHIFT); + pr_debug("vmalloc is at addr %p, size=%d\n", + dma->vaddr, nr_pages << PAGE_SHIFT); memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; -- cgit From 5c804c6bc55bcfb217c8001b3ca49cca0f9e7047 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:30:03 -0400 Subject: media: vivid-radio-rx: add a cast to avoid a warning The logic at vivid_radio_rx_g_tuner() is producint an overflow warning: drivers/media/platform/vivid/vivid-radio-rx.c:250 vivid_radio_rx_g_tuner() warn: potential negative subtraction from max '65535 - (__builtin_choose_expr( == || == , , __builtin_choose_expr( == || == , , __builtin_choose_expr( == || == , , __builtin_choose_expr( == || == , , __builtin_choose_expr( == || == , , __builtin_choose_expr( == , , (0))))))) * 65535) / delta' Add a cast to prevent that. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-radio-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c index acbfea2cce76..1f86d7d4f72f 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -247,7 +247,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) vt->rangehigh = FM_FREQ_RANGE_HIGH; sig_qual = dev->radio_rx_sig_qual; vt->signal = abs(sig_qual) > delta ? 0 : - 0xffff - (abs(sig_qual) * 0xffff) / delta; + 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta; vt->afc = sig_qual > delta ? 0 : sig_qual; if (abs(sig_qual) > delta) vt->rxsubchans = 0; -- cgit From 2be09d8d8342f775a9a6a9da6b91dded0a879718 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:31:59 -0400 Subject: media: zr364xx: avoid casting just to print pointer address Instead of casting, just use %p. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/zr364xx/zr364xx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 8b7c19943d46..b8886102c5ed 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -517,8 +517,7 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam, printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n"); return; } - DBG("%s: Buffer 0x%08lx size= %d\n", __func__, - (unsigned long)vbuf, pos); + DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos); /* tell v4l buffer was filled */ buf->vb.field_count = cam->frame_count * 2; @@ -1277,7 +1276,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) DBG("%s: cam == NULL\n", __func__); return -ENODEV; } - DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma); + DBG("mmap called, vma=%p\n", vma); ret = videobuf_mmap_mapper(&cam->vb_vidq, vma); -- cgit From 728d9fd9f148f03ec0bfa4891a44210a032d9663 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:33:22 -0400 Subject: media: em28xx-input: improve error handling code The current I2C error handling logic makes static analyzers confused: drivers/media/usb/em28xx/em28xx-input.c:96 em28xx_get_key_terratec() error: uninitialized symbol 'b'. Change it to match the coding style we're using elsewhere. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index eb2ec0384b69..2dc1be00b8b8 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -82,11 +82,16 @@ struct em28xx_IR { static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, enum rc_proto *protocol, u32 *scancode) { + int rc; unsigned char b; /* poll IR chip */ - if (i2c_master_recv(i2c_dev, &b, 1) != 1) + rc = i2c_master_recv(i2c_dev, &b, 1); + if (rc != 1) { + if (rc < 0) + return rc; return -EIO; + } /* * it seems that 0xFE indicates that a button is still hold -- cgit From e771bdf595ce7b297d9d50918300220f4981b5da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:42:32 -0400 Subject: media: tm6000: avoid casting just to print pointer address Instead of casting, just use %p. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tm6000/tm6000-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 8314d3fa9241..b2399d4266da 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1346,9 +1346,8 @@ static int __tm6000_open(struct file *file) fh->width = dev->width; fh->height = dev->height; - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&dev->vidq); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=%p, dev=%p, dev->vidq=%p\n", + fh, dev, &dev->vidq); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n", list_empty(&dev->vidq.queued)); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n", -- cgit From afdb4ca2be93d02cd1902395a7191097963dd8c1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:48:08 -0400 Subject: media: tda9840: cleanup a warning There's a false positive warning there: drivers/media/i2c/tda9840.c:79 tda9840_status() error: uninitialized symbol 'byte'. Change the code to match our coding style, in order to fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda9840.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index f31e659588ac..0dd6ff3e6201 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -68,11 +68,15 @@ static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val) static int tda9840_status(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); + int rc; u8 byte; - if (1 != i2c_master_recv(client, &byte, 1)) { + rc = i2c_master_recv(client, &byte, 1); + if (rc != 1) { v4l2_dbg(1, debug, sd, "i2c_master_recv() failed\n"); + if (rc < 0) + return rc; return -EIO; } -- cgit From 98c1ce0ccff1617cba45e8ead236768a50545e7f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 07:51:07 -0400 Subject: media: cec-core: fix a bug at cec_error_inj_write() If the adapter doesn't have error_inj_parse_line() ops, the write() logic won't return -EINVAL, but, instead, it will keep looping, because "count" is a non-negative number. Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index ea3eccfdba15..b0c87f9ea08f 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -209,14 +209,14 @@ static ssize_t cec_error_inj_write(struct file *file, if (IS_ERR(buf)) return PTR_ERR(buf); p = buf; - while (p && *p && count >= 0) { + while (p && *p) { p = skip_spaces(p); line = strsep(&p, "\n"); if (!*line || *line == '#') continue; if (!adap->ops->error_inj_parse_line(adap, line)) { - count = -EINVAL; - break; + kfree(buf); + return -EINVAL; } } kfree(buf); -- cgit From 86b2989361df6fd9bb3f46518b5326775c76358d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 08:23:23 -0400 Subject: media: uvc: to the right check at uvc_ioctl_enum_framesizes() While the logic there is correct, it tricks both humans and machines, a the check if "i" var is not zero is actually to validate if the "frames" var was initialized when the loop ran for the first time. That produces the following warning: drivers/media/usb/uvc/uvc_v4l2.c:1192 uvc_ioctl_enum_framesizes() error: potentially dereferencing uninitialized 'frame'. Change the logic to do the right test instead. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 818a4369a51a..bd32914259ae 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1173,7 +1173,7 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, struct uvc_fh *handle = fh; struct uvc_streaming *stream = handle->stream; struct uvc_format *format = NULL; - struct uvc_frame *frame; + struct uvc_frame *frame = NULL; unsigned int index; unsigned int i; @@ -1189,7 +1189,7 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, /* Skip duplicate frame sizes */ for (i = 0, index = 0; i < format->nframes; i++) { - if (i && frame->wWidth == format->frame[i].wWidth && + if (frame && frame->wWidth == format->frame[i].wWidth && frame->wHeight == format->frame[i].wHeight) continue; frame = &format->frame[i]; -- cgit From 0d2a531d00a36e378fce570cb96dbddee1f825f7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 08:43:47 -0400 Subject: media: dvb-usb-v2: fix a missing dependency of I2C_MUX Now that af9015 requires I2C_MUX, all drivers that select it should also depend on it. drivers/media/dvb-frontends/af9013.o: In function `af9013_remove': >> drivers/media/dvb-frontends/af9013.c:1560: undefined reference to `i2c_mux_del_adapters' drivers/media/dvb-frontends/af9013.o: In function `af9013_probe': >> drivers/media/dvb-frontends/af9013.c:1488: undefined reference to `i2c_mux_alloc' >> drivers/media/dvb-frontends/af9013.c:1495: undefined reference to `i2c_mux_add_adapter' drivers/media/dvb-frontends/af9013.c:1544: undefined reference to `i2c_mux_del_adapters' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 09a52aae299a..37053477b84d 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -15,7 +15,7 @@ config DVB_USB_V2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 + depends on DVB_USB_V2 && I2C_MUX select REGMAP select DVB_AF9013 select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT -- cgit From 6ccd228e0cfce2a4f44558422d25c60fcb1a6710 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Mar 2018 08:54:22 -0400 Subject: media: fimc-capture: get rid of two warnings Smatch produces two warnings when building this file: ./arch/x86/include/asm/bitops.h:433:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:433:22: warning: asm output is not an lvalue On some asm instructions. I suspect that those asm instructions might not be producing the right code, so, better to use two intermediate vars, get rid of the warnings and of the risk of producing a wrong code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index ed9302caa004..a3cdac188190 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -670,10 +670,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, return; } if (target == V4L2_SEL_TGT_COMPOSE) { + u32 tmp_min_h = ffs(sink->width) - 3; + u32 tmp_min_v = ffs(sink->height) - 1; + if (ctx->rotation != 90 && ctx->rotation != 270) align_h = 1; - max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); - max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); + max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h); + max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v); min_sz = var->min_out_pixsize; } else { u32 depth = fimc_get_format_depth(sink->fmt); -- cgit From f8a695c4b43d02c89b8bba9ba6058fd5db1bc71d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Mar 2018 05:59:25 -0400 Subject: media: v4l2-ioctl: rename a temp var that stores _IOC_SIZE(cmd) Instead of just calling it as "size", let's name it as "ioc_size", as it reflects better its contents. As this is constant along the function, also mark it as const. Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index a5dab16ff2d2..f48c505550e0 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2833,15 +2833,15 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, size_t array_size = 0; void __user *user_ptr = NULL; void **kernel_ptr = NULL; - size_t size = _IOC_SIZE(cmd); + const size_t ioc_size = _IOC_SIZE(cmd); /* Copy arguments into temp kernel buffer */ if (_IOC_DIR(cmd) != _IOC_NONE) { - if (size <= sizeof(sbuf)) { + if (ioc_size <= sizeof(sbuf)) { parg = sbuf; } else { /* too big to allocate from stack */ - mbuf = kvmalloc(size, GFP_KERNEL); + mbuf = kvmalloc(ioc_size, GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; @@ -2849,7 +2849,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned int n = size; + unsigned int n = ioc_size; /* * In some cases, only a few fields are used as input, @@ -2870,11 +2870,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, goto out; /* zero out anything we don't copy from userspace */ - if (n < size) - memset((u8 *)parg + n, 0, size - n); + if (n < ioc_size) + memset((u8 *)parg + n, 0, ioc_size - n); } else { /* read-only ioctl */ - memset(parg, 0, size); + memset(parg, 0, ioc_size); } } @@ -2932,7 +2932,7 @@ out_array_args: switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, size)) + if (copy_to_user((void __user *)arg, parg, ioc_size)) err = -EFAULT; break; } -- cgit