HDMI CEC framework
Subsystems (13)
v10 cover HDMI CEC framework
Hi all,
The tenth version of this patchset addresses comments I received from Russell King and various bug fixes and enhancements as the result of more testing.
The cec.txt has been updated, but before I can make the final version there are three areas that I want to look at more closely:
1) What to do if a cable is disconnected and reconnected for a source:
should the CEC adapter be disabled and re-enabled? Which means that you need to reconfigure. Or just update the physical address from the EDID (if necessary)? I think the latter, but I need to analyze this more closely.
2) I am not happy with the event mechanism. It's OK for messages, but for other events it is awkward.
3) The status field gives insufficient information and I want to reorganize that for the next version.
The cec-ctl and cec-compliance utilities used to test the CEC framework can be found here:
http://git.linuxtv.org/cgit.cgi/hverkuil/v4l-utils.git/log/?h=cec
Best regards,
Hans
Changes since v9
================
- Updated cec.txt
- Added a promiscuous capability to signal those adapters that can monitor all CEC traffic, not just directed and broadcast messages. I have one adapter that can do this. Added code in the framework to handle such messages correctly.
- The status field is now value and no longer a bitmask.
- Renamed the kernel config from CEC to MEDIA_CEC
- The adap_transmit() callback now has a retries argument.
- Use the new CEC_MAX_MSG_SIZE define instead of hardcoding it as 16
- Add support to wait for a reply after a broadcast message: this was forbidden, but it is a valid use-case.
- Make sure you can't send a message to yourself.
- Waiting for a transmit to succeed would never timeout (and couldn't be interrupted). Fixed.
- The message status was not updated correctly if it was CEC_MSG_FEATURE_ABORTed.
- Fixed a nasty kernel oops when deleting a cec adapter.
- Removed the owner check: the module owner is NULL if it is compiled into the kernel instead of as a module.
- Added separate register/unregister calls: this is safer and actually made it possible to drop the ugly 'cec_ready' v4l2_subdev op. Suggested by Russell, and that was a good idea.
- Added missing support for 32-bit to 64-bit ioctl conversion.
- Move the v4l2_subdev cec ops into a v4l2_subdev_cec_ops struct.
Changes since v8
================
- Addressed the comments Russell King made about how the cec character devices should be allocated/freed.
- Updated the DocBook documentation.
Changes since v7
================
- I thought that the core thread could handle out-of-order messages, but that turned out to be wrong. After careful analysis I realized that I had to rewrite this part in cec.c in order to make it work.
- Added new CEC-specific keys to input.h and use them in the CEC rc keymap. Replaced KEY_PLAY/PAUSE/STOP with KEY_PLAYCD/PAUSECD/STOPCD to clarify that these are media operations and not the Pause key on the keyboard.
- Added CEC_PHYS_ADDR_INVALID (0xffff)
- Added monitor support to monitor CEC traffic
- Replaced CAP_TRANSMIT and CAP_RECEIVE by a single CAP_IO.
- Replaced CAP_CDC by CAP_CDC_HPD since this only applies to the HPD part of the CDC messages.
- Add CAP_IS_SOURCE.
- Add ninputs field to cec_caps to export the number of inputs of the device.
- Drop CEC_LOG_ADDRS_FL_HANDLE_MSGS and the flags field (see next change for more info).
- Add CEC_CLAIM and CEC_RELEASE to explicitly start/stop processing CEC messages. This also implies ownership of the CEC interface, so other filehandles can only receive but not transmit.
- Reworked event handling: report adapter state changes, input changes and if the message receive queue is full.
- cec-funcs.h: added CDC HEC support.
- Renamed G/S_ADAP ioctls to ADAP_G/S: this made it clearer which ioctls deal with the adapter configuration and which deal with CEC messages/events.
- Clarified which CEC messages are passed on to userspace and which aren't. Specifically if CAP_ARC is set, then all ARC messages are handled by the kernel. If CAP_CDC_HPD is set, then all CDC hotplug messages are handled by the kernel. Otherwise these messages are passed on to userspace.
Changes since v6
================
- added cec-funcs.h to provide wrapper functions that fill in the cec_msg struct. This header is needed both by the kernel and by applications.
- fix a missing rc_unregister_device call.
- added CEC support for the adv7842 and cobalt drivers.
- added CEC operand defines. Rename CEC message defines to CEC_MSG_ and operand defines now use CEC_OP_.
- the CEC_VERSION defines are dropped since we now have the CEC_OP_VERSION defines.
- ditto: CEC_PRIM_DEVTYPE_ is now CEC_OP_PRIM_DEVTYPE.
- ditto: CEC_FL_ALL_DEVTYPE_ is now CEC_OP_ALL_DEVTYPE.
- cec-ioc-g-adap-log-addrs.xml: document cec_versions field.
- cec-ioc-g-caps.xml: drop vendor_id and version fields.
- add MAINTAINERS entry.
- add CDC support (not yet fully functional).
- add a second debug level for message debugging.
- fix a nasty kernel Oops in cec_transmit_msg while waiting for transmit completion (adap->tx_queue[idx].func wasn't set to NULL).
- add support for CEC_MSG_REPORT_FEATURES (CEC 2.0 only).
- correctly abort unsupported messages.
- add support for the device power status feature.
- add support for the audio return channel (preliminary).
- add support for the CDC hotplug message (preliminary).
- added osd_name to struct cec_log_addrs.
- reported physical addresses are stored internally.
- fix enabling/disabling the CEC adapter (internal fields weren't cleared correctly).
- zero reserved fields.
- return an error if you try to receive/transmit and the adapter isn't configured.
- when creating the adapter provide the owner module and the parent device.
- add a CEC_VENDOR_ID_NONE define to signal if no vendor ID was set.
- add new capabilities: RC (remote control), ARC (audio return channel) and CDC (Capability Discovery and Control).
- applications that want to handle messages for a logical address need to set the CEC_LOG_ADDRS_FL_HANDLE_MSGS flag. Otherwise the CEC core will be the one handling all messages.
- Each logical address has its own all_device_types value. So this should be an array, not a single value.
- I'm sure I've forgotten some changes...
Changes since v5
================
- drop struct cec_timeval in favour of a __u64 that keeps the timestamp in ns
- remove userspace documentation from Documentation/cec.txt as userspace API is described in the DocBook
- add missing documentation for the passthrough mode to the DocBook
- add information about the number of events that can be queued
- fix misspelling of reply
- fix behaviour of posting an event in cec_received_msg, such that the behaviour is consistent with the documentation
Changes since v4
================
- add sequence numbering to transmitted messages
- add sequence number handling to event hanlding
- add passthrough mode
- change reserved field sizes
- fixed CEC version defines and addec CEC 2.0 commands
- add DocBook documentation
Changes since v3
================
- remove the promiscuous mode
- rewrite the devicetree patches
- fixes, expansion and partial rewrite of the documentation
- reorder of API structures and addition of reserved fields
- use own struct to report time (32/64 bit safe)
- fix of handling events
- add cec.h to include/uapi/linux/Kbuild
- fixes in the adv76xx driver (add missing methods, change adv7604 to adv76xx)
- cleanup of debug messages in s5p-cec driver
- remove non necessary claiming of a gpio in the s5p-cec driver
- cleanup headers of the s5p-cec driver
Changes since v2
===============-
- added promiscuous mode
- added new key codes to the input framework
- add vendor ID reporting
- add the possibility to clear assigned logical addresses
- cleanup of the rc cec map
Changes since v1
================
- documentation edited and moved to the Documentation folder
- added key up/down message handling
- add missing CEC commands to the cec.h file
Background
==========
The work on a common CEC framework was started over three years ago by Hans Verkuil. Unfortunately the work has stalled. As I have received the task of creating a driver for the CEC interface module present on the Exynos range of SoCs, I got in touch with Hans. He replied that the work stalled due to his lack of time.
Original RFC by Hans Verkuil/Martin Bugge
=========================================
https://www.mail-archive.com/[email protected]/msg28735.html
Hans Verkuil (10):
input.h: add BUS_CEC type
cec: add HDMI CEC framework
cec: add compat32 ioctl support
cec.txt: add CEC framework documentation
DocBook/media: add CEC documentation
v4l2-subdev: add HDMI CEC ops
cec: adv7604: add cec support.
cec: adv7842: add cec support
cec: adv7511: add cec support.
cobalt: add cec support
Kamil Debski (6):
dts: exynos4*: add HDMI CEC pin definition to pinctrl
dts: exynos4: add node for the HDMI CEC device
dts: exynos4412-odroid*: enable the HDMI CEC device
HID: add HDMI CEC specific keycodes
rc: Add HDMI CEC protocol handling
cec: s5p-cec: Add s5p-cec driver
Documentation/DocBook/device-drivers.tmpl | 3 + Documentation/DocBook/media/Makefile | 2 + Documentation/DocBook/media/v4l/biblio.xml | 10 + Documentation/DocBook/media/v4l/cec-api.xml | 76 + Documentation/DocBook/media/v4l/cec-func-close.xml | 59 + Documentation/DocBook/media/v4l/cec-func-ioctl.xml | 73 + Documentation/DocBook/media/v4l/cec-func-open.xml | 94 + Documentation/DocBook/media/v4l/cec-func-poll.xml | 89 + .../DocBook/media/v4l/cec-ioc-adap-g-caps.xml | 167 ++ .../DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml | 306 +++ .../DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml | 80 + .../DocBook/media/v4l/cec-ioc-adap-g-state.xml | 87 + .../DocBook/media/v4l/cec-ioc-adap-g-vendor-id.xml | 70 + Documentation/DocBook/media/v4l/cec-ioc-claim.xml | 71 + .../DocBook/media/v4l/cec-ioc-dqevent.xml | 208 +++ .../DocBook/media/v4l/cec-ioc-g-monitor.xml | 86 + .../DocBook/media/v4l/cec-ioc-g-passthrough.xml | 81 + .../DocBook/media/v4l/cec-ioc-receive.xml | 190 ++ Documentation/DocBook/media_api.tmpl | 6 +- Documentation/cec.txt | 326 ++++ .../devicetree/bindings/media/s5p-cec.txt | 31 + MAINTAINERS | 12 + arch/arm/boot/dts/exynos4.dtsi | 12 + arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 7 + arch/arm/boot/dts/exynos4210-universal_c210.dts | 4 + arch/arm/boot/dts/exynos4x12-pinctrl.dtsi | 7 + drivers/media/Kconfig | 7 + drivers/media/Makefile | 2 + drivers/media/cec.c | 1962 ++++++++++++++++++++ drivers/media/i2c/adv7511.c | 364 +++- drivers/media/i2c/adv7604.c | 241 ++- drivers/media/i2c/adv7842.c | 255 ++- drivers/media/pci/cobalt/Kconfig | 1 + drivers/media/pci/cobalt/cobalt-driver.c | 108 +- drivers/media/pci/cobalt/cobalt-driver.h | 2 + drivers/media/pci/cobalt/cobalt-irq.c | 3 + drivers/media/pci/cobalt/cobalt-v4l2.c | 126 +- drivers/media/pci/cobalt/cobalt-v4l2.h | 2 + drivers/media/platform/Kconfig | 12 + drivers/media/platform/Makefile | 1 + drivers/media/platform/s5p-cec/Makefile | 2 + drivers/media/platform/s5p-cec/exynos_hdmi_cec.h | 37 + .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c | 208 +++ drivers/media/platform/s5p-cec/regs-cec.h | 96 + drivers/media/platform/s5p-cec/s5p_cec.c | 289 +++ drivers/media/platform/s5p-cec/s5p_cec.h | 76 + drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-cec.c | 174 ++ drivers/media/rc/rc-main.c | 1 + fs/compat_ioctl.c | 19 + include/media/adv7511.h | 6 +- include/media/cec.h | 182 ++ include/media/rc-core.h | 1 + include/media/rc-map.h | 5 +- include/media/v4l2-subdev.h | 14 + include/uapi/linux/Kbuild | 2 + include/uapi/linux/cec-funcs.h | 1771 ++++++++++++++++++ include/uapi/linux/cec.h | 884 +++++++++ include/uapi/linux/input.h | 29 + 59 files changed, 8979 insertions(+), 61 deletions(-) create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-state.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-vendor-id.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-claim.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-monitor.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml create mode 100644 Documentation/cec.txt create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt create mode 100644 drivers/media/cec.c create mode 100644 drivers/media/platform/s5p-cec/Makefile create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h create mode 100644 drivers/media/rc/keymaps/rc-cec.c create mode 100644 include/media/cec.h create mode 100644 include/uapi/linux/cec-funcs.h create mode 100644 include/uapi/linux/cec.h
Signature · 1 line
2.6.2
PATCH v10 1/16 dts: exynos4*: add HDMI CEC pin definition to pinctrl
From: Kamil Debski <[email protected]>
Add pinctrl nodes for the HDMI CEC device to the Exynos4210 and Exynos4x12 SoCs. These are required by the HDMI CEC device.
--- arch/arm/boot/dts/exynos4210-pinctrl.dtsi | 7 +++++++ arch/arm/boot/dts/exynos4x12-pinctrl.dtsi | 7 +++++++ 2 files changed, 14 insertions(+)
arch/arm/boot/dts/exynos4210-pinctrl.dtsi +7 -0
@@ -820,6 +820,13 @@ samsung,pin-pud = <1>; samsung,pin-drv = <0>; }; + + hdmi_cec: hdmi-cec { + samsung,pins = "gpx3-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; pinctrl@03860000 {
arch/arm/boot/dts/exynos4x12-pinctrl.dtsi +7 -0
@@ -885,6 +885,13 @@ samsung,pin-pud = <0>; samsung,pin-drv = <0>; }; + + hdmi_cec: hdmi-cec { + samsung,pins = "gpx3-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; pinctrl_2: pinctrl@03860000 {
Signature · 1 line
2.6.2
PATCH v10 2/16 dts: exynos4: add node for the HDMI CEC device
In reply to Hans VerkuilFrom: Kamil Debski <[email protected]>
This patch adds HDMI CEC node specific to the Exynos4210/4x12 SoC series.
--- arch/arm/boot/dts/exynos4.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/arm/boot/dts/exynos4.dtsi +12 -0
@@ -720,6 +720,18 @@ status = "disabled"; }; + hdmicec: cec@100B0000 { + compatible = "samsung,s5p-cec"; + reg = <0x100B0000 0x200>; + interrupts = <0 114 0>; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "disabled"; + }; + mixer: mixer@12C10000 { compatible = "samsung,exynos4210-mixer"; interrupts = <0 91 0>;
Signature · 1 line
2.6.2
PATCH v10 3/16 dts: exynos4412-odroid*: enable the HDMI CEC device
In reply to Hans VerkuilFrom: Kamil Debski <[email protected]>
Add a dts node entry and enable the HDMI CEC device present in the Exynos4 family of SoCs.
--- arch/arm/boot/dts/exynos4210-universal_c210.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm/boot/dts/exynos4210-universal_c210.dts +4 -0
@@ -222,6 +222,10 @@ enable-active-high; }; + cec@100B0000 { + status = "okay"; + }; + hdmi_ddc: i2c-ddc { compatible = "i2c-gpio"; gpios = <&gpe4 2 0 &gpe4 3 0>;
Signature · 1 line
2.6.2
PATCH v10 4/16 input.h: add BUS_CEC type
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Inputs can come in over the HDMI CEC bus, so add a new type for this.
--- include/uapi/linux/input.h | 1 + 1 file changed, 1 insertion(+)
include/uapi/linux/input.h +1 -0
@@ -972,6 +972,7 @@ struct input_keymap_entry {#define BUS_GSC 0x1A#define BUS_ATARI 0x1B#define BUS_SPI 0x1C +#define BUS_CEC 0x1D/* * MT_TOOL types
Signature · 1 line
2.6.2
PATCH v10 5/16 HID: add HDMI CEC specific keycodes
In reply to Hans VerkuilFrom: Kamil Debski <[email protected]>
Add HDMI CEC specific keycodes to the keycodes definition.
--- include/uapi/linux/input.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
include/uapi/linux/input.h +28 -0
@@ -752,6 +752,34 @@ struct input_keymap_entry {#define KEY_KBDINPUTASSIST_ACCEPT 0x264#define KEY_KBDINPUTASSIST_CANCEL 0x265 +#define KEY_RIGHT_UP 0x266 +#define KEY_RIGHT_DOWN 0x267 +#define KEY_LEFT_UP 0x268 +#define KEY_LEFT_DOWN 0x269 +#define KEY_ROOT_MENU 0x26a/* Show Device's Root Menu */ +#define KEY_MEDIA_TOP_MENU 0x26b/* Show Top Menu of the Media (e.g. DVD) */ +#define KEY_NUMERIC_11 0x26c +#define KEY_NUMERIC_12 0x26d +/* +* Toggle Audio Description: refers to an audio service that helps blind and +* visually impaired consumers understand the action in a program. Note: in +* some countries this is referred to as "Video Description". +*/ +#define KEY_AUDIO_DESC 0x26e +#define KEY_3D_MODE 0x26f +#define KEY_NEXT_FAVORITE 0x270 +#define KEY_STOP_RECORD 0x271 +#define KEY_PAUSE_RECORD 0x272 +#define KEY_VOD 0x273/* Video on Demand */ +#define KEY_UNMUTE 0x274 +#define KEY_FASTREVERSE 0x275 +#define KEY_SLOWREVERSE 0x276 +/* +* Control a data application associated with the currently viewed channel, +* e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) +*/ +#define KEY_DATA 0x275 +#define BTN_TRIGGER_HAPPY 0x2c0#define BTN_TRIGGER_HAPPY1 0x2c0#define BTN_TRIGGER_HAPPY2 0x2c1
Signature · 1 line
2.6.2
PATCH v10 6/16 rc: Add HDMI CEC protocol handling
In reply to Hans VerkuilFrom: Kamil Debski <[email protected]>
Add handling of remote control events coming from the HDMI CEC bus. This patch includes a new keymap that maps values found in the CEC messages to the keys pressed and released. Also, a new protocol has been added to the core.
--- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-cec.c | 174 ++++++++++++++++++++++++++++++++++++++ drivers/media/rc/rc-main.c | 1 + include/media/rc-core.h | 1 + include/media/rc-map.h | 5 +- 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 drivers/media/rc/keymaps/rc-cec.c
drivers/media/rc/keymaps/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-behold.o \ rc-behold-columbus.o \ rc-budget-ci-old.o \ + rc-cec.o \ rc-cinergy-1400.o \ rc-cinergy.o \ rc-delock-61959.o \
drivers/media/rc/keymaps/rc-cec.c new file +174 -0
174 lines not on this page · raw message
drivers/media/rc/rc-main.c +1 -0
@@ -801,6 +801,7 @@ static struct { { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, { RC_BIT_XMP, "xmp" }, + { RC_BIT_CEC, "cec" }, };/**
include/media/rc-core.h +1 -0
@@ -32,6 +32,7 @@ do { \enum rc_driver_type {RC_DRIVER_SCANCODE =0 ,/* Driver or hardware generates a scancode */ RC_DRIVER_IR_RAW ,/* Needs a Infra-Red pulse/space decoder */ +RC_DRIVER_CEC , };/**
include/media/rc-map.h +4 -1
@@ -31,6 +31,7 @@ enum rc_type {RC_TYPE_RC6_MCE =16 ,/* MCE (Philips RC6-6A-32 subtype) protocol */ RC_TYPE_SHARP =17 ,/* Sharp protocol */ RC_TYPE_XMP =18 ,/* XMP protocol */ + RC_TYPE_CEC = 19, /* CEC protocol */ };#define RC_BIT_NONE 0
@@ -53,6 +54,7 @@ enum rc_type {#define RC_BIT_RC6_MCE (1 << RC_TYPE_RC6_MCE)#define RC_BIT_SHARP (1 << RC_TYPE_SHARP)#define RC_BIT_XMP (1 << RC_TYPE_XMP) +#define RC_BIT_CEC (1 << RC_TYPE_CEC)#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
@@ -61,7 +63,7 @@ enum rc_type { RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \ RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \ RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \ - RC_BIT_XMP) + RC_BIT_XMP | RC_BIT_CEC)#define RC_SCANCODE_UNKNOWN (x) (x)
@@ -123,6 +125,7 @@ void rc_map_init(void);#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus"#define RC_MAP_BEHOLD "rc-behold"#define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" +#define RC_MAP_CEC "rc-cec"#define RC_MAP_CINERGY_1400 "rc-cinergy-1400"#define RC_MAP_CINERGY "rc-cinergy"#define RC_MAP_DELOCK_61959 "rc-delock-61959"
Signature · 1 line
2.6.2
PATCH v10 7/16 cec: add HDMI CEC framework
In reply to Hans VerkuilThe added HDMI CEC framework provides a generic kernel interface for HDMI CEC devices.
[[email protected]: change kthread handling when setting logical address]
[[email protected]: code cleanup and fixes] [[email protected]: add missing CEC commands to match spec] [[email protected]: add RC framework support] [[email protected]: move and edit documentation] [[email protected]: add vendor id reporting] [[email protected]: add possibility to clear assigned logical addresses]
[[email protected]: documentation fixes, clenaup and expansion] [[email protected]: reorder of API structs and add reserved fields] [[email protected]: fix handling of events and fix 32/64bit timespec problem]
[[email protected]: add cec.h to include/uapi/linux/Kbuild] [[email protected]: add sequence number handling] [[email protected]: add passthrough mode] [[email protected]: fix CEC defines, add missing CEC 2.0 commands] minor additions]
--- MAINTAINERS | 12 + drivers/media/Kconfig | 7 + drivers/media/Makefile | 2 + drivers/media/cec.c | 1962 ++++++++++++++++++++++++++++++++++++++++ include/media/cec.h | 182 ++++ include/uapi/linux/Kbuild | 2 + include/uapi/linux/cec-funcs.h | 1771 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/cec.h | 884 ++++++++++++++++++ 8 files changed, 4822 insertions(+) create mode 100644 drivers/media/cec.c create mode 100644 include/media/cec.h create mode 100644 include/uapi/linux/cec-funcs.h create mode 100644 include/uapi/linux/cec.h
MAINTAINERS +12 -0
@@ -2599,6 +2599,18 @@ F: drivers/net/ieee802154/cc2520.c F: include/linux/spi/cc2520.h F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt +CEC DRIVER +M: Hans Verkuil <[email protected]> +L: [email protected] +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Supported +F: drivers/media/cec.c +F: drivers/media/rc/keymaps/rc-cec.c +F: include/media/cec.h +F: include/uapi/linux/cec.h +F: include/uapi/linux/cec-funcs.h + CELL BROADBAND ENGINE ARCHITECTURE M: Arnd Bergmann <[email protected]> L: [email protected]
drivers/media/Kconfig +7 -0
@@ -80,6 +80,13 @@ config MEDIA_RC_SUPPORT Say Y when you have a TV or an IR device. +config MEDIA_CEC + tristate "CEC API (EXPERIMENTAL)" + depends on MEDIA_RC_SUPPORT + select RC_CORE + ---help--- + Enable the CEC API. + # # Media controller # Selectable only for webcam/grabbers, as other drivers don't use it
drivers/media/Makefile +2 -0
@@ -2,6 +2,8 @@ # Makefile for the kernel multimedia device drivers. # +obj-$(CONFIG_MEDIA_CEC) += cec.o + media-objs := media-device.o media-devnode.o media-entity.o #
drivers/media/cec.c new file +1962 -0
1,962 lines not on this page · raw message
include/media/cec.h new file +182 -0
182 lines not on this page · raw message
include/uapi/linux/Kbuild +2 -0
@@ -81,6 +81,8 @@ header-y += capi.h header-y += cciss_defs.h header-y += cciss_ioctl.h header-y += cdrom.h +header-y += cec.h +header-y += cec-funcs.h header-y += cgroupstats.h header-y += chio.h header-y += cm4000_cs.h
include/uapi/linux/cec-funcs.h new file +1771 -0
809 lines not on this page · raw message
include/uapi/linux/cec.h new file +884 -0
884 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.6.2
Part of the diff is not shown here. View the raw message.
PATCH v10 8/16 cec: add compat32 ioctl support
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
The CEC ioctls didn't have compat32 support, so they returned -ENOTTY when used in a 32 bit application on a 64 bit kernel.
Since all the CEC ioctls are 32-bit compatible adding support for this API is trivial.
--- fs/compat_ioctl.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
fs/compat_ioctl.c +19 -0
@@ -57,6 +57,7 @@#include <linux/i2c-dev.h> #include <linux/atalk.h> #include <linux/gfp.h> +#include <linux/cec.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_sock.h>
@@ -1381,6 +1382,24 @@ COMPATIBLE_IOCTL(VIDEO_GET_NAVI) COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES) COMPATIBLE_IOCTL(VIDEO_GET_SIZE) COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE) +/* cec */ +COMPATIBLE_IOCTL(CEC_ADAP_G_CAPS) +COMPATIBLE_IOCTL(CEC_ADAP_G_LOG_ADDRS) +COMPATIBLE_IOCTL(CEC_ADAP_S_LOG_ADDRS) +COMPATIBLE_IOCTL(CEC_ADAP_G_STATE) +COMPATIBLE_IOCTL(CEC_ADAP_S_STATE) +COMPATIBLE_IOCTL(CEC_ADAP_G_PHYS_ADDR) +COMPATIBLE_IOCTL(CEC_ADAP_S_PHYS_ADDR) +COMPATIBLE_IOCTL(CEC_ADAP_G_VENDOR_ID) +COMPATIBLE_IOCTL(CEC_ADAP_S_VENDOR_ID) +COMPATIBLE_IOCTL(CEC_G_MONITOR) +COMPATIBLE_IOCTL(CEC_S_MONITOR) +COMPATIBLE_IOCTL(CEC_CLAIM) +COMPATIBLE_IOCTL(CEC_RELEASE) +COMPATIBLE_IOCTL(CEC_G_PASSTHROUGH) +COMPATIBLE_IOCTL(CEC_TRANSMIT) +COMPATIBLE_IOCTL(CEC_RECEIVE) +COMPATIBLE_IOCTL(CEC_DQEVENT) /* joystick */ COMPATIBLE_IOCTL(JSIOCGVERSION)
Signature · 1 line
2.6.2
PATCH v10 9/16 cec.txt: add CEC framework documentation
In reply to Hans VerkuilDocument the new HDMI CEC framework.
[[email protected]: add DocBook documentation by Hans Verkuil, with
--- Documentation/cec.txt | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 Documentation/cec.txt
Documentation/cec.txt new file +326 -0
@@ -0,0 +1,326 @@ +CEC Kernel Support +================== + +The CEC framework provides a unified kernel interface for use with HDMI CEC +hardware. It is designed to handle a multiple types of hardware (receivers, +transmitters, USB dongles). The framework also gives the option to decide +what to do in the kernel driver and what should be handled by userspace +applications. In addition it integrates the remote control passthrough +feature into the kernel's remote control framework. + + +The CEC Protocol +---------------- + +The CEC protocol enables consumer electronic devices to communicate with each +other through the HDMI connection. The protocol uses logical addresses in the +communication. The logical address is strictly connected with the functionality +provided by the device. The TV acting as the communication hub is always +assigned address 0. The physical address is determined by the physical +connection between devices. + +The CEC framework described here is up to date with the CEC 2.0 specification. +It is documented in the HDMI 1.4 specification with the new 2.0 bits documented +in the HDMI 2.0 specification. But for most of the features the freely available +HDMI 1.3a specification is sufficient: + +http://www.microprocessor.org/HDMISpecification13a.pdf + + +The Kernel Interface +==================== + +CEC Adapter +----------- + +The struct cec_adapter represents the CEC adapter hardware. It is created by +calling cec_create_adapter() and deleted by calling cec_delete_adapter(): + +struct cec_adapter *cec_create_adapter(const struct cec_adap_ops *ops, + void *priv, const char *name, u32 caps, + u8 ninputs, struct module *owner, struct device *parent); +void cec_delete_adapter(struct cec_adapter *adap); + +To create an adapter you need to pass the following information: + +ops: adapter operations which are called by the CEC framework and that you +have to implement. + +priv: will be stored in adap->priv and can be used by the adapter ops. + +name: the name of the CEC adapter + +caps: capabilities of the CEC adapter. These capabilities determine the + capabilities of the hardware and which parts are to be handled + by userspace and which parts are handled by kernelspace. The + capabilities are returned by CEC_ADAP_G_CAPS. + +ninputs: the number of HDMI inputs of the device. This may be 0. This + is returned by CEC_ADAP_G_CAPS. + +owner: the module owner. + +parent: the parent device. + + +After creating the adapter the driver can modify the following fields +in struct cec_adapter: + + u8 available_log_addrs; + +This determines the number of simultaneous logical addresses the hardware +can program. Often this is 1, which is also the default. + + u8 pwr_state; + +The CEC_MSG_GIVE_DEVICE_POWER_STATUS power state. By default this is +CEC_OP_POWER_STATUS_ON (0). The driver can change this to signal power +state transitions. + + u16 phys_addr; + +By default this is 0xffff, but drivers can change this. The phys_addr field +must be set before the CEC adapter is enabled (see the adap_enable op below). +While the CEC adapter remains enabled it cannot be changed. Drivers never set +this if CEC_CAP_PHYS_ADDR is set. + + u32 vendor_id; + +By default this is CEC_VENDOR_ID_NONE (0xffffffff). It should not be changed +once the adapter is configured. Drivers never set this if CEC_CAP_VENDOR_ID +is set. + + u8 cec_version; + +The CEC version that the framework should support. By default this is the +latest version, but it can be changed to an older version, causing attempts +to use later extensions to fail. Obviously this should be set before the +CEC adapter is enabled. + +To register the /dev/cecX device node and the remote control device (if +CEC_CAP_RC is set) you call: + +int cec_register_adapter(struct cec_adapter *adap); + +To unregister the devices call: + +void cec_unregister_adapter(struct cec_adapter *adap); + + +Implementing the Low-Level CEC Adapter +-------------------------------------- + +The following low-level adapter operations have to be implemented in +your driver: + +struct cec_adap_ops { + /* Low-level callbacks */ + int (*adap_enable)(struct cec_adapter *adap, bool enable); + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); + int (*adap_transmit)(struct cec_adapter *adap, u32 timeout_ms, struct cec_msg *msg); + + /* High-level callbacks */ + ... +}; + +The three low-level ops deal with various aspects of controlling the CEC adapter +hardware: + +To enable/disable the hardware: + + int (*adap_enable)(struct cec_adapter *adap, bool enable); + +This callback enables or disables the CEC hardware. Enabling the CEC hardware +means powering it up in a state where no logical addresses are claimed. This +op assumes that the physical address (adap->phys_addr) is valid when enable is +true and will not change while the CEC adapter remains enabled. The initial +state of the CEC adapter after calling cec_create_adapter() is disabled. + +To program a new logical address: + + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); + +If logical_addr == CEC_LOG_ADDR_INVALID then all programmed logical addresses +are to be erased. Otherwise the given logical address should be programmed. +If the maximum number of available logical addresses is exceeded, then it +should return -ENXIO. Once a logical address is programmed the CEC hardware +can start receiving messages. + +To transmit a new message: + + int (*adap_transmit)(struct cec_adapter *adap, u32 timeout_ms, + u8 retries, struct cec_msg *msg); + +This transmits a new message. The timeout_ms argument is the suggested timeout +in milliseconds to use in the hardware (200 ms for a poll message, 1000 ms for +other messages). The retries argument is the suggested number of retries for +the transmit. The low level implementation is responsible for repeating the +transmit in case of a failure. This is typically something that the hardware +will do for you. The recommended number of retry attempts are 1 for a poll +message and 3 for other messages. + +Your adapter driver will also have to react to events (typically interrupt +driven) by calling into the framework in the following situations: + +When a transmit finished (successfully or otherwise): + +void cec_transmit_done(struct cec_adapter *adap, u32 status); + +The status can be one of: + +CEC_TX_STATUS_OK: the transmit was successful. +CEC_TX_STATUS_ARB_LOST: arbitration was lost: another CEC initiator +unexpectedly takes control of the CEC line and you lost the arbitration. +#define CEC_TX_STATUS_RETRY_TIMEOUT: could not transmit the message after +trying multiple times. + +Never return CEC_TX_STATUS_FEATURE_ABORT or CEC_TX_STATUS_REPLY_TIMEOUT: +these are high-level statuses that are returned by the CEC framework and +not by a CEC adapter driver. + +When a CEC message was received: + +void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg); + +Speaks for itself. + +When the number connected inputs changes: + +void cec_connected_inputs(struct cec_adapter *adap, u16 connected_inputs); + +The connected_inputs argument is a bit mask where bit 0 refers to HDMI input 0, +etc. Only the first ninputs (see CEC_ADAP_G_CAPS) bits can be 1, the remainder +are always 0. This function should be called when the HDMI receiver driver +detects when a new device is connected or disconnected from a given input. + +The CEC framework will pass this information on to the user. + +Implementing the High-Level CEC Adapter +--------------------------------------- + +The low-level operations drive the hardware, the high-level operations are +CEC protocol driven. The following high-level callbacks are available: + +struct cec_adap_ops { + /* Low-level callbacks */ + ... + + /* High-level CEC message callback */ + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); + + /* High-level CDC Hotplug Detect callbacks */ + u8 (*source_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state); + void (*sink_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state, u8 cdc_hpd_error); + + /* High-level Audio Return Channel callbacks */ + int (*sink_initiate_arc)(struct cec_adapter *adap); + int (*sink_terminate_arc)(struct cec_adapter *adap); + int (*source_arc_initiated)(struct cec_adapter *adap); + int (*source_arc_terminated)(struct cec_adapter *adap); +}; + +The received() callback allows the driver to optionally handle a newly +received CEC message + + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); + +If the driver wants to process a CEC message, then it can implement this +callback. If it doesn't want to handle this message, then it should return +-ENOMSG, otherwise the CEC framework assumes it processed this message and +it will not no anything with it. + +The other callbacks deal with two CEC features: CDC Hotplug Detect and +Audio Return Channel. Here the framework takes care of handling these +messages and it calls the callbacks to notify the driver when it needs +to take action. + +CDC Hotplug Support +------------------- + +A source received a hotplug state change message: + + u8 (*source_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state); + +A source received a CEC_MSG_CDC_HPD_SET_STATE message. The framework will +reply with a CEC_MSG_CDC_HPD_REPORT_STATE message and this callback is used +to fill in the HPD Error Code Operand of the REPORT_STATE message. In addition, +the driver can act in this callback on the hotplug state change. + +Only implement if CEC_CAP_CDC_HPD is set. + +A sink received a hotplug report state message: + + void (*sink_cdc_hpd)(struct cec_adapter *adap, u8 cdc_hpd_state, u8 cdc_hpd_error); + +A sink received a CEC_MSG_CDC_HPD_REPORT_STATE message. This callback will +do anything necessary to implement this hotplug change. The two arguments +are the HPD Error State and HPD Error Code Operands from the CEC_MSG_CDC_HPD_REPORT_STATE +message. + + +Audio Return Channel Support +---------------------------- + +Called if a CEC_MSG_INITIATE_ARC message is received by an HDMI sink. +This callback should start sending audio over the audio return channel. If +successful it should return 0. + + int (*sink_initiate_arc)(struct cec_adapter *adap); + +Called if a CEC_MSG_TERMINATE_ARC message is received by an HDMI sink. +This callback should stop sending audio over the audio return channel. If +successful it should return 0. + + void (*sink_terminate_arc)(struct cec_adapter *adap); + +Called if a CEC_MSG_REPORT_ARC_INITIATED message is received by an +HDMI source. This callback can be used to enable receiving audio from +the audio return channel. + + void (*source_arc_initiated)(struct cec_adapter *adap); + +Called if a CEC_MSG_REPORT_ARC_TERMINATED message is received by an +HDMI source. This callback can be used to disable receiving audio from +the audio return channel. + + void (*source_arc_terminated)(struct cec_adapter *adap); + + +CEC framework functions +----------------------- + +CEC Adapter drivers can call the following CEC framework functions: + +int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, + bool block); + +Transmit a CEC message. If block is true, then wait until the message has been +transmitted, otherwise just queue it and return. + +int cec_claim_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs *log_addrs, bool block); + +Claim the CEC logical addresses. Should never be called if CEC_CAP_LOG_ADDRS +is set. If block is true, then wait until the logical addresses have been +claimed, otherwise just queue it and return. + +int cec_enable(struct cec_adapter *adap, bool enable); + +Enable or disable the CEC adapter. HDMI transmitters will typically disable +the adapter when the hotplug signal goes down and enable it after it went up +again and the EDID was read containing the new physical address. Should never +be called if CEC_CAP_STATE is set. + +u8 cec_sink_cdc_hpd(struct cec_adapter *adap, u8 input_port, u8 cdc_hpd_state); + +If an HDMI receiver supports hotplug signalling over CDC (CEC_CAP_CDC_HPD is +set), then the driver should call this function whenever the hotplug state +changes for an input. This call will send an appropriate CDC message over +the CEC line. It returns CEC_OP_HPD_ERROR_NONE on success, if the adapter +is unconfigured it returns CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE and if +the cec_transmit fails it returns CEC_OP_HPD_ERROR_OTHER. + +void cec_log_status(struct cec_adapter *adap); + +This logs the current CEC adapter status in the kernel log. Useful for +debugging and implementing the V4L2 VIDIOC_LOG_STATUS ioctl.
Signature · 1 line
2.6.2
PATCH v10 10/16 DocBook/media: add CEC documentation
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add DocBook documentation for the CEC API.
--- Documentation/DocBook/device-drivers.tmpl | 3 + Documentation/DocBook/media/Makefile | 2 + Documentation/DocBook/media/v4l/biblio.xml | 10 + Documentation/DocBook/media/v4l/cec-api.xml | 76 +++++ Documentation/DocBook/media/v4l/cec-func-close.xml | 59 ++++ Documentation/DocBook/media/v4l/cec-func-ioctl.xml | 73 +++++ Documentation/DocBook/media/v4l/cec-func-open.xml | 94 +++++++ Documentation/DocBook/media/v4l/cec-func-poll.xml | 89 ++++++ .../DocBook/media/v4l/cec-ioc-adap-g-caps.xml | 167 +++++++++++ .../DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml | 306 +++++++++++++++++++++ .../DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml | 80 ++++++ .../DocBook/media/v4l/cec-ioc-adap-g-state.xml | 87 ++++++ .../DocBook/media/v4l/cec-ioc-adap-g-vendor-id.xml | 70 +++++ Documentation/DocBook/media/v4l/cec-ioc-claim.xml | 71 +++++ .../DocBook/media/v4l/cec-ioc-dqevent.xml | 208 ++++++++++++++ .../DocBook/media/v4l/cec-ioc-g-monitor.xml | 86 ++++++ .../DocBook/media/v4l/cec-ioc-g-passthrough.xml | 81 ++++++ .../DocBook/media/v4l/cec-ioc-receive.xml | 190 +++++++++++++ Documentation/DocBook/media_api.tmpl | 6 +- 19 files changed, 1757 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-state.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-adap-g-vendor-id.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-claim.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-monitor.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml
Documentation/DocBook/device-drivers.tmpl +3 -0
@@ -319,6 +319,9 @@ X!Isound/sound_firmware.c !Iinclude/media/media-devnode.h !Iinclude/media/media-entity.h </sect1> + <sect1><title>Consumer Electronics Control devices</title> +!Iinclude/media/cec.h + </sect1> </chapter>
Documentation/DocBook/media/Makefile +2 -0
@@ -64,6 +64,7 @@ IOCTLS = \ $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \ $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \ $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \ + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/cec.h) \ $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ DEFINES = \
@@ -100,6 +101,7 @@ STRUCTS = \ $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \ $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \ $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \ + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/cec.h) \ $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h)
Documentation/DocBook/media/v4l/biblio.xml +10 -0
@@ -342,6 +342,16 @@ in the frequency range from 87,5 to 108,0 MHz</title> <subtitle>Specification Version 1.4a</subtitle> </biblioentry> + <biblioentry id="hdmi2"> + <abbrev>HDMI2</abbrev> + <authorgroup> + <corpauthor>HDMI Licensing LLC +(<ulink url="http://www.hdmi.org">http://www.hdmi.org</ulink>)</corpauthor> + </authorgroup> + <title>High-Definition Multimedia Interface</title> + <subtitle>Specification Version 2.0</subtitle> + </biblioentry> + <biblioentry id="dp"> <abbrev>DP</abbrev> <authorgroup>
Documentation/DocBook/media/v4l/cec-api.xml new file +76 -0
76 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-func-close.xml new file +59 -0
59 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-func-ioctl.xml new file +73 -0
73 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-func-open.xml new file +94 -0
94 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-func-poll.xml new file +89 -0
89 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml new file +167 -0
167 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml new file +306 -0
306 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml new file +80 -0
80 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-adap-g-state.xml new file +87 -0
87 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-adap-g-vendor-id.xml new file +70 -0
70 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-claim.xml new file +71 -0
71 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml new file +208 -0
208 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-g-monitor.xml new file +86 -0
86 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml new file +81 -0
81 lines not on this page · raw message
Documentation/DocBook/media/v4l/cec-ioc-receive.xml new file +190 -0
190 lines not on this page · raw message
Documentation/DocBook/media_api.tmpl +5 -1
@@ -75,7 +75,7 @@ </mediaobject> </figure> <para>The media infrastructure API was designed to control such - devices. It is divided into four parts.</para> + devices. It is divided into five parts.</para> <para>The first part covers radio, video capture and output, cameras, analog TV devices and codecs.</para> <para>The second part covers the
@@ -87,6 +87,7 @@ <xref linkend="fe-delivery-system-t" />.</para> <para>The third part covers the Remote Controller API.</para> <para>The fourth part covers the Media Controller API.</para> + <para>The fifth part covers the CEC (Consumer Electronics Control) API.</para> <para>It should also be noted that a media device may also have audio components, like mixers, PCM capture, PCM playback, etc, which are controlled via ALSA API.</para>
@@ -107,6 +108,9 @@ <part id="media_common"> &sub-media-controller; </part> +<part id="cec"> +&sub-cec-api; +</part> <chapter id="gen_errors"> &sub-gen-errors;
Signature · 1 line
2.6.2
PATCH v10 11/16 v4l2-subdev: add HDMI CEC ops
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add CEC callbacks to the new v4l2_subdev_cec_ops struct. These are the low-level CEC ops that subdevs that support CEC have to implement.
--- include/media/v4l2-subdev.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
include/media/v4l2-subdev.h +14 -0
@@ -42,6 +42,10 @@#define V4L2_DEVICE_NOTIFY_EVENT _IOW('v', 2, struct v4l2_event) +#define V4L2_SUBDEV_CEC_TX_DONE _IOW('v', 3, u32) +#define V4L2_SUBDEV_CEC_RX_MSG _IOW('v', 4, struct cec_msg) +#define V4L2_SUBDEV_CEC_CONN_INPUTS _IOW('v', 5, u16) +struct v4l2_device ;struct v4l2_ctrl_handler ;struct v4l2_event ;
@@ -51,6 +55,7 @@ struct v4l2_subdev;struct v4l2_subdev_fh ;struct tuner_setup ;struct v4l2_mbus_frame_desc ; +struct cec_msg ;/* decode_vbi_line */ struct v4l2_decode_vbi_line {
@@ -642,6 +647,14 @@ struct v4l2_subdev_pad_ops { struct v4l2_mbus_frame_desc *fd); }; +struct v4l2_subdev_cec_ops { +unsigned (*available_log_addrs)(struct v4l2_subdev *sd); +int (*enable)(struct v4l2_subdev *sd,bool enable); +int (*log_addr)(struct v4l2_subdev *sd,u8 logical_addr); +int (*transmit)(struct v4l2_subdev *sd,u32 timeout_ms, +u8 retries,struct cec_msg *msg); +}; +struct v4l2_subdev_ops {const struct v4l2_subdev_core_ops *core;const struct v4l2_subdev_tuner_ops *tuner;
@@ -651,6 +664,7 @@ struct v4l2_subdev_ops {const struct v4l2_subdev_ir_ops *ir;const struct v4l2_subdev_sensor_ops *sensor;const struct v4l2_subdev_pad_ops *pad; +const struct v4l2_subdev_cec_ops *cec; };/*
Signature · 1 line
2.6.2
PATCH v10 12/16 cec: adv7604: add cec support.
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add CEC support to the adv7604 driver.
--- drivers/media/i2c/adv7604.c | 241 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 4 deletions(-)
drivers/media/i2c/adv7604.c +237 -4
@@ -40,6 +40,7 @@#include <linux/regmap.h> #include <media/adv7604.h> +#include <media/cec.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h>
@@ -80,6 +81,8 @@ MODULE_LICENSE("GPL");#define ADV76XX_OP_SWAP_CB_CR (1 << 0) +#define ADV76XX_MAX_ADDRS (3) +enum adv76xx_type {ADV7604 ,ADV7611 ,
@@ -184,6 +187,10 @@ struct adv76xx_state {u16 spa_port_a[2 ];struct v4l2_fract aspect_ratio;u32 rgb_quantization_range; +u8 cec_addr[ADV76XX_MAX_ADDRS ]; +u8 cec_valid_addrs; +bool cec_enabled_adap; +struct workqueue_struct *work_queues;struct delayed_work delayed_work_enable_hotplug;bool restart_stdi_once;
@@ -430,7 +437,8 @@ static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)return regmap_write (state->regmap[ADV76XX_PAGE_IO ], reg, val); } -static inline int io_write_clr_set (struct v4l2_subdev *sd,u8 reg,u8 mask,u8 val) +static inline int io_write_clr_set (struct v4l2_subdev *sd,u8 reg,u8 mask, +u8 val) {return io_write (sd, reg, (io_read (sd, reg) & ~mask) | val); }
@@ -463,6 +471,12 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)return regmap_write (state->regmap[ADV76XX_PAGE_CEC ], reg, val); } +static inline int cec_write_clr_set (struct v4l2_subdev *sd,u8 reg,u8 mask, +u8 val) +{ +return cec_write (sd, reg, (cec_read (sd, reg) & ~mask) | val); +} +static inline int infoframe_read (struct v4l2_subdev *sd,u8 reg) {struct adv76xx_state *state =to_state (sd);
@@ -550,8 +564,13 @@ static inline int edid_write_block(struct v4l2_subdev *sd,static void adv76xx_set_hpd (struct adv76xx_state *state,unsigned int hpd) { +u16 connected_inputs;unsigned int i; + connected_inputs = hpd & state->info->read_cable_det (&state->sd); +v4l2_subdev_notify (&state->sd,V4L2_SUBDEV_CEC_CONN_INPUTS , + &connected_inputs); +for (i =0 ; i < state->info->num_dv_ports; ++i)gpiod_set_value_cansleep (state->hpd_gpio[i], hpd &BIT (i));
@@ -891,9 +910,12 @@ static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) {struct adv76xx_state *state =to_state (sd);const struct adv76xx_chip_info *info = state->info; +u16 cable_det = info->read_cable_det (sd); +u16 connected_inputs = state->edid.present & cable_det; -return v4l2_ctrl_s_ctrl (state->detect_tx_5v_ctrl, - info->read_cable_det (sd)); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_CONN_INPUTS , + &connected_inputs); +return v4l2_ctrl_s_ctrl (state->detect_tx_5v_ctrl, cable_det); } static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
@@ -1914,6 +1936,187 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,return 0 ; } +static void adv76xx_cec_tx_raw_status (struct v4l2_subdev *sd,u8 tx_raw_status) +{ +if ((cec_read (sd,0x11 ) &0x01 ) ==0 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: tx disabled\n" , __func__); +return ; + } + +if (tx_raw_status &0x02 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: arbitration lost\n" , + __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_ARB_LOST ); +return ; + } +if (tx_raw_status &0x04 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: retry failed\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_RETRY_TIMEOUT ); +return ; + } +if (tx_raw_status &0x01 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: ready ok\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_OK ); +return ; + } +} + +static void adv76xx_cec_isr (struct v4l2_subdev *sd,bool *handled) +{ +u8 cec_irq; + +/* cec controller */ + cec_irq =io_read (sd,0x4d ) &0x0f ; +if (!cec_irq) +return ; + +v4l2_dbg (1 , debug, sd,"%s: cec: irq 0x%x\n" , __func__, cec_irq); +adv76xx_cec_tx_raw_status (sd, cec_irq); +if (cec_irq &0x08 ) { +struct cec_msg msg; + + msg.len =cec_read (sd,0x25 ) &0x1f ; +if (msg.len >16 ) + msg.len =16 ; + +if (msg.len) { +u8 i; + +for (i =0 ; i < msg.len; i++) + msg.msg[i] =cec_read (sd, i +0x15 ); +cec_write (sd,0x26 ,0x01 );/* re-enable rx */ +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_RX_MSG , &msg); + } + } + +/* note: the bit order is swapped between 0x4d and 0x4e */ + cec_irq = ((cec_irq &0x08 ) >>3 ) | ((cec_irq &0x04 ) >>1 ) | + ((cec_irq &0x02 ) <<1 ) | ((cec_irq &0x01 ) <<3 ); +io_write (sd,0x4e , cec_irq); + +if (handled) + *handled = true; +} + +static unsigned adv76xx_cec_available_log_addrs (struct v4l2_subdev *sd) +{ +return ADV76XX_MAX_ADDRS ; +} + +static int adv76xx_cec_enable (struct v4l2_subdev *sd,bool enable) +{ +struct adv76xx_state *state =to_state (sd); + +if (!state->cec_enabled_adap && enable) { +cec_write_clr_set (sd,0x2a ,0x01 ,0x01 );/* power up cec */ +cec_write (sd,0x2c ,0x01 );/* cec soft reset */ +cec_write_clr_set (sd,0x11 ,0x01 ,0 );/* initially disable tx */ +/* enabled irqs: */ +/* tx: ready */ +/* tx: arbitration lost */ +/* tx: retry timeout */ +/* rx: ready */ +io_write_clr_set (sd,0x50 ,0x0f ,0x0f ); +cec_write (sd,0x26 ,0x01 );/* enable rx */ + }else if (state->cec_enabled_adap && !enable) { +/* disable cec interrupts */ +io_write_clr_set (sd,0x50 ,0x0f ,0x00 ); +/* disable address mask 1-3 */ +cec_write_clr_set (sd,0x27 ,0x70 ,0x00 ); +/* power down cec section */ +cec_write_clr_set (sd,0x2a ,0x01 ,0x00 ); + state->cec_valid_addrs =0 ; + } + state->cec_enabled_adap = enable; +adv76xx_s_detect_tx_5v_ctrl (sd); +return 0 ; +} + +static int adv76xx_cec_log_addr (struct v4l2_subdev *sd,u8 addr) +{ +struct adv76xx_state *state =to_state (sd); +unsigned i, free_idx =ADV76XX_MAX_ADDRS ; + +if (!state->cec_enabled_adap) +return -EIO ; + +if (addr ==CEC_LOG_ADDR_INVALID ) { +cec_write_clr_set (sd,0x27 ,0x70 ,0 ); + state->cec_valid_addrs =0 ; +return 0 ; + } + +for (i =0 ; i <ADV76XX_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (free_idx ==ADV76XX_MAX_ADDRS && !is_valid) + free_idx = i; +if (is_valid && state->cec_addr[i] == addr) +return 0 ; + } +if (i ==ADV76XX_MAX_ADDRS ) { + i = free_idx; +if (i ==ADV76XX_MAX_ADDRS ) +return -ENXIO ; + } + state->cec_addr[i] = addr; + state->cec_valid_addrs |=1 << i; + +switch (i) { +case 0 : +/* enable address mask 0 */ +cec_write_clr_set (sd,0x27 ,0x10 ,0x10 ); +/* set address for mask 0 */ +cec_write_clr_set (sd,0x28 ,0x0f , addr); +break ; +case 1 : +/* enable address mask 1 */ +cec_write_clr_set (sd,0x27 ,0x20 ,0x20 ); +/* set address for mask 1 */ +cec_write_clr_set (sd,0x28 ,0xf0 , addr <<4 ); +break ; +case 2 : +/* enable address mask 2 */ +cec_write_clr_set (sd,0x27 ,0x40 ,0x40 ); +/* set address for mask 1 */ +cec_write_clr_set (sd,0x29 ,0x0f , addr); +break ; + } +return 0 ; +} + +static int adv76xx_cec_transmit (struct v4l2_subdev *sd,u32 timeout_ms, +u8 retries,struct cec_msg *msg) +{ +u8 len = msg->len; +unsigned i; + +if (len ==1 ) +/* allow for one retry for polling */ +cec_write_clr_set (sd,0x12 ,0x07 ,1 ); +else +/* allow for three retries */ +cec_write_clr_set (sd,0x12 ,0x07 ,3 ); + +if (len >16 ) { +v4l2_err (sd,"%s: len exceeded 16 (%d)\n" , __func__, len); +return -EINVAL ; + } + +/* write data */ +for (i =0 ; i < len; i++) +cec_write (sd, i, msg->msg[i]); + +/* set length (data + header) */ +cec_write (sd,0x10 , len); +/* start transmit, enable tx */ +cec_write (sd,0x11 ,0x01 ); +return 0 ; +} +static int adv76xx_isr (struct v4l2_subdev *sd,u32 status,bool *handled) {struct adv76xx_state *state =to_state (sd);
@@ -1959,6 +2162,9 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) *handled = true; } +/* cec */ +adv76xx_cec_isr (sd, handled); +/* tx 5v detect */ tx_5v =io_read (sd,0x70 ) & info->cable_det_mask;if (tx_5v) {
@@ -2266,8 +2472,19 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) ((edid_enabled &0x02 ) ?"Yes" :"No" ), ((edid_enabled &0x04 ) ?"Yes" :"No" ), ((edid_enabled & 0x08) ? "Yes" : "No")); -v4l2_info (sd,"CEC: %s\n" , !!(cec_read (sd,0x2a ) &0x01 ) ? +v4l2_info (sd,"CEC: %s\n" , state->cec_enabled_adap ?"enabled" :"disabled" ); +if (state->cec_enabled_adap) { +int i; + +for (i =0 ; i <ADV76XX_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (is_valid) +v4l2_info (sd,"CEC Logical Address: 0x%x\n" , + state->cec_addr[i]); + } + }v4l2_info (sd,"-----Signal status-----\n" ); cable_det = info->read_cable_det (sd);
@@ -2402,6 +2619,13 @@ static const struct v4l2_subdev_video_ops adv76xx_video_ops = { .query_dv_timings = adv76xx_query_dv_timings, }; +static const struct v4l2_subdev_cec_ops adv76xx_cec_ops = { + .available_log_addrs = adv76xx_cec_available_log_addrs, + .enable = adv76xx_cec_enable, + .log_addr = adv76xx_cec_log_addr, + .transmit = adv76xx_cec_transmit, +}; +static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { .enum_mbus_code = adv76xx_enum_mbus_code, .get_fmt = adv76xx_get_format,
@@ -2416,6 +2640,7 @@ static const struct v4l2_subdev_ops adv76xx_ops = { .core = &adv76xx_core_ops, .video = &adv76xx_video_ops, .pad = &adv76xx_pad_ops, + .cec = &adv76xx_cec_ops, };/* -------------------------- custom ctrls ---------------------------------- */
@@ -3249,6 +3474,14 @@ static int adv76xx_remove(struct i2c_client *client)struct v4l2_subdev *sd =i2c_get_clientdata (client);struct adv76xx_state *state =to_state (sd); +/* disable interrupts */ +io_write (sd,0x40 ,0 ); +io_write (sd,0x41 ,0 ); +io_write (sd,0x46 ,0 ); +io_write (sd,0x6e ,0 ); +io_write (sd,0x73 ,0 ); +adv76xx_cec_enable (sd, false); +cancel_delayed_work (&state->delayed_work_enable_hotplug);destroy_workqueue (state->work_queues);v4l2_async_unregister_subdev (sd);
Signature · 1 line
2.6.2
PATCH v10 13/16 cec: adv7842: add cec support
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add CEC support to the adv7842 driver.
--- drivers/media/i2c/adv7842.c | 255 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 238 insertions(+), 17 deletions(-)
drivers/media/i2c/adv7842.c +238 -17
@@ -39,6 +39,7 @@#include <linux/workqueue.h> #include <linux/v4l2-dv-timings.h> #include <linux/hdmi.h> +#include <media/cec.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h>
@@ -79,6 +80,8 @@ MODULE_LICENSE("GPL");#define ADV7842_OP_SWAP_CB_CR (1 << 0) +#define ADV7842_MAX_ADDRS (3) +/* ********************************************************************** *
@@ -142,6 +145,10 @@ struct adv7842_state {struct v4l2_ctrl *free_run_color_ctrl_manual;struct v4l2_ctrl *free_run_color_ctrl;struct v4l2_ctrl *rgb_quantization_range_ctrl; + +u8 cec_addr[ADV7842_MAX_ADDRS ]; +u8 cec_valid_addrs; +bool cec_enabled_adap; };/* Unsupported timings. This device cannot support 720p30. */
@@ -418,9 +425,9 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)return adv_smbus_write_byte_data (state->i2c_cec, reg, val); } -static inline int cec_write_and_or (struct v4l2_subdev *sd,u8 reg,u8 mask,u8 val) +static inline int cec_write_clr_set (struct v4l2_subdev *sd,u8 reg,u8 mask,u8 val) { -return cec_write (sd, reg, (cec_read (sd, reg) & mask) | val); +return cec_write (sd, reg, (cec_read (sd, reg) & ~mask) | val); }static inline int infoframe_read (struct v4l2_subdev *sd,u8 reg)
@@ -696,6 +703,18 @@ adv7842_get_dv_timings_cap(struct v4l2_subdev *sd)/* ----------------------------------------------------------------------- */ +static u16 adv7842_read_cable_det (struct v4l2_subdev *sd) +{ +u8 reg =io_read (sd,0x6f ); +u16 val =0 ; + +if (reg &0x02 ) + val |=1 ;/* port A */ +if (reg &0x01 ) + val |=2 ;/* port B */ +return val; +} +static void adv7842_delayed_work_enable_hotplug (struct work_struct *work) {struct delayed_work *dwork =to_delayed_work (work);
@@ -703,8 +722,13 @@ static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) struct adv7842_state, delayed_work_enable_hotplug);struct v4l2_subdev *sd = &state->sd;int present = state->hdmi_edid.present; +u16 connected_inputs;u8 mask =0 ; + connected_inputs = present &adv7842_read_cable_det (sd); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_CONN_INPUTS , + &connected_inputs); +v4l2_dbg (2 , debug, sd,"%s: enable hotplug on ports: 0x%x\n" , __func__, present);
@@ -983,20 +1007,16 @@ static int adv7842_s_register(struct v4l2_subdev *sd,static int adv7842_s_detect_tx_5v_ctrl (struct v4l2_subdev *sd) {struct adv7842_state *state =to_state (sd); -int prev =v4l2_ctrl_g_ctrl (state->detect_tx_5v_ctrl); -u8 reg_io_6f =io_read (sd,0x6f ); -int val =0 ; +u16 cable_det =adv7842_read_cable_det (sd); +u16 connected_inputs; -if (reg_io_6f &0x02 ) - val |=1 ;/* port A */ -if (reg_io_6f &0x01 ) - val |=2 ;/* port B */ +v4l2_dbg (1 , debug, sd,"%s: 0x%x\n" , __func__, cable_det); -v4l2_dbg (1 , debug, sd,"%s: 0x%x -> 0x%x\n" , __func__, prev, val); + connected_inputs = state->hdmi_edid.present & cable_det; +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_CONN_INPUTS , + &connected_inputs); -if (val != prev) -return v4l2_ctrl_s_ctrl (state->detect_tx_5v_ctrl, val); -return 0 ; +return v4l2_ctrl_s_ctrl (state->detect_tx_5v_ctrl, cable_det); } static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
@@ -2157,6 +2177,183 @@ static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable) } } +static void adv7842_cec_tx_raw_status (struct v4l2_subdev *sd,u8 tx_raw_status) +{ +if ((cec_read (sd,0x11 ) &0x01 ) ==0 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: tx disabled\n" , __func__); +return ; + } + +if (tx_raw_status &0x02 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: arbitration lost\n" , + __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_ARB_LOST ); +return ; + } +if (tx_raw_status &0x04 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: retry failed\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_RETRY_TIMEOUT ); +return ; + } +if (tx_raw_status &0x01 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: ready ok\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_OK ); +return ; + } +} + +static void adv7842_cec_isr (struct v4l2_subdev *sd,bool *handled) +{ +u8 cec_irq; + +/* cec controller */ + cec_irq =io_read (sd,0x93 ) &0x0f ; +if (!cec_irq) +return ; + +v4l2_dbg (1 , debug, sd,"%s: cec: irq 0x%x\n" , __func__, cec_irq); +adv7842_cec_tx_raw_status (sd, cec_irq); +if (cec_irq &0x08 ) { +struct cec_msg msg; + + msg.len =cec_read (sd,0x25 ) &0x1f ; +if (msg.len >16 ) + msg.len =16 ; + +if (msg.len) { +u8 i; + +for (i =0 ; i < msg.len; i++) + msg.msg[i] =cec_read (sd, i +0x15 ); +cec_write (sd,0x26 ,0x01 );/* re-enable rx */ +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_RX_MSG , &msg); + } + } + +io_write (sd,0x94 , cec_irq); + +if (handled) + *handled = true; +} + +static unsigned adv7842_cec_available_log_addrs (struct v4l2_subdev *sd) +{ +return ADV7842_MAX_ADDRS ; +} + +static int adv7842_cec_enable (struct v4l2_subdev *sd,bool enable) +{ +struct adv7842_state *state =to_state (sd); + +if (!state->cec_enabled_adap && enable) { +cec_write_clr_set (sd,0x2a ,0x01 ,0x01 );/* power up cec */ +cec_write (sd,0x2c ,0x01 );/* cec soft reset */ +cec_write_clr_set (sd,0x11 ,0x01 ,0 );/* initially disable tx */ +/* enabled irqs: */ +/* tx: ready */ +/* tx: arbitration lost */ +/* tx: retry timeout */ +/* rx: ready */ +io_write_clr_set (sd,0x96 ,0x0f ,0x0f ); +cec_write (sd,0x26 ,0x01 );/* enable rx */ + }else if (state->cec_enabled_adap && !enable) { +/* disable cec interrupts */ +io_write_clr_set (sd,0x96 ,0x0f ,0x00 ); +/* disable address mask 1-3 */ +cec_write_clr_set (sd,0x27 ,0x70 ,0x00 ); +/* power down cec section */ +cec_write_clr_set (sd,0x2a ,0x01 ,0x00 ); + state->cec_valid_addrs =0 ; + } + state->cec_enabled_adap = enable; +return 0 ; +} + +static int adv7842_cec_log_addr (struct v4l2_subdev *sd,u8 addr) +{ +struct adv7842_state *state =to_state (sd); +unsigned i, free_idx =ADV7842_MAX_ADDRS ; + +if (!state->cec_enabled_adap) +return -EIO ; + +if (addr ==CEC_LOG_ADDR_INVALID ) { +cec_write_clr_set (sd,0x27 ,0x70 ,0 ); + state->cec_valid_addrs =0 ; +return 0 ; + } + +for (i =0 ; i <ADV7842_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (free_idx ==ADV7842_MAX_ADDRS && !is_valid) + free_idx = i; +if (is_valid && state->cec_addr[i] == addr) +return 0 ; + } +if (i ==ADV7842_MAX_ADDRS ) { + i = free_idx; +if (i ==ADV7842_MAX_ADDRS ) +return -ENXIO ; + } + state->cec_addr[i] = addr; + state->cec_valid_addrs |=1 << i; + +switch (i) { +case 0 : +/* enable address mask 0 */ +cec_write_clr_set (sd,0x27 ,0x10 ,0x10 ); +/* set address for mask 0 */ +cec_write_clr_set (sd,0x28 ,0x0f , addr); +break ; +case 1 : +/* enable address mask 1 */ +cec_write_clr_set (sd,0x27 ,0x20 ,0x20 ); +/* set address for mask 1 */ +cec_write_clr_set (sd,0x28 ,0xf0 , addr <<4 ); +break ; +case 2 : +/* enable address mask 2 */ +cec_write_clr_set (sd,0x27 ,0x40 ,0x40 ); +/* set address for mask 1 */ +cec_write_clr_set (sd,0x29 ,0x0f , addr); +break ; + } +return 0 ; +} + +static int adv7842_cec_transmit (struct v4l2_subdev *sd,u32 timeout_ms, +u8 retries,struct cec_msg *msg) +{ +u8 len = msg->len; +unsigned i; + +if (len ==1 ) +/* allow for one retry for polling */ +cec_write_clr_set (sd,0x12 ,0x07 ,1 ); +else +/* allow for three retries */ +cec_write_clr_set (sd,0x12 ,0x07 ,3 ); + +if (len >16 ) { +v4l2_err (sd,"%s: len exceeded 16 (%d)\n" , __func__, len); +return -EINVAL ; + } + +/* write data */ +for (i =0 ; i < len; i++) +cec_write (sd, i, msg->msg[i]); + +/* set length (data + header) */ +cec_write (sd,0x10 , len); +/* start transmit, enable tx */ +cec_write (sd,0x11 ,0x01 ); +return 0 ; +} +static int adv7842_isr (struct v4l2_subdev *sd,u32 status,bool *handled) {struct adv7842_state *state =to_state (sd);
@@ -2228,6 +2425,9 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) *handled = true; } +/* cec */ +adv7842_cec_isr (sd, handled); +/* tx 5v detect */ if (irq_status[2 ] &0x3 ) {v4l2_dbg (1 , debug, sd,"%s: irq tx_5v\n" , __func__);
@@ -2308,10 +2508,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)case ADV7842_EDID_PORT_A :case ADV7842_EDID_PORT_B :memset (&state->hdmi_edid.edid,0 ,256 ); -if (e->blocks) +if (e->blocks) { state->hdmi_edid.present |=0x04 << e->pad; -else + }else { state->hdmi_edid.present &= ~(0x04 << e->pad); +adv7842_s_detect_tx_5v_ctrl (sd); + }memcpy (&state->hdmi_edid.edid, e->edid,128 * e->blocks); err =edid_write_hdmi_segment (sd, e->pad);break ;
@@ -2496,8 +2698,19 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)v4l2_info (sd,"HPD A %s, B %s\n" , reg_io_0x21 &0x02 ?"enabled" :"disabled" , reg_io_0x21 &0x01 ?"enabled" :"disabled" ); -v4l2_info (sd,"CEC %s\n" , !!(cec_read (sd,0x2a ) &0x01 ) ? +v4l2_info (sd,"CEC: %s\n" , state->cec_enabled_adap ?"enabled" :"disabled" ); +if (state->cec_enabled_adap) { +int i; + +for (i =0 ; i <ADV7842_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (is_valid) +v4l2_info (sd,"CEC Logical Address: 0x%x\n" , + state->cec_addr[i]); + } + }v4l2_info (sd,"-----Signal status-----\n" );if (state->hdmi_port_a) {
@@ -3047,6 +3260,13 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { .query_dv_timings = adv7842_query_dv_timings, }; +static const struct v4l2_subdev_cec_ops adv7842_cec_ops = { + .available_log_addrs = adv7842_cec_available_log_addrs, + .enable = adv7842_cec_enable, + .log_addr = adv7842_cec_log_addr, + .transmit = adv7842_cec_transmit, +}; +static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { .enum_mbus_code = adv7842_enum_mbus_code, .get_fmt = adv7842_get_format,
@@ -3061,6 +3281,7 @@ static const struct v4l2_subdev_ops adv7842_ops = { .core = &adv7842_core_ops, .video = &adv7842_video_ops, .pad = &adv7842_pad_ops, + .cec = &adv7842_cec_ops, };/* -------------------------- custom ctrls ---------------------------------- */
@@ -3341,7 +3562,7 @@ static int adv7842_remove(struct i2c_client *client)struct adv7842_state *state =to_state (sd);adv7842_irq_enable (sd, false); - +adv7842_cec_enable (sd, false);cancel_delayed_work (&state->delayed_work_enable_hotplug);destroy_workqueue (state->work_queues);v4l2_device_unregister_subdev (sd);
Signature · 1 line
2.6.2
PATCH v10 14/16 cec: adv7511: add cec support.
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add CEC support to the adv7511 driver.
--- drivers/media/i2c/adv7511.c | 364 +++++++++++++++++++++++++++++++++++++++++++- include/media/adv7511.h | 6 +- 2 files changed, 358 insertions(+), 12 deletions(-)
drivers/media/i2c/adv7511.c +357 -7
@@ -33,6 +33,7 @@#include <media/v4l2-ctrls.h> #include <media/v4l2-dv-timings.h> #include <media/adv7511.h> +#include <media/cec.h> static int debug;module_param (debug, int,0644 );
@@ -59,6 +60,8 @@ MODULE_LICENSE("GPL v2");#define ADV7511_MIN_PIXELCLOCK 20000000#define ADV7511_MAX_PIXELCLOCK 225000000 +#define ADV7511_MAX_ADDRS (3) +/* ********************************************************************** *
@@ -90,12 +93,19 @@ struct adv7511_state {struct v4l2_ctrl_handler hdl;int chip_revision;u8 i2c_edid_addr; -u8 i2c_cec_addr;u8 i2c_pktmem_addr; +u8 i2c_cec_addr; + +struct i2c_client *i2c_cec; +u8 cec_addr[ADV7511_MAX_ADDRS ]; +u8 cec_valid_addrs; +bool cec_enabled_adap; +/* Is the adv7511 powered on? */ bool power_on;/* Did we receive hotplug and rx-sense signals? */ bool have_monitor; +bool enabled_irq;/* timings from s_dv_timings */ struct v4l2_dv_timings dv_timings;u32 fmt_code;
@@ -225,7 +235,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client,return ret; } -static inline void adv7511_edid_rd (struct v4l2_subdev *sd,u16 len,u8 *buf) +static void adv7511_edid_rd (struct v4l2_subdev *sd,uint16_t len,uint8_t *buf) {struct adv7511_state *state =get_adv7511_state (sd);int i;
@@ -240,6 +250,34 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf)v4l2_err (sd,"%s: i2c read error\n" , __func__); } +static inline int adv7511_cec_read (struct v4l2_subdev *sd,u8 reg) +{ +struct adv7511_state *state =get_adv7511_state (sd); + +return i2c_smbus_read_byte_data (state->i2c_cec, reg); +} + +static int adv7511_cec_write (struct v4l2_subdev *sd,u8 reg,u8 val) +{ +struct adv7511_state *state =get_adv7511_state (sd); +int ret; +int i; + +for (i =0 ; i <3 ; i++) { + ret =i2c_smbus_write_byte_data (state->i2c_cec, reg, val); +if (ret ==0 ) +return 0 ; + } +v4l2_err (sd,"%s: I2C Write Problem\n" , __func__); +return ret; +} + +static inline int adv7511_cec_write_and_or (struct v4l2_subdev *sd,u8 reg,u8 mask, +u8 val) +{ +return adv7511_cec_write (sd, reg, (adv7511_cec_read (sd, reg) & mask) | val); +} +static int adv7511_pktmem_rd (struct v4l2_subdev *sd,u8 reg) {struct adv7511_state *state =get_adv7511_state (sd);
@@ -413,16 +451,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = {#ifdef CONFIG_VIDEO_ADV_DEBUG static void adv7511_inv_register (struct v4l2_subdev *sd) { +struct adv7511_state *state =get_adv7511_state (sd); +v4l2_info (sd,"0x000-0x0ff: Main Map\n" ); +if (state->i2c_cec) +v4l2_info (sd,"0x100-0x1ff: CEC Map\n" ); }static int adv7511_g_register (struct v4l2_subdev *sd,struct v4l2_dbg_register *reg) { +struct adv7511_state *state =get_adv7511_state (sd); + reg->size =1 ;switch (reg->reg >>8 ) {case 0 : reg->val =adv7511_rd (sd, reg->reg &0xff );break ; +case 1 : +if (state->i2c_cec) { + reg->val =adv7511_cec_read (sd, reg->reg &0xff ); +break ; + } +/* fall through */ default :v4l2_info (sd,"Register %03llx not supported\n" , reg->reg);adv7511_inv_register (sd);
@@ -433,10 +483,18 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *static int adv7511_s_register (struct v4l2_subdev *sd,const struct v4l2_dbg_register *reg) { +struct adv7511_state *state =get_adv7511_state (sd); +switch (reg->reg >>8 ) {case 0 :adv7511_wr (sd, reg->reg &0xff , reg->val &0xff );break ; +case 1 : +if (state->i2c_cec) { +adv7511_cec_write (sd, reg->reg &0xff , reg->val &0xff ); +break ; + } +/* fall through */ default :v4l2_info (sd,"Register %03llx not supported\n" , reg->reg);adv7511_inv_register (sd);
@@ -524,6 +582,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) {struct adv7511_state *state =get_adv7511_state (sd);struct adv7511_state_edid *edid = &state->edid; +int i;static const char *const states[] = {"in reset" ,
@@ -593,7 +652,23 @@ static int adv7511_log_status(struct v4l2_subdev *sd)else v4l2_info (sd,"no timings set\n" );v4l2_info (sd,"i2c edid addr: 0x%x\n" , state->i2c_edid_addr); + +if (state->i2c_cec ==NULL ) +return 0 ; +v4l2_info (sd,"i2c cec addr: 0x%x\n" , state->i2c_cec_addr); + +v4l2_info (sd,"CEC: %s\n" , state->cec_enabled_adap ? +"enabled" :"disabled" ); +if (state->cec_enabled_adap) { +for (i =0 ; i <ADV7511_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (is_valid) +v4l2_info (sd,"CEC Logical Address: 0x%x\n" , + state->cec_addr[i]); + } + }v4l2_info (sd,"i2c pktmem addr: 0x%x\n" , state->i2c_pktmem_addr);return 0 ; }
@@ -651,15 +726,139 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on)return true; } +static unsigned adv7511_cec_available_log_addrs (struct v4l2_subdev *sd) +{ +return ADV7511_MAX_ADDRS ; +} + +static int adv7511_cec_enable (struct v4l2_subdev *sd,bool enable) +{ +struct adv7511_state *state =get_adv7511_state (sd); + +if (state->i2c_cec ==NULL ) +return -EIO ; + +if (!state->cec_enabled_adap && enable) { +/* power up cec section */ +adv7511_cec_write_and_or (sd,0x4e ,0xfc ,0x01 ); +/* legacy mode and clear all rx buffers */ +adv7511_cec_write (sd,0x4a ,0x07 ); +adv7511_cec_write (sd,0x4a ,0 ); +adv7511_cec_write_and_or (sd,0x11 ,0xfe ,0 );/* initially disable tx */ +/* enabled irqs: */ +/* tx: ready */ +/* tx: arbitration lost */ +/* tx: retry timeout */ +/* rx: ready 1 */ +if (state->enabled_irq) +adv7511_wr_and_or (sd,0x95 ,0xc0 ,0x39 ); + }else if (state->cec_enabled_adap && !enable) { +if (state->enabled_irq) +adv7511_wr_and_or (sd,0x95 ,0xc0 ,0x00 ); +/* disable address mask 1-3 */ +adv7511_cec_write_and_or (sd,0x4b ,0x8f ,0x00 ); +/* power down cec section */ +adv7511_cec_write_and_or (sd,0x4e ,0xfc ,0x00 ); + state->cec_valid_addrs =0 ; + } + state->cec_enabled_adap = enable; +return 0 ; +} + +static int adv7511_cec_log_addr (struct v4l2_subdev *sd,u8 addr) +{ +struct adv7511_state *state =get_adv7511_state (sd); +unsigned i, free_idx =ADV7511_MAX_ADDRS ; + +if (!state->cec_enabled_adap) +return -EIO ; + +if (addr ==CEC_LOG_ADDR_INVALID ) { +adv7511_cec_write_and_or (sd,0x4b ,0x8f ,0 ); + state->cec_valid_addrs =0 ; +return 0 ; + } + +for (i =0 ; i <ADV7511_MAX_ADDRS ; i++) { +bool is_valid = state->cec_valid_addrs & (1 << i); + +if (free_idx ==ADV7511_MAX_ADDRS && !is_valid) + free_idx = i; +if (is_valid && state->cec_addr[i] == addr) +return 0 ; + } +if (i ==ADV7511_MAX_ADDRS ) { + i = free_idx; +if (i ==ADV7511_MAX_ADDRS ) +return -ENXIO ; + } + state->cec_addr[i] = addr; + state->cec_valid_addrs |=1 << i; + +switch (i) { +case 0 : +/* enable address mask 0 */ +adv7511_cec_write_and_or (sd,0x4b ,0xef ,0x10 ); +/* set address for mask 0 */ +adv7511_cec_write_and_or (sd,0x4c ,0xf0 , addr); +break ; +case 1 : +/* enable address mask 1 */ +adv7511_cec_write_and_or (sd,0x4b ,0xdf ,0x20 ); +/* set address for mask 1 */ +adv7511_cec_write_and_or (sd,0x4c ,0x0f , addr <<4 ); +break ; +case 2 : +/* enable address mask 2 */ +adv7511_cec_write_and_or (sd,0x4b ,0xbf ,0x40 ); +/* set address for mask 1 */ +adv7511_cec_write_and_or (sd,0x4d ,0xf0 , addr); +break ; + } +return 0 ; +} + +static int adv7511_cec_transmit (struct v4l2_subdev *sd,u32 timeout_ms, +u8 retries,struct cec_msg *msg) +{ +u8 len = msg->len; +unsigned i; + +v4l2_dbg (1 , debug, sd,"%s: len %d\n" , __func__, len); + +if (len >16 ) { +v4l2_err (sd,"%s: len exceeded 16 (%d)\n" , __func__, len); +return -EINVAL ; + } + +/* blocking, clear cec tx irq status */ +adv7511_wr_and_or (sd,0x97 ,0xc7 ,0x38 ); + +/* write data */ +for (i =0 ; i < len; i++) +adv7511_cec_write (sd, i, msg->msg[i]); + +/* set length (data + header) */ +adv7511_cec_write (sd,0x10 , len); +/* start transmit, enable tx */ +adv7511_cec_write (sd,0x11 ,0x01 ); +return 0 ; +} +/* Enable interrupts */ static void adv7511_set_isr (struct v4l2_subdev *sd,bool enable) { +struct adv7511_state *state =get_adv7511_state (sd);u8 irqs =MASK_ADV7511_HPD_INT |MASK_ADV7511_MSEN_INT ;u8 irqs_rd;int retries =100 ;v4l2_dbg (2 , debug, sd,"%s: %s\n" , __func__, enable ?"enable" :"disable" ); +if (state->enabled_irq == enable) +return ; + state->enabled_irq = enable; +/* The datasheet says that the EDID ready interrupt should be disabled if there is no hotplug. */ if (!enable)
@@ -667,6 +866,9 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)else if (adv7511_have_hotplug (sd)) irqs |=MASK_ADV7511_EDID_RDY_INT ; +if (state->cec_enabled_adap) +adv7511_wr_and_or (sd,0x95 ,0xc0 , enable ?0x39 :0x00 ); +/* * This i2c write can fail (approx. 1 in 1000 writes). But it * is essential that this register is correct, so retry it
@@ -685,24 +887,82 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)v4l2_err (sd,"Could not set interrupts: hw failure?\n" ); } +static void adv_cec_tx_raw_status (struct v4l2_subdev *sd,u8 tx_raw_status) +{ +if ((adv7511_cec_read (sd,0x11 ) &0x01 ) ==0 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: tx disabled\n" , __func__); +return ; + } + +if (tx_raw_status &0x10 ) { +v4l2_dbg (1 , debug, sd, +"%s: tx raw: arbitration lost\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_ARB_LOST ); +return ; + } +if (tx_raw_status &0x08 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: retry failed\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_RETRY_TIMEOUT ); +return ; + } +if (tx_raw_status &0x20 ) { +v4l2_dbg (1 , debug, sd,"%s: tx raw: ready ok\n" , __func__); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_TX_DONE , + (void *)CEC_TX_STATUS_OK ); +return ; + } +} +/* Interrupt handler */ static int adv7511_isr (struct v4l2_subdev *sd,u32 status,bool *handled) {u8 irq_status; +u8 cec_irq;/* disable interrupts to prevent a race condition */ adv7511_set_isr (sd, false); irq_status =adv7511_rd (sd,0x96 ); + cec_irq =adv7511_rd (sd,0x97 );/* clear detected interrupts */ adv7511_wr (sd,0x96 , irq_status); +adv7511_wr (sd,0x97 , cec_irq); -v4l2_dbg (1 , debug, sd,"%s: irq 0x%x\n" , __func__, irq_status); +v4l2_dbg (1 , debug, sd,"%s: irq 0x%x, cec-irq 0x%x\n" , __func__, + irq_status, cec_irq);if (irq_status & (MASK_ADV7511_HPD_INT |MASK_ADV7511_MSEN_INT ))adv7511_check_monitor_present_status (sd);if (irq_status &MASK_ADV7511_EDID_RDY_INT )adv7511_check_edid_status (sd); +if (cec_irq &0x38 ) +adv_cec_tx_raw_status (sd, cec_irq); + +if (cec_irq &1 ) { +struct cec_msg msg; + + msg.len =adv7511_cec_read (sd,0x25 ) &0x1f ; + +v4l2_dbg (1 , debug, sd,"%s: cec msg len %d\n" , __func__, + msg.len); + +if (msg.len >16 ) + msg.len =16 ; + +if (msg.len) { +u8 i; + +for (i =0 ; i < msg.len; i++) + msg.msg[i] =adv7511_cec_read (sd, i +0x15 ); + +adv7511_cec_write (sd,0x4a ,1 );/* toggle to re-enable rx 1 */ +adv7511_cec_write (sd,0x4a ,0 ); +v4l2_subdev_notify (sd,V4L2_SUBDEV_CEC_RX_MSG , &msg); + } + } +/* enable interrupts */ adv7511_set_isr (sd, true);
@@ -808,6 +1068,13 @@ static const struct v4l2_subdev_video_ops adv7511_video_ops = { .g_dv_timings = adv7511_g_dv_timings, }; +static const struct v4l2_subdev_cec_ops adv7511_cec_ops = { + .available_log_addrs = adv7511_cec_available_log_addrs, + .enable = adv7511_cec_enable, + .log_addr = adv7511_cec_log_addr, + .transmit = adv7511_cec_transmit, +}; +/* ------------------------------ AUDIO OPS ------------------------------ */ static int adv7511_s_audio_stream (struct v4l2_subdev *sd,int enable) {
@@ -1138,6 +1405,7 @@ static const struct v4l2_subdev_ops adv7511_ops = { .pad = &adv7511_pad_ops, .video = &adv7511_video_ops, .audio = &adv7511_audio_ops, + .cec = &adv7511_cec_ops, };/* ----------------------------------------------------------------------- */
@@ -1193,6 +1461,7 @@ static void adv7511_edid_handler(struct work_struct *work)/* We failed to read the EDID, so send an event for this. */ ed.present = false; ed.segment =adv7511_rd (sd,0xc4 ); + ed.phys_addr =0xffff ;v4l2_subdev_notify (sd,ADV7511_EDID_DETECT , (void *)&ed);v4l2_dbg (1 , debug, sd,"%s: no edid found\n" , __func__); }
@@ -1333,10 +1602,36 @@ static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)return !memcmp (data, hdmi_header,sizeof (hdmi_header)); } +static int get_edid_spa_location (const u8 *edid) +{ +u8 d; + +if (edid[0x7e ] !=1 || edid[0x80 ] !=0x02 || edid[0x81 ] !=0x03 ) +return -1 ; + +/* search Vendor Specific Data Block (tag 3) */ + d = edid[0x82 ] &0x7f ; +if (d >4 ) { +int i =0x84 ; +int end =0x80 + d; + +do { +u8 tag = edid[i] >>5 ; +u8 len = edid[i] &0x1f ; + +if (tag ==3 && len >=5 ) +return i +4 ; + i += len +1 ; + }while (i < end); + } +return -1 ; +} +static bool adv7511_check_edid_status (struct v4l2_subdev *sd) {struct adv7511_state *state =get_adv7511_state (sd);u8 edidRdy =adv7511_rd (sd,0xc5 ); +int offset;v4l2_dbg (1 , debug, sd,"%s: edid ready (retries: %d)\n" , __func__,EDID_MAX_RETRIES - state->edid.read_retries);
@@ -1382,6 +1677,12 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)v4l2_dbg (1 , debug, sd,"%s: edid complete with %d segment(s)\n" , __func__, state->edid.segments); state->edid.complete = true; + offset =get_edid_spa_location (state->edid.data); +if (offset >0 ) + ed.phys_addr = (state->edid.data[offset] <<8 ) | + state->edid.data[offset +1 ]; +else + ed.phys_addr =0xffff ;/* report when we have all segments but report only for segment 0
@@ -1403,11 +1704,14 @@ static void adv7511_init_setup(struct v4l2_subdev *sd) {struct adv7511_state *state =get_adv7511_state (sd);struct adv7511_state_edid *edid = &state->edid; +u32 cec_clk = state->pdata.cec_clk; +u8 ratio;v4l2_dbg (1 , debug, sd,"%s\n" , __func__);/* clear all interrupts */ adv7511_wr (sd,0x96 ,0xff ); +adv7511_wr (sd,0x97 ,0xff );/* * Stop HPD from resetting a lot of registers. * It might leave the chip in a partly un-initialized state,
@@ -1419,6 +1723,25 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)adv7511_set_isr (sd, false);adv7511_s_stream (sd, false);adv7511_s_audio_stream (sd, false); + +if (state->i2c_cec ==NULL ) +return ; + +v4l2_dbg (1 , debug, sd,"%s: cec_clk %d\n" , __func__, cec_clk); + +/* cec soft reset */ +adv7511_cec_write (sd,0x50 ,0x01 ); +adv7511_cec_write (sd,0x50 ,0x00 ); + +/* legacy mode */ +adv7511_cec_write (sd,0x4a ,0x00 ); + +if (cec_clk %750000 !=0 ) +v4l2_err (sd,"%s: cec_clk %d, not multiple of 750 Khz\n" , + __func__, cec_clk); + + ratio = (cec_clk /750000 ) -1 ; +adv7511_cec_write (sd,0x4e , ratio <<2 ); }static int adv7511_probe (struct i2c_client *client,const struct i2c_device_id *id)
@@ -1495,26 +1818,47 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * chip_id[0 ] =adv7511_rd (sd,0xf5 ); chip_id[1 ] =adv7511_rd (sd,0xf6 );if (chip_id[0 ] !=0x75 || chip_id[1 ] !=0x11 ) { -v4l2_err (sd,"chip_id != 0x7511, read 0x%02x%02x\n" , chip_id[0 ], chip_id[1 ]); +v4l2_err (sd,"chip_id != 0x7511, read 0x%02x%02x\n" , chip_id[0 ], + chip_id[1 ]); err = -EIO ; goto err_entity; } - state->i2c_edid =i2c_new_dummy (client->adapter, state->i2c_edid_addr >>1 ); + state->i2c_edid =i2c_new_dummy (client->adapter, + state->i2c_edid_addr >>1 );if (state->i2c_edid ==NULL ) {v4l2_err (sd,"failed to register edid i2c client\n" ); err = -ENOMEM ; goto err_entity; } +adv7511_wr (sd,0xe1 , state->i2c_cec_addr); +if (state->pdata.cec_clk <3000000 || + state->pdata.cec_clk >100000000 ) { +v4l2_err (sd,"%s: cec_clk %u outside range, disabling cec\n" , + __func__, state->pdata.cec_clk); + state->pdata.cec_clk =0 ; + } + +if (state->pdata.cec_clk) { + state->i2c_cec =i2c_new_dummy (client->adapter, + state->i2c_cec_addr >>1 ); +if (state->i2c_cec ==NULL ) { +v4l2_err (sd,"failed to register cec i2c client\n" ); + goto err_unreg_edid; + } +adv7511_wr (sd,0xe2 ,0x00 );/* power up cec section */ + }else { +adv7511_wr (sd,0xe2 ,0x01 );/* power down cec section */ + } + state->i2c_pktmem =i2c_new_dummy (client->adapter, state->i2c_pktmem_addr >>1 );if (state->i2c_pktmem ==NULL ) {v4l2_err (sd,"failed to register pktmem i2c client\n" ); err = -ENOMEM ; - goto err_unreg_edid; + goto err_unreg_cec; } -adv7511_wr (sd,0xe2 ,0x01 );/* power down cec section */ state->work_queue =create_singlethread_workqueue (sd->name);if (state->work_queue ==NULL ) {v4l2_err (sd,"could not create workqueue\n" );
@@ -1534,6 +1878,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * err_unreg_pktmem:i2c_unregister_device (state->i2c_pktmem); +err_unreg_cec: +if (state->i2c_cec) +i2c_unregister_device (state->i2c_cec); err_unreg_edid:i2c_unregister_device (state->i2c_edid); err_entity:
@@ -1555,9 +1902,12 @@ static int adv7511_remove(struct i2c_client *client)v4l2_dbg (1 , debug, sd,"%s removed @ 0x%x (%s)\n" , client->name, client->addr <<1 , client->adapter->name); +adv7511_set_isr (sd, false);adv7511_init_setup (sd);cancel_delayed_work (&state->edid_handler);i2c_unregister_device (state->i2c_edid); +if (state->i2c_cec) +i2c_unregister_device (state->i2c_cec);i2c_unregister_device (state->i2c_pktmem);destroy_workqueue (state->work_queue);v4l2_device_unregister_subdev (sd);
include/media/adv7511.h +1 -5
@@ -32,11 +32,7 @@ struct adv7511_monitor_detect {struct adv7511_edid_detect {int present;int segment; -}; - -struct adv7511_cec_arg { -void *arg; -u32 f_flags; +uint16_t phys_addr; };struct adv7511_platform_data {
Signature · 1 line
2.6.2
PATCH v10 15/16 cec: s5p-cec: Add s5p-cec driver
In reply to Hans VerkuilFrom: Kamil Debski <[email protected]>
Add CEC interface driver present in the Samsung Exynos range of SoCs.
The following files were based on work by SangPil Moon:
- exynos_hdmi_cec.h
- exynos_hdmi_cecctl.c
--- .../devicetree/bindings/media/s5p-cec.txt | 31 +++ drivers/media/platform/Kconfig | 12 + drivers/media/platform/Makefile | 1 + drivers/media/platform/s5p-cec/Makefile | 2 + drivers/media/platform/s5p-cec/exynos_hdmi_cec.h | 37 +++ .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c | 208 +++++++++++++++ drivers/media/platform/s5p-cec/regs-cec.h | 96 +++++++ drivers/media/platform/s5p-cec/s5p_cec.c | 289 +++++++++++++++++++++ drivers/media/platform/s5p-cec/s5p_cec.h | 76 ++++++ 9 files changed, 752 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt create mode 100644 drivers/media/platform/s5p-cec/Makefile create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h
Documentation/devicetree/bindings/media/s5p-cec.txt new file +31 -0
@@ -0,0 +1,31 @@ +* Samsung HDMI CEC driver + +The HDMI CEC module is present is Samsung SoCs and its purpose is to +handle communication between HDMI connected devices over the CEC bus. + +Required properties: + - compatible : value should be following + "samsung,s5p-cec" + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : HDMI CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to HDMI CEC clock. + - clock-names : from common clock binding: must contain "hdmicec", + corresponding to entry in the clocks property. + - samsung,syscon-phandle - phandle to the PMU system controller + +Example: + +hdmicec: cec@100B0000 { + compatible = "samsung,s5p-cec"; + reg = <0x100B0000 0x200>; + interrupts = <0 114 0>; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + status = "okay"; +};
drivers/media/platform/Kconfig +12 -0
@@ -117,6 +117,18 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" + +config VIDEO_SAMSUNG_S5P_CEC + tristate "Samsung S5P CEC driver" + depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) + select MEDIA_CEC + default n + ---help--- + This is a driver for Samsung S5P HDMI CEC interface. It uses the + generic CEC framework interface. + CEC bus is present in the HDMI connector and enables communication + between compatible devices. + source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig"
drivers/media/platform/Makefile +1 -0
@@ -27,6 +27,7 @@ obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/
drivers/media/platform/s5p-cec/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec.o +s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o
drivers/media/platform/s5p-cec/exynos_hdmi_cec.h new file +37 -0
@@ -0,0 +1,37 @@ +/* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h +* +* Copyright (c) 2010, 2014 Samsung Electronics +* http://www.samsung.com/ +* +* Header file for interface of Samsung Exynos hdmi cec hardware +* +* 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. +*/ + +#ifndef _EXYNOS_HDMI_CEC_H_ +#define _EXYNOS_HDMI_CEC_H_ __FILE__ + +#include <linux/regmap.h> +#include <linux/miscdevice.h> +#include "s5p_cec.h" + +void s5p_cec_set_divider (struct s5p_cec_dev *cec); +void s5p_cec_enable_rx (struct s5p_cec_dev *cec); +void s5p_cec_mask_rx_interrupts (struct s5p_cec_dev *cec); +void s5p_cec_unmask_rx_interrupts (struct s5p_cec_dev *cec); +void s5p_cec_mask_tx_interrupts (struct s5p_cec_dev *cec); +void s5p_cec_unmask_tx_interrupts (struct s5p_cec_dev *cec); +void s5p_cec_reset (struct s5p_cec_dev *cec); +void s5p_cec_tx_reset (struct s5p_cec_dev *cec); +void s5p_cec_rx_reset (struct s5p_cec_dev *cec); +void s5p_cec_threshold (struct s5p_cec_dev *cec); +void s5p_cec_copy_packet (struct s5p_cec_dev *cec,char *data,size_t count); +void s5p_cec_set_addr (struct s5p_cec_dev *cec,u32 addr); +u32 s5p_cec_get_status (struct s5p_cec_dev *cec); +void s5p_clr_pending_tx (struct s5p_cec_dev *cec); +void s5p_clr_pending_rx (struct s5p_cec_dev *cec); +void s5p_cec_get_rx_buf (struct s5p_cec_dev *cec,u32 size,u8 *buffer); + +#endif /* _EXYNOS_HDMI_CEC_H_ */
drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c new file +208 -0
208 lines not on this page · raw message
drivers/media/platform/s5p-cec/regs-cec.h new file +96 -0
96 lines not on this page · raw message
drivers/media/platform/s5p-cec/s5p_cec.c new file +289 -0
289 lines not on this page · raw message
drivers/media/platform/s5p-cec/s5p_cec.h new file +76 -0
76 lines not on this page · raw message
Signature · 1 line
2.6.2
PATCH v10 16/16 cobalt: add cec support
In reply to Hans VerkuilFrom: Hans Verkuil <[email protected]>
Add CEC support to the cobalt driver.
--- drivers/media/pci/cobalt/Kconfig | 1 + drivers/media/pci/cobalt/cobalt-driver.c | 108 +++++++++++++++++++++----- drivers/media/pci/cobalt/cobalt-driver.h | 2 + drivers/media/pci/cobalt/cobalt-irq.c | 3 + drivers/media/pci/cobalt/cobalt-v4l2.c | 126 ++++++++++++++++++++++++++++--- drivers/media/pci/cobalt/cobalt-v4l2.h | 2 + 6 files changed, 216 insertions(+), 26 deletions(-)
drivers/media/pci/cobalt/Kconfig +1 -0
@@ -4,6 +4,7 @@ config VIDEO_COBALT depends on PCI_MSI && MTD_COMPLEX_MAPPINGS depends on GPIOLIB || COMPILE_TEST depends on SND + select MEDIA_CEC select I2C_ALGOBIT select VIDEO_ADV7604 select VIDEO_ADV7511
drivers/media/pci/cobalt/cobalt-driver.c +91 -17
222 lines not on this page · raw message
drivers/media/pci/cobalt/cobalt-driver.h +2 -0
@@ -31,6 +31,7 @@#include <linux/workqueue.h> #include <linux/mutex.h> +#include <media/cec.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h>
@@ -223,6 +224,7 @@ struct cobalt_stream {struct list_head bufs;struct i2c_adapter *i2c_adap;struct v4l2_subdev *sd; +struct cec_adapter *cec_adap;struct mutex lock;spinlock_t irqlock;struct v4l2_dv_timings timings;
drivers/media/pci/cobalt/cobalt-irq.c +3 -0
@@ -234,6 +234,9 @@ void cobalt_irq_log_status(struct cobalt *cobalt)u32 mask;int i; +cobalt_info ("irq: edge=%08x mask=%08x\n" , +cobalt_read_bar1 (cobalt,COBALT_SYS_STAT_EDGE ), +cobalt_read_bar1 (cobalt,COBALT_SYS_STAT_MASK ));cobalt_info ("irq: adv1=%u adv2=%u advout=%u none=%u full=%u\n" , cobalt->irq_adv1, cobalt->irq_adv2, cobalt->irq_advout, cobalt->irq_none, cobalt->irq_full_fifo);
drivers/media/pci/cobalt/cobalt-v4l2.c +117 -9
181 lines not on this page · raw message
drivers/media/pci/cobalt/cobalt-v4l2.h +2 -0
@@ -18,5 +18,7 @@* SOFTWARE. */ +extern const struct cec_adap_ops cobalt_cec_adap_ops; +int cobalt_nodes_register (struct cobalt *cobalt);void cobalt_nodes_unregister (struct cobalt *cobalt);
Signature · 1 line
2.6.2