--- /dev/null
+Freescale i.MX IPUv3
+====================
+
+Required properties:
+- compatible: Should be "fsl,<chip>-ipu"
+- reg: should be register base and length as documented in the
+ datasheet
+- interrupts: Should contain sync interrupt and error interrupt,
+ in this order.
+- #crtc-cells: 1, See below
+
+example:
+
+ipu: ipu@18000000 {
+ #crtc-cells = <1>;
+ compatible = "fsl,imx53-ipu";
+ reg = <0x18000000 0x080000000>;
+ interrupts = <11 10>;
+};
+
+Parallel display support
+========================
+
+Required properties:
+- compatible: Should be "fsl,imx-parallel-display"
+- crtc: the crtc this display is connected to, see below
+Optional properties:
+- interface_pix_fmt: How this display is connected to the
+ crtc. Currently supported types: "rgb24", "rgb565"
+- edid: verbatim EDID data block describing attached display.
+- ddc: phandle describing the i2c bus handling the display data
+ channel
+
+example:
+
+display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ edid = [edid-data];
+ crtc = <&ipu 0>;
+ interface-pix-fmt = "rgb24";
+};
source "drivers/staging/ced1401/Kconfig"
+source "drivers/staging/imx-drm/Kconfig"
+
endif # STAGING
obj-$(CONFIG_ZCACHE2) += ramster/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
+obj-$(CONFIG_DRM_IMX) += imx-drm/
VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, PUINT puiBuffer)
{
B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1));
- stIM_SFHostNotify *pHostInfo = NULL;
+ struct bcm_stim_sfhostnotify *pHostInfo = NULL;
UINT uiSearchRuleIndex = 0;
ULONG ulSFID = 0;
while (u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES) {
u32NumofSFsinMsg--;
- pHostInfo = (stIM_SFHostNotify *)puiBuffer;
+ pHostInfo = (struct bcm_stim_sfhostnotify *)puiBuffer;
puiBuffer = (PUINT)(pHostInfo + 1);
ulSFID = ntohl(pHostInfo->SFID);
#ifndef CNTRL_SIGNALING_INTERFACE_
#define CNTRL_SIGNALING_INTERFACE_
-
-
-
-#define DSA_REQ 11
-#define DSA_RSP 12
-#define DSA_ACK 13
-#define DSC_REQ 14
-#define DSC_RSP 15
-#define DSC_ACK 16
-#define DSD_REQ 17
-#define DSD_RSP 18
-#define DSD_ACK 19
-#define MAX_CLASSIFIERS_IN_SF 4
-
-
-#define MAX_STRING_LEN 20
-#define MAX_PHS_LENGTHS 255
-#define VENDOR_PHS_PARAM_LENGTH 10
-#define MAX_NUM_ACTIVE_BS 10
-#define AUTH_TOKEN_LENGTH 10
-#define NUM_HARQ_CHANNELS 16 //Changed from 10 to 16 to accommodate all HARQ channels
-#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 //Changed the size to 1 byte since we dnt use it
-#define VENDOR_SPECIF_QOS_PARAM 1
-#define VENDOR_PHS_PARAM_LENGTH 10
-#define MBS_CONTENTS_ID_LENGTH 10
-#define GLOBAL_SF_CLASSNAME_LENGTH 6
-
-#define TYPE_OF_SERVICE_LENGTH 3
-#define IP_MASKED_SRC_ADDRESS_LENGTH 32
-#define IP_MASKED_DEST_ADDRESS_LENGTH 32
-#define PROTOCOL_SRC_PORT_RANGE_LENGTH 4
-#define PROTOCOL_DEST_PORT_RANGE_LENGTH 4
-#define ETHERNET_DEST_MAC_ADDR_LENGTH 12
-#define ETHERNET_SRC_MAC_ADDR_LENGTH 12
-#define NUM_ETHERTYPE_BYTES 3
-#define NUM_IPV6_FLOWLABLE_BYTES 3
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////structure Definitions///////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-/// \brief class cCPacketClassificationRule
-struct _stCPacketClassificationRuleSI{
-
- /** 16bit UserPriority Of The Service Flow*/
- B_UINT16 u16UserPriority;
- /** 16bit VLANID Of The Service Flow*/
- B_UINT16 u16VLANID;
- /** 16bit Packet Classification RuleIndex Of The Service Flow*/
- B_UINT16 u16PacketClassificationRuleIndex;
- /** 8bit Classifier Rule Priority Of The Service Flow*/
- B_UINT8 u8ClassifierRulePriority;
- /** Length of IP TypeOfService field*/
- B_UINT8 u8IPTypeOfServiceLength;
- /** 3bytes IP TypeOfService */
- B_UINT8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH];
- /** Protocol used in classification of Service Flow*/
- B_UINT8 u8Protocol;
- /** Length of IP Masked Source Address */
- B_UINT8 u8IPMaskedSourceAddressLength;
- /** IP Masked Source Address used in classification for the Service Flow*/
- B_UINT8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH];
- /** Length of IP Destination Address */
- B_UINT8 u8IPDestinationAddressLength;
- /** IP Destination Address used in classification for the Service Flow*/
- B_UINT8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH];
- /** Length of Protocol Source Port Range */
- B_UINT8 u8ProtocolSourcePortRangeLength;
- /** Protocol Source Port Range used in the Service Flow*/
- B_UINT8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH];
- /** Length of Protocol Dest Port Range */
- B_UINT8 u8ProtocolDestPortRangeLength;
- /** Protocol Dest Port Range used in the Service Flow*/
- B_UINT8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH];
- /** Length of Ethernet Destination MAC Address */
- B_UINT8 u8EthernetDestMacAddressLength;
- /** Ethernet Destination MAC Address used in classification of the Service Flow*/
- B_UINT8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH];
- /** Length of Ethernet Source MAC Address */
- B_UINT8 u8EthernetSourceMACAddressLength;
- /** Ethernet Source MAC Address used in classification of the Service Flow*/
- B_UINT8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH];
- /** Length of Ethertype */
- B_UINT8 u8EthertypeLength;
- /** 3bytes Ethertype Of The Service Flow*/
- B_UINT8 u8Ethertype[NUM_ETHERTYPE_BYTES];
- /** 8bit Associated PHSI Of The Service Flow*/
- B_UINT8 u8AssociatedPHSI;
- /** Length of Vendor Specific Classifier Param length Of The Service Flow*/
- B_UINT8 u8VendorSpecificClassifierParamLength;
- /** Vendor Specific Classifier Param Of The Service Flow*/
- B_UINT8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH];
- /** Length Of IPv6 Flow Lable of the Service Flow*/
- B_UINT8 u8IPv6FlowLableLength;
- /** IPv6 Flow Lable Of The Service Flow*/
- B_UINT8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES];
- /** Action associated with the classifier rule*/
- B_UINT8 u8ClassifierActionRule;
- B_UINT16 u16ValidityBitMap;
+#define DSA_REQ 11
+#define DSA_RSP 12
+#define DSA_ACK 13
+#define DSC_REQ 14
+#define DSC_RSP 15
+#define DSC_ACK 16
+#define DSD_REQ 17
+#define DSD_RSP 18
+#define DSD_ACK 19
+#define MAX_CLASSIFIERS_IN_SF 4
+
+#define MAX_STRING_LEN 20
+#define MAX_PHS_LENGTHS 255
+#define VENDOR_PHS_PARAM_LENGTH 10
+#define MAX_NUM_ACTIVE_BS 10
+#define AUTH_TOKEN_LENGTH 10
+#define NUM_HARQ_CHANNELS 16 /* Changed from 10 to 16 to accommodate all HARQ channels */
+#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 /* Changed the size to 1 byte since we dnt use it */
+#define VENDOR_SPECIF_QOS_PARAM 1
+#define VENDOR_PHS_PARAM_LENGTH 10
+#define MBS_CONTENTS_ID_LENGTH 10
+#define GLOBAL_SF_CLASSNAME_LENGTH 6
+
+#define TYPE_OF_SERVICE_LENGTH 3
+#define IP_MASKED_SRC_ADDRESS_LENGTH 32
+#define IP_MASKED_DEST_ADDRESS_LENGTH 32
+#define PROTOCOL_SRC_PORT_RANGE_LENGTH 4
+#define PROTOCOL_DEST_PORT_RANGE_LENGTH 4
+#define ETHERNET_DEST_MAC_ADDR_LENGTH 12
+#define ETHERNET_SRC_MAC_ADDR_LENGTH 12
+#define NUM_ETHERTYPE_BYTES 3
+#define NUM_IPV6_FLOWLABLE_BYTES 3
+
+/*
+ * structure Definitions
+ *
+ * brief class cCPacketClassificationRule
+ */
+struct _stCPacketClassificationRuleSI {
+ /* 16bit UserPriority Of The Service Flow */
+ B_UINT16 u16UserPriority;
+ /* 16bit VLANID Of The Service Flow */
+ B_UINT16 u16VLANID;
+ /* 16bit Packet Classification RuleIndex Of The Service Flow */
+ B_UINT16 u16PacketClassificationRuleIndex;
+ /* 8bit Classifier Rule Priority Of The Service Flow */
+ B_UINT8 u8ClassifierRulePriority;
+ /* Length of IP TypeOfService field */
+ B_UINT8 u8IPTypeOfServiceLength;
+ /* 3bytes IP TypeOfService */
+ B_UINT8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH];
+ /* Protocol used in classification of Service Flow */
+ B_UINT8 u8Protocol;
+ /* Length of IP Masked Source Address */
+ B_UINT8 u8IPMaskedSourceAddressLength;
+ /* IP Masked Source Address used in classification for the Service Flow */
+ B_UINT8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH];
+ /* Length of IP Destination Address */
+ B_UINT8 u8IPDestinationAddressLength;
+ /* IP Destination Address used in classification for the Service Flow */
+ B_UINT8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH];
+ /* Length of Protocol Source Port Range */
+ B_UINT8 u8ProtocolSourcePortRangeLength;
+ /* Protocol Source Port Range used in the Service Flow */
+ B_UINT8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH];
+ /* Length of Protocol Dest Port Range */
+ B_UINT8 u8ProtocolDestPortRangeLength;
+ /* Protocol Dest Port Range used in the Service Flow */
+ B_UINT8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH];
+ /* Length of Ethernet Destination MAC Address */
+ B_UINT8 u8EthernetDestMacAddressLength;
+ /* Ethernet Destination MAC Address used in classification of the Service Flow */
+ B_UINT8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH];
+ /* Length of Ethernet Source MAC Address */
+ B_UINT8 u8EthernetSourceMACAddressLength;
+ /* Ethernet Source MAC Address used in classification of the Service Flow */
+ B_UINT8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH];
+ /* Length of Ethertype */
+ B_UINT8 u8EthertypeLength;
+ /* 3bytes Ethertype Of The Service Flow */
+ B_UINT8 u8Ethertype[NUM_ETHERTYPE_BYTES];
+ /* 8bit Associated PHSI Of The Service Flow */
+ B_UINT8 u8AssociatedPHSI;
+ /* Length of Vendor Specific Classifier Param length Of The Service Flow */
+ B_UINT8 u8VendorSpecificClassifierParamLength;
+ /* Vendor Specific Classifier Param Of The Service Flow */
+ B_UINT8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH];
+ /* Length Of IPv6 Flow Lable of the Service Flow */
+ B_UINT8 u8IPv6FlowLableLength;
+ /* IPv6 Flow Lable Of The Service Flow */
+ B_UINT8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES];
+ /* Action associated with the classifier rule */
+ B_UINT8 u8ClassifierActionRule;
+ B_UINT16 u16ValidityBitMap;
};
-typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI;
+typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI, stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI;
-/// \brief class CPhsRuleSI
+/* brief class CPhsRuleSI */
typedef struct _stPhsRuleSI {
- /** 8bit PHS Index Of The Service Flow*/
- B_UINT8 u8PHSI;
- /** PHSF Length Of The Service Flow*/
- B_UINT8 u8PHSFLength;
- /** String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS*/
- B_UINT8 u8PHSF[MAX_PHS_LENGTHS];
- /** PHSM Length Of The Service Flow*/
- B_UINT8 u8PHSMLength;
- /** PHS Mask for the SF*/
- B_UINT8 u8PHSM[MAX_PHS_LENGTHS];
- /** 8bit Total number of bytes to be suppressed for the Service Flow*/
- B_UINT8 u8PHSS;
- /** 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */
- B_UINT8 u8PHSV;
- /** Vendor Specific PHS param Length Of The Service Flow*/
- B_UINT8 u8VendorSpecificPHSParamsLength;
- /** Vendor Specific PHS param Of The Service Flow*/
- B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
-
- B_UINT8 u8Padding[2];
-}stPhsRuleSI,*pstPhsRuleSI;
+ /* 8bit PHS Index Of The Service Flow */
+ B_UINT8 u8PHSI;
+ /* PHSF Length Of The Service Flow */
+ B_UINT8 u8PHSFLength;
+ /* String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS */
+ B_UINT8 u8PHSF[MAX_PHS_LENGTHS];
+ /* PHSM Length Of The Service Flow */
+ B_UINT8 u8PHSMLength;
+ /* PHS Mask for the SF */
+ B_UINT8 u8PHSM[MAX_PHS_LENGTHS];
+ /* 8bit Total number of bytes to be suppressed for the Service Flow */
+ B_UINT8 u8PHSS;
+ /* 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */
+ B_UINT8 u8PHSV;
+ /* Vendor Specific PHS param Length Of The Service Flow */
+ B_UINT8 u8VendorSpecificPHSParamsLength;
+ /* Vendor Specific PHS param Of The Service Flow */
+ B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
+ B_UINT8 u8Padding[2];
+} stPhsRuleSI, *pstPhsRuleSI;
typedef stPhsRuleSI CPhsRuleSI;
-/// \brief structure cConvergenceSLTypes
-struct _stConvergenceSLTypes{
- /** 8bit Phs Classfier Action Of The Service Flow*/
- B_UINT8 u8ClassfierDSCAction;
- /** 8bit Phs DSC Action Of The Service Flow*/
- B_UINT8 u8PhsDSCAction;
- /** 16bit Padding */
- B_UINT8 u8Padding[2];
- /// \brief class cCPacketClassificationRule
- stCPacketClassificationRuleSI cCPacketClassificationRule;
- /// \brief class CPhsRuleSI
- struct _stPhsRuleSI cPhsRule;
+/* brief structure cConvergenceSLTypes */
+struct _stConvergenceSLTypes {
+ /* 8bit Phs Classfier Action Of The Service Flow */
+ B_UINT8 u8ClassfierDSCAction;
+ /* 8bit Phs DSC Action Of The Service Flow */
+ B_UINT8 u8PhsDSCAction;
+ /* 16bit Padding */
+ B_UINT8 u8Padding[2];
+ /* brief class cCPacketClassificationRule */
+ stCPacketClassificationRuleSI cCPacketClassificationRule;
+ /* brief class CPhsRuleSI */
+ struct _stPhsRuleSI cPhsRule;
};
-typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes;
-
-
-/// \brief structure CServiceFlowParamSI
-typedef struct _stServiceFlowParamSI{
-
- /** 32bitSFID Of The Service Flow*/
- B_UINT32 u32SFID;
-
- /** 32bit Maximum Sustained Traffic Rate of the Service Flow*/
- B_UINT32 u32MaxSustainedTrafficRate;
-
- /** 32bit Maximum Traffic Burst allowed for the Service Flow*/
- B_UINT32 u32MaxTrafficBurst;
-
- /** 32bit Minimum Reserved Traffic Rate of the Service Flow*/
- B_UINT32 u32MinReservedTrafficRate;
-
- /** 32bit Tolerated Jitter of the Service Flow*/
- B_UINT32 u32ToleratedJitter;
-
- /** 32bit Maximum Latency of the Service Flow*/
- B_UINT32 u32MaximumLatency;
-
- /** 16bitCID Of The Service Flow*/
- B_UINT16 u16CID;
-
- /** 16bit SAID on which the service flow being set up shall be mapped*/
- B_UINT16 u16TargetSAID;
-
- /** 16bit ARQ window size negotiated*/
- B_UINT16 u16ARQWindowSize;
-
- /** 16bit Total Tx delay incl sending, receiving & processing delays */
- B_UINT16 u16ARQRetryTxTimeOut;
-
- /** 16bit Total Rx delay incl sending, receiving & processing delays */
- B_UINT16 u16ARQRetryRxTimeOut;
-
- /** 16bit ARQ block lifetime */
- B_UINT16 u16ARQBlockLifeTime;
-
- /** 16bit ARQ Sync loss timeout*/
- B_UINT16 u16ARQSyncLossTimeOut;
-
- /** 16bit ARQ Purge timeout */
- B_UINT16 u16ARQRxPurgeTimeOut;
-//TODO::Remove this once we move to a new CORR2 driver
- /// \brief Size of an ARQ block
- B_UINT16 u16ARQBlockSize;
-
-//#endif
- /** 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP*/
- B_UINT16 u16SDUInterArrivalTime;
-
- /** 16bit Specifies the time base for rate measurement */
- B_UINT16 u16TimeBase;
-
- /** 16bit Interval b/w Successive Grant oppurtunities*/
- B_UINT16 u16UnsolicitedGrantInterval;
-
- /** 16bit Interval b/w Successive Polling grant oppurtunities*/
- B_UINT16 u16UnsolicitedPollingInterval;
-
- /** internal var to get the overhead */
- B_UINT16 u16MacOverhead;
-
- /** MBS contents Identifier*/
- B_UINT16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH];
-
- /** MBS contents Identifier length*/
- B_UINT8 u8MBSContentsIDLength;
-
- /** ServiceClassName Length Of The Service Flow*/
- B_UINT8 u8ServiceClassNameLength;
-
- /** 32bytes ServiceClassName Of The Service Flow*/
- B_UINT8 u8ServiceClassName[32];
-
- /** 8bit Indicates whether or not MBS service is requested for this Serivce Flow*/
- B_UINT8 u8MBSService;
-
- /** 8bit QOS Parameter Set specifies proper application of QoS parameters to Provisioned, Admitted and Active sets*/
- B_UINT8 u8QosParamSet;
-
- /** 8bit Traffic Priority Of the Service Flow */
- B_UINT8 u8TrafficPriority;
-
- /** 8bit Uplink Grant Scheduling Type of The Service Flow */
- B_UINT8 u8ServiceFlowSchedulingType;
-
- /** 8bit Request transmission Policy of the Service Flow*/
- B_UINT8 u8RequesttransmissionPolicy;
-
- /** 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */
- B_UINT8 u8FixedLengthVSVariableLengthSDUIndicator;
-
- /** 8bit Length of the SDU for a fixed length SDU service flow*/
- B_UINT8 u8SDUSize;
-
- /** 8bit Indicates whether or not ARQ is requested for this connection*/
- B_UINT8 u8ARQEnable;
-
- /**< 8bit Indicates whether or not data has tobe delivered in order to higher layer*/
- B_UINT8 u8ARQDeliverInOrder;
-
- /** 8bit Receiver ARQ ACK processing time */
- B_UINT8 u8RxARQAckProcessingTime;
-
- /** 8bit Convergence Sublayer Specification Of The Service Flow*/
- B_UINT8 u8CSSpecification;
-
- /** 8 bit Type of data delivery service*/
- B_UINT8 u8TypeOfDataDeliveryService;
-
- /** 8bit Specifies whether a service flow may generate Paging */
- B_UINT8 u8PagingPreference;
-
- /** 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */
- B_UINT8 u8MBSZoneIdentifierassignment;
-
- /** 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode*/
- B_UINT8 u8TrafficIndicationPreference;
-
- /** 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */
- B_UINT8 u8GlobalServicesClassNameLength;
-
- /** 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */
- B_UINT8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH];
-
- /** 8bit Indicates whether or not SN feedback is enabled for the conn */
- B_UINT8 u8SNFeedbackEnabled;
-
- /** Indicates the size of the Fragment Sequence Number for the connection */
- B_UINT8 u8FSNSize;
-
- /** 8bit Number of CIDs in active BS list */
- B_UINT8 u8CIDAllocation4activeBSsLength;
-
- /** CIDs of BS in the active list */
- B_UINT8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS];
-
- /** Specifies if PDU extended subheader should be applied on every PDU on this conn*/
- B_UINT8 u8PDUSNExtendedSubheader4HarqReordering;
-
- /** 8bit Specifies whether the connection uses HARQ or not */
- B_UINT8 u8HARQServiceFlows;
-
- /** Specifies the length of Authorization token*/
- B_UINT8 u8AuthTokenLength;
-
- /** Specifies the Authorization token*/
- B_UINT8 u8AuthToken[AUTH_TOKEN_LENGTH];
-
- /** specifes Number of HARQ channels used to carry data length*/
- B_UINT8 u8HarqChannelMappingLength;
-
- /** specifes HARQ channels used to carry data*/
- B_UINT8 u8HARQChannelMapping[NUM_HARQ_CHANNELS];
-
- /** 8bit Length of Vendor Specific QoS Params */
- B_UINT8 u8VendorSpecificQoSParamLength;
-
- /** 1byte Vendor Specific QoS Param Of The Service Flow*/
- B_UINT8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM];
-
- // indicates total classifiers in the SF
- B_UINT8 u8TotalClassifiers; /**< Total number of valid classifiers*/
- B_UINT8 bValid; /**< Validity flag */
- B_UINT8 u8Padding; /**< Padding byte*/
-
-/**
-Structure for Convergence SubLayer Types with a maximum of 4 classifiers
-*/
- stConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
+typedef struct _stConvergenceSLTypes stConvergenceSLTypes, CConvergenceSLTypes, *pstConvergenceSLTypes;
+
+/* brief structure CServiceFlowParamSI */
+typedef struct _stServiceFlowParamSI {
+ /* 32bitSFID Of The Service Flow */
+ B_UINT32 u32SFID;
+ /* 32bit Maximum Sustained Traffic Rate of the Service Flow */
+ B_UINT32 u32MaxSustainedTrafficRate;
+ /* 32bit Maximum Traffic Burst allowed for the Service Flow */
+ B_UINT32 u32MaxTrafficBurst;
+ /* 32bit Minimum Reserved Traffic Rate of the Service Flow */
+ B_UINT32 u32MinReservedTrafficRate;
+ /* 32bit Tolerated Jitter of the Service Flow */
+ B_UINT32 u32ToleratedJitter;
+ /* 32bit Maximum Latency of the Service Flow */
+ B_UINT32 u32MaximumLatency;
+ /* 16bitCID Of The Service Flow */
+ B_UINT16 u16CID;
+ /* 16bit SAID on which the service flow being set up shall be mapped */
+ B_UINT16 u16TargetSAID;
+ /* 16bit ARQ window size negotiated */
+ B_UINT16 u16ARQWindowSize;
+ /* 16bit Total Tx delay incl sending, receiving & processing delays */
+ B_UINT16 u16ARQRetryTxTimeOut;
+ /* 16bit Total Rx delay incl sending, receiving & processing delays */
+ B_UINT16 u16ARQRetryRxTimeOut;
+ /* 16bit ARQ block lifetime */
+ B_UINT16 u16ARQBlockLifeTime;
+ /* 16bit ARQ Sync loss timeout */
+ B_UINT16 u16ARQSyncLossTimeOut;
+ /* 16bit ARQ Purge timeout */
+ B_UINT16 u16ARQRxPurgeTimeOut;
+ /* TODO::Remove this once we move to a new CORR2 driver
+ * brief Size of an ARQ block
+ */
+ B_UINT16 u16ARQBlockSize;
+ /* #endif */
+ /* 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP */
+ B_UINT16 u16SDUInterArrivalTime;
+ /* 16bit Specifies the time base for rate measurement */
+ B_UINT16 u16TimeBase;
+ /* 16bit Interval b/w Successive Grant oppurtunities */
+ B_UINT16 u16UnsolicitedGrantInterval;
+ /* 16bit Interval b/w Successive Polling grant oppurtunities */
+ B_UINT16 u16UnsolicitedPollingInterval;
+ /* internal var to get the overhead */
+ B_UINT16 u16MacOverhead;
+ /* MBS contents Identifier */
+ B_UINT16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH];
+ /* MBS contents Identifier length */
+ B_UINT8 u8MBSContentsIDLength;
+ /* ServiceClassName Length Of The Service Flow */
+ B_UINT8 u8ServiceClassNameLength;
+ /* 32bytes ServiceClassName Of The Service Flow */
+ B_UINT8 u8ServiceClassName[32];
+ /* 8bit Indicates whether or not MBS service is requested for this Serivce Flow */
+ B_UINT8 u8MBSService;
+ /* 8bit QOS Parameter Set specifies proper application of QoS parameters to Provisioned, Admitted and Active sets */
+ B_UINT8 u8QosParamSet;
+ /* 8bit Traffic Priority Of the Service Flow */
+ B_UINT8 u8TrafficPriority;
+ /* 8bit Uplink Grant Scheduling Type of The Service Flow */
+ B_UINT8 u8ServiceFlowSchedulingType;
+ /* 8bit Request transmission Policy of the Service Flow */
+ B_UINT8 u8RequesttransmissionPolicy;
+ /* 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */
+ B_UINT8 u8FixedLengthVSVariableLengthSDUIndicator;
+ /* 8bit Length of the SDU for a fixed length SDU service flow */
+ B_UINT8 u8SDUSize;
+ /* 8bit Indicates whether or not ARQ is requested for this connection */
+ B_UINT8 u8ARQEnable;
+ /* < 8bit Indicates whether or not data has tobe delivered in order to higher layer */
+ B_UINT8 u8ARQDeliverInOrder;
+ /* 8bit Receiver ARQ ACK processing time */
+ B_UINT8 u8RxARQAckProcessingTime;
+ /* 8bit Convergence Sublayer Specification Of The Service Flow */
+ B_UINT8 u8CSSpecification;
+ /* 8 bit Type of data delivery service */
+ B_UINT8 u8TypeOfDataDeliveryService;
+ /* 8bit Specifies whether a service flow may generate Paging */
+ B_UINT8 u8PagingPreference;
+ /* 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */
+ B_UINT8 u8MBSZoneIdentifierassignment;
+ /* 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode */
+ B_UINT8 u8TrafficIndicationPreference;
+ /* 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */
+ B_UINT8 u8GlobalServicesClassNameLength;
+ /* 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */
+ B_UINT8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH];
+ /* 8bit Indicates whether or not SN feedback is enabled for the conn */
+ B_UINT8 u8SNFeedbackEnabled;
+ /* Indicates the size of the Fragment Sequence Number for the connection */
+ B_UINT8 u8FSNSize;
+ /* 8bit Number of CIDs in active BS list */
+ B_UINT8 u8CIDAllocation4activeBSsLength;
+ /* CIDs of BS in the active list */
+ B_UINT8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS];
+ /* Specifies if PDU extended subheader should be applied on every PDU on this conn */
+ B_UINT8 u8PDUSNExtendedSubheader4HarqReordering;
+ /* 8bit Specifies whether the connection uses HARQ or not */
+ B_UINT8 u8HARQServiceFlows;
+ /* Specifies the length of Authorization token */
+ B_UINT8 u8AuthTokenLength;
+ /* Specifies the Authorization token */
+ B_UINT8 u8AuthToken[AUTH_TOKEN_LENGTH];
+ /* specifes Number of HARQ channels used to carry data length */
+ B_UINT8 u8HarqChannelMappingLength;
+ /* specifes HARQ channels used to carry data */
+ B_UINT8 u8HARQChannelMapping[NUM_HARQ_CHANNELS];
+ /* 8bit Length of Vendor Specific QoS Params */
+ B_UINT8 u8VendorSpecificQoSParamLength;
+ /* 1byte Vendor Specific QoS Param Of The Service Flow */
+ B_UINT8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM];
+ /* indicates total classifiers in the SF */
+ B_UINT8 u8TotalClassifiers; /* < Total number of valid classifiers */
+ B_UINT8 bValid; /* < Validity flag */
+ B_UINT8 u8Padding; /* < Padding byte */
+/*
+ * Structure for Convergence SubLayer Types with a maximum of 4 classifiers
+ */
+ stConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
} stServiceFlowParamSI, *pstServiceFlowParamSI;
typedef stServiceFlowParamSI CServiceFlowParamSI;
-/**
-structure stLocalSFAddRequest
-*/
-typedef struct _stLocalSFAddRequest{
-
- B_UINT8 u8Type; /**< Type*/
- B_UINT8 eConnectionDir; /**< Connection direction*/
- /// \brief 16 bit TID
- B_UINT16 u16TID; /**< 16bit TID*/
- /// \brief 16bitCID
- B_UINT16 u16CID; /**< 16bit CID*/
- /// \brief 16bitVCID
- B_UINT16 u16VCID; /**< 16bit VCID*/
- /// \brief structure ParameterSet
-
- stServiceFlowParamSI *psfParameterSet; /**< structure ParameterSet*/
-
-}stLocalSFAddRequest, *pstLocalSFAddRequest;
-
-
-/**
-structure stLocalSFAddIndication
-*/
-typedef struct _stLocalSFAddIndication{
-
- B_UINT8 u8Type; /**< Type*/
- B_UINT8 eConnectionDir; /**< Connection Direction*/
- /// \brief 16 bit TID
- B_UINT16 u16TID; /**< TID*/
- /// \brief 16bitCID
- B_UINT16 u16CID; /**< 16bitCID*/
- /// \brief 16bitVCID
- B_UINT16 u16VCID; /**< 16bitVCID*/
-
-
- /// \brief structure AuthorizedSet
- /// \brief structure AuthorizedSet
- stServiceFlowParamSI *psfAuthorizedSet; /**< AuthorizedSet of type stServiceFlowParamSI*/
- /// \brief structure AdmittedSet
- stServiceFlowParamSI *psfAdmittedSet; /**< AdmittedSet of type stServiceFlowParamSI*/
- /// \brief structure ActiveSet
- stServiceFlowParamSI *psfActiveSet; /**< sfActiveSet of type stServiceFlowParamSI*/
- B_UINT8 u8CC; /**< Confirmation Code*/
- B_UINT8 u8Padd; /**< 8-bit Padding */
-
- B_UINT16 u16Padd; /**< 16 bit Padding */
-
-}stLocalSFAddIndication;
-
+/*
+ * structure stLocalSFAddRequest
+ */
+typedef struct _stLocalSFAddRequest {
+ B_UINT8 u8Type; /* < Type */
+ B_UINT8 eConnectionDir; /* < Connection direction */
+ /* brief 16 bit TID */
+ B_UINT16 u16TID; /* < 16bit TID */
+ /* brief 16bitCID */
+ B_UINT16 u16CID; /* < 16bit CID */
+ /* brief 16bitVCID */
+ B_UINT16 u16VCID; /* < 16bit VCID */
+ /* brief structure ParameterSet */
+ stServiceFlowParamSI *psfParameterSet; /* < structure ParameterSet */
+
+} stLocalSFAddRequest, *pstLocalSFAddRequest;
+
+/*
+ * structure stLocalSFAddIndication
+ */
+typedef struct _stLocalSFAddIndication {
+ B_UINT8 u8Type; /* < Type */
+ B_UINT8 eConnectionDir; /* < Connection Direction */
+ /* brief 16 bit TID */
+ B_UINT16 u16TID; /* < TID */
+ /* brief 16bitCID */
+ B_UINT16 u16CID; /* < 16bitCID */
+ /* brief 16bitVCID */
+ B_UINT16 u16VCID; /* < 16bitVCID */
+ /* brief structure AuthorizedSet */
+ /* brief structure AuthorizedSet */
+ stServiceFlowParamSI *psfAuthorizedSet; /* < AuthorizedSet of type stServiceFlowParamSI */
+ /* brief structure AdmittedSet */
+ stServiceFlowParamSI *psfAdmittedSet; /* < AdmittedSet of type stServiceFlowParamSI */
+ /* brief structure ActiveSet */
+ stServiceFlowParamSI *psfActiveSet; /* < sfActiveSet of type stServiceFlowParamSI */
+ B_UINT8 u8CC; /* <Confirmation Code */
+ B_UINT8 u8Padd; /* < 8-bit Padding */
+ B_UINT16 u16Padd; /* < 16 bit Padding */
+
+} stLocalSFAddIndication;
typedef struct _stLocalSFAddIndication *pstLocalSFAddIndication;
-/**
-structure stLocalSFChangeRequest is same as structure stLocalSFAddIndication
-*/
+/*
+ * structure stLocalSFChangeRequest is same as structure stLocalSFAddIndication
+ */
typedef struct _stLocalSFAddIndication stLocalSFChangeRequest, *pstLocalSFChangeRequest;
-/**
-structure stLocalSFChangeIndication is same as structure stLocalSFAddIndication
-*/
+/*
+ * structure stLocalSFChangeIndication is same as structure stLocalSFAddIndication
+ */
typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFChangeIndication;
-/**
-structure stLocalSFDeleteRequest
-*/
-typedef struct _stLocalSFDeleteRequest{
- B_UINT8 u8Type; /**< Type*/
- B_UINT8 u8Padding; /**< Padding byte*/
- B_UINT16 u16TID; /**< TID*/
- /// \brief 32bitSFID
- B_UINT32 u32SFID; /**< SFID*/
-}stLocalSFDeleteRequest, *pstLocalSFDeleteRequest;
-
-/**
-structure stLocalSFDeleteIndication
-*/
-typedef struct stLocalSFDeleteIndication{
- B_UINT8 u8Type; /**< Type */
- B_UINT8 u8Padding; /**< Padding */
- B_UINT16 u16TID; /**< TID */
- /// \brief 16bitCID
- B_UINT16 u16CID; /**< CID */
- /// \brief 16bitVCID
- B_UINT16 u16VCID; /**< VCID */
- /// \brief 32bitSFID
- B_UINT32 u32SFID; /**< SFID */
- /// \brief 8bit Confirmation code
- B_UINT8 u8ConfirmationCode; /**< Confirmation code */
- B_UINT8 u8Padding1[3]; /**< 3 byte Padding */
-}stLocalSFDeleteIndication;
-
-typedef struct _stIM_SFHostNotify
-{
- B_UINT32 SFID; //SFID of the service flow
- B_UINT16 newCID; //the new/changed CID
- B_UINT16 VCID; //Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid
- B_UINT8 RetainSF; //Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete
- B_UINT8 QoSParamSet; //QoS paramset of the retained SF
- B_UINT16 u16reserved; //For byte alignment
-
-} stIM_SFHostNotify;
+/*
+ * structure stLocalSFDeleteRequest
+ */
+typedef struct _stLocalSFDeleteRequest {
+ B_UINT8 u8Type; /* < Type */
+ B_UINT8 u8Padding; /* < Padding byte */
+ B_UINT16 u16TID; /* < TID */
+ /* brief 32bitSFID */
+ B_UINT32 u32SFID; /* < SFID */
+} stLocalSFDeleteRequest, *pstLocalSFDeleteRequest;
+
+/*
+ * structure stLocalSFDeleteIndication
+ */
+typedef struct stLocalSFDeleteIndication {
+ B_UINT8 u8Type; /* < Type */
+ B_UINT8 u8Padding; /* < Padding */
+ B_UINT16 u16TID; /* < TID */
+ /* brief 16bitCID */
+ B_UINT16 u16CID; /* < CID */
+ /* brief 16bitVCID */
+ B_UINT16 u16VCID; /* < VCID */
+ /* brief 32bitSFID */
+ B_UINT32 u32SFID; /* < SFID */
+ /* brief 8bit Confirmation code */
+ B_UINT8 u8ConfirmationCode; /* < Confirmation code */
+ B_UINT8 u8Padding1[3]; /* < 3 byte Padding */
+} stLocalSFDeleteIndication;
+
+struct bcm_stim_sfhostnotify {
+ B_UINT32 SFID; /* SFID of the service flow */
+ B_UINT16 newCID; /* the new/changed CID */
+ B_UINT16 VCID; /* Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid */
+ B_UINT8 RetainSF; /* Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete */
+ B_UINT8 QoSParamSet; /* QoS paramset of the retained SF */
+ B_UINT16 u16reserved; /* For byte alignment */
+};
#endif
int WaitEvent(DEVICE_EXTENSION * pdx, int nArea, int msTimeOut)
{
int iReturn;
- if ((unsigned)nArea > MAX_TRANSAREAS)
+ if ((unsigned)nArea >= MAX_TRANSAREAS)
return U14ERR_BADAREA;
else {
int iWait;
int TestEvent(DEVICE_EXTENSION * pdx, int nArea)
{
int iReturn;
- if ((unsigned)nArea > MAX_TRANSAREAS)
+ if ((unsigned)nArea >= MAX_TRANSAREAS)
iReturn = U14ERR_BADAREA;
else {
TRANSAREA *pTA = &pdx->rTransDef[nArea];
return res;
}
-static ssize_t ced_read(struct file *file, char *buffer, size_t count,
- loff_t * ppos)
-{
- DEVICE_EXTENSION *pdx = file->private_data;
- dev_err(&pdx->interface->dev, "%s called: use ioctl for cedusb",
- __func__);
- return 0; // as we do not do reads this way
-}
-
-static ssize_t ced_write(struct file *file, const char *user_buffer,
- size_t count, loff_t * ppos)
-{
- DEVICE_EXTENSION *pdx = file->private_data;
- dev_err(&pdx->interface->dev, "%s called: use ioctl for cedusb",
- __func__);
- return 0;
-}
-
/***************************************************************************
** CanAcceptIoRequests
** If the device is removed, interface is set NULL. We also clear our pointer
static const struct file_operations ced_fops = {
.owner = THIS_MODULE,
- .read = ced_read,
- .write = ced_write,
.open = ced_open,
.release = ced_release,
.flush = ced_flush,
.supports_autosuspend = 1,
};
-static int __init usb_skel_init(void)
-{
- /* register this driver with the USB subsystem */
- return usb_register(&ced_driver);
-}
-
-static void __exit usb_skel_exit(void)
-{
- /* deregister this driver with the USB subsystem */
- usb_deregister(&ced_driver);
-}
-
-module_init(usb_skel_init);
-module_exit(usb_skel_exit);
-
+module_usb_driver(ced_driver);
MODULE_LICENSE("GPL");
/* subdevice types */
- enum comedi_subdevice_type {
- COMEDI_SUBD_UNUSED, /* unused by driver */
- COMEDI_SUBD_AI, /* analog input */
- COMEDI_SUBD_AO, /* analog output */
- COMEDI_SUBD_DI, /* digital input */
- COMEDI_SUBD_DO, /* digital output */
- COMEDI_SUBD_DIO, /* digital input/output */
- COMEDI_SUBD_COUNTER, /* counter */
- COMEDI_SUBD_TIMER, /* timer */
- COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */
- COMEDI_SUBD_CALIB, /* calibration DACs */
- COMEDI_SUBD_PROC, /* processor, DSP */
- COMEDI_SUBD_SERIAL, /* serial IO */
- COMEDI_SUBD_PWM /* PWM */
- };
+enum comedi_subdevice_type {
+ COMEDI_SUBD_UNUSED, /* unused by driver */
+ COMEDI_SUBD_AI, /* analog input */
+ COMEDI_SUBD_AO, /* analog output */
+ COMEDI_SUBD_DI, /* digital input */
+ COMEDI_SUBD_DO, /* digital output */
+ COMEDI_SUBD_DIO, /* digital input/output */
+ COMEDI_SUBD_COUNTER, /* counter */
+ COMEDI_SUBD_TIMER, /* timer */
+ COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */
+ COMEDI_SUBD_CALIB, /* calibration DACs */
+ COMEDI_SUBD_PROC, /* processor, DSP */
+ COMEDI_SUBD_SERIAL, /* serial IO */
+ COMEDI_SUBD_PWM /* PWM */
+};
/* configuration instructions */
- enum configuration_ids {
- INSN_CONFIG_DIO_INPUT = 0,
- INSN_CONFIG_DIO_OUTPUT = 1,
- INSN_CONFIG_DIO_OPENDRAIN = 2,
- INSN_CONFIG_ANALOG_TRIG = 16,
+enum configuration_ids {
+ INSN_CONFIG_DIO_INPUT = 0,
+ INSN_CONFIG_DIO_OUTPUT = 1,
+ INSN_CONFIG_DIO_OPENDRAIN = 2,
+ INSN_CONFIG_ANALOG_TRIG = 16,
/* INSN_CONFIG_WAVEFORM = 17, */
/* INSN_CONFIG_TRIG = 18, */
/* INSN_CONFIG_COUNTER = 19, */
- INSN_CONFIG_ALT_SOURCE = 20,
- INSN_CONFIG_DIGITAL_TRIG = 21,
- INSN_CONFIG_BLOCK_SIZE = 22,
- INSN_CONFIG_TIMER_1 = 23,
- INSN_CONFIG_FILTER = 24,
- INSN_CONFIG_CHANGE_NOTIFY = 25,
-
- /*ALPHA*/ INSN_CONFIG_SERIAL_CLOCK = 26,
- INSN_CONFIG_BIDIRECTIONAL_DATA = 27,
- INSN_CONFIG_DIO_QUERY = 28,
- INSN_CONFIG_PWM_OUTPUT = 29,
- INSN_CONFIG_GET_PWM_OUTPUT = 30,
- INSN_CONFIG_ARM = 31,
- INSN_CONFIG_DISARM = 32,
- INSN_CONFIG_GET_COUNTER_STATUS = 33,
- INSN_CONFIG_RESET = 34,
- /* Use CTR as single pulsegenerator */
- INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001,
- /* Use CTR as pulsetraingenerator */
- INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002,
- /* Use the counter as encoder */
- INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003,
- INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */
- INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */
- /* Set master clock source */
- INSN_CONFIG_SET_CLOCK_SRC = 2003,
- INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */
- INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */
- /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */
- /* Get size in bytes of subdevice's on-board fifos used during
- * streaming input/output */
- INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,
- INSN_CONFIG_SET_COUNTER_MODE = 4097,
- /* INSN_CONFIG_8254_SET_MODE is deprecated */
- INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,
- INSN_CONFIG_8254_READ_STATUS = 4098,
- INSN_CONFIG_SET_ROUTING = 4099,
- INSN_CONFIG_GET_ROUTING = 4109,
-/* PWM */
- INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */
- INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */
- INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */
- /* sets H bridge: duty cycle and sign bit for a relay at the
- * same time */
- INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
- /* gets H bridge data: duty cycle and the sign bit */
- INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
- };
-
- enum comedi_io_direction {
- COMEDI_INPUT = 0,
- COMEDI_OUTPUT = 1,
- COMEDI_OPENDRAIN = 2
- };
-
- enum comedi_support_level {
- COMEDI_UNKNOWN_SUPPORT = 0,
- COMEDI_SUPPORTED,
- COMEDI_UNSUPPORTED
- };
+ INSN_CONFIG_ALT_SOURCE = 20,
+ INSN_CONFIG_DIGITAL_TRIG = 21,
+ INSN_CONFIG_BLOCK_SIZE = 22,
+ INSN_CONFIG_TIMER_1 = 23,
+ INSN_CONFIG_FILTER = 24,
+ INSN_CONFIG_CHANGE_NOTIFY = 25,
+
+ INSN_CONFIG_SERIAL_CLOCK = 26, /*ALPHA*/
+ INSN_CONFIG_BIDIRECTIONAL_DATA = 27,
+ INSN_CONFIG_DIO_QUERY = 28,
+ INSN_CONFIG_PWM_OUTPUT = 29,
+ INSN_CONFIG_GET_PWM_OUTPUT = 30,
+ INSN_CONFIG_ARM = 31,
+ INSN_CONFIG_DISARM = 32,
+ INSN_CONFIG_GET_COUNTER_STATUS = 33,
+ INSN_CONFIG_RESET = 34,
+ /* Use CTR as single pulsegenerator */
+ INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001,
+ /* Use CTR as pulsetraingenerator */
+ INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002,
+ /* Use the counter as encoder */
+ INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003,
+ INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */
+ INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */
+ /* Set master clock source */
+ INSN_CONFIG_SET_CLOCK_SRC = 2003,
+ INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */
+ INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */
+ /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */
+ /* Get size in bytes of subdevice's on-board fifos used during
+ * streaming input/output */
+ INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,
+ INSN_CONFIG_SET_COUNTER_MODE = 4097,
+ /* INSN_CONFIG_8254_SET_MODE is deprecated */
+ INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,
+ INSN_CONFIG_8254_READ_STATUS = 4098,
+ INSN_CONFIG_SET_ROUTING = 4099,
+ INSN_CONFIG_GET_ROUTING = 4109,
+ /* PWM */
+ INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */
+ INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */
+ INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */
+ /* sets H bridge: duty cycle and sign bit for a relay at the
+ * same time */
+ INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
+ /* gets H bridge data: duty cycle and the sign bit */
+ INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
+};
+
+enum comedi_io_direction {
+ COMEDI_INPUT = 0,
+ COMEDI_OUTPUT = 1,
+ COMEDI_OPENDRAIN = 2
+};
+
+enum comedi_support_level {
+ COMEDI_UNKNOWN_SUPPORT = 0,
+ COMEDI_SUPPORTED,
+ COMEDI_UNSUPPORTED
+};
/* ioctls */
/* structures */
- struct comedi_trig {
- unsigned int subdev; /* subdevice */
- unsigned int mode; /* mode */
- unsigned int flags;
- unsigned int n_chan; /* number of channels */
- unsigned int *chanlist; /* channel/range list */
- short *data; /* data list, size depends on subd flags */
- unsigned int n; /* number of scans */
- unsigned int trigsrc;
- unsigned int trigvar;
- unsigned int trigvar1;
- unsigned int data_len;
- unsigned int unused[3];
- };
-
- struct comedi_insn {
- unsigned int insn;
- unsigned int n;
- unsigned int __user *data;
- unsigned int subdev;
- unsigned int chanspec;
- unsigned int unused[3];
- };
-
- struct comedi_insnlist {
- unsigned int n_insns;
- struct comedi_insn __user *insns;
- };
-
- struct comedi_cmd {
- unsigned int subdev;
- unsigned int flags;
-
- unsigned int start_src;
- unsigned int start_arg;
-
- unsigned int scan_begin_src;
- unsigned int scan_begin_arg;
-
- unsigned int convert_src;
- unsigned int convert_arg;
-
- unsigned int scan_end_src;
- unsigned int scan_end_arg;
-
- unsigned int stop_src;
- unsigned int stop_arg;
-
- unsigned int __user *chanlist; /* channel/range list */
- unsigned int chanlist_len;
-
- short __user *data; /* data list, size depends on subd flags */
- unsigned int data_len;
- };
-
- struct comedi_chaninfo {
- unsigned int subdev;
- unsigned int __user *maxdata_list;
- unsigned int __user *flaglist;
- unsigned int __user *rangelist;
- unsigned int unused[4];
- };
-
- struct comedi_rangeinfo {
- unsigned int range_type;
- void __user *range_ptr;
- };
-
- struct comedi_krange {
- int min; /* fixed point, multiply by 1e-6 */
- int max; /* fixed point, multiply by 1e-6 */
- unsigned int flags;
- };
-
- struct comedi_subdinfo {
- unsigned int type;
- unsigned int n_chan;
- unsigned int subd_flags;
- unsigned int timer_type;
- unsigned int len_chanlist;
- unsigned int maxdata;
- unsigned int flags; /* channel flags */
- unsigned int range_type; /* lookup in kernel */
- unsigned int settling_time_0;
- /* see support_level enum for values */
- unsigned insn_bits_support;
- unsigned int unused[8];
- };
-
- struct comedi_devinfo {
- unsigned int version_code;
- unsigned int n_subdevs;
- char driver_name[COMEDI_NAMELEN];
- char board_name[COMEDI_NAMELEN];
- int read_subdevice;
- int write_subdevice;
- int unused[30];
- };
-
- struct comedi_devconfig {
- char board_name[COMEDI_NAMELEN];
- int options[COMEDI_NDEVCONFOPTS];
- };
-
- struct comedi_bufconfig {
- unsigned int subdevice;
- unsigned int flags;
-
- unsigned int maximum_size;
- unsigned int size;
-
- unsigned int unused[4];
- };
-
- struct comedi_bufinfo {
- unsigned int subdevice;
- unsigned int bytes_read;
-
- unsigned int buf_write_ptr;
- unsigned int buf_read_ptr;
- unsigned int buf_write_count;
- unsigned int buf_read_count;
-
- unsigned int bytes_written;
-
- unsigned int unused[4];
- };
+struct comedi_trig {
+ unsigned int subdev; /* subdevice */
+ unsigned int mode; /* mode */
+ unsigned int flags;
+ unsigned int n_chan; /* number of channels */
+ unsigned int *chanlist; /* channel/range list */
+ short *data; /* data list, size depends on subd flags */
+ unsigned int n; /* number of scans */
+ unsigned int trigsrc;
+ unsigned int trigvar;
+ unsigned int trigvar1;
+ unsigned int data_len;
+ unsigned int unused[3];
+};
+
+struct comedi_insn {
+ unsigned int insn;
+ unsigned int n;
+ unsigned int __user *data;
+ unsigned int subdev;
+ unsigned int chanspec;
+ unsigned int unused[3];
+};
+
+struct comedi_insnlist {
+ unsigned int n_insns;
+ struct comedi_insn __user *insns;
+};
+
+struct comedi_cmd {
+ unsigned int subdev;
+ unsigned int flags;
+
+ unsigned int start_src;
+ unsigned int start_arg;
+
+ unsigned int scan_begin_src;
+ unsigned int scan_begin_arg;
+
+ unsigned int convert_src;
+ unsigned int convert_arg;
+
+ unsigned int scan_end_src;
+ unsigned int scan_end_arg;
+
+ unsigned int stop_src;
+ unsigned int stop_arg;
+
+ unsigned int *chanlist; /* channel/range list */
+ unsigned int chanlist_len;
+
+ short __user *data; /* data list, size depends on subd flags */
+ unsigned int data_len;
+};
+
+struct comedi_chaninfo {
+ unsigned int subdev;
+ unsigned int __user *maxdata_list;
+ unsigned int __user *flaglist;
+ unsigned int __user *rangelist;
+ unsigned int unused[4];
+};
+
+struct comedi_rangeinfo {
+ unsigned int range_type;
+ void __user *range_ptr;
+};
+
+struct comedi_krange {
+ int min; /* fixed point, multiply by 1e-6 */
+ int max; /* fixed point, multiply by 1e-6 */
+ unsigned int flags;
+};
+
+struct comedi_subdinfo {
+ unsigned int type;
+ unsigned int n_chan;
+ unsigned int subd_flags;
+ unsigned int timer_type;
+ unsigned int len_chanlist;
+ unsigned int maxdata;
+ unsigned int flags; /* channel flags */
+ unsigned int range_type; /* lookup in kernel */
+ unsigned int settling_time_0;
+ /* see support_level enum for values */
+ unsigned insn_bits_support;
+ unsigned int unused[8];
+};
+
+struct comedi_devinfo {
+ unsigned int version_code;
+ unsigned int n_subdevs;
+ char driver_name[COMEDI_NAMELEN];
+ char board_name[COMEDI_NAMELEN];
+ int read_subdevice;
+ int write_subdevice;
+ int unused[30];
+};
+
+struct comedi_devconfig {
+ char board_name[COMEDI_NAMELEN];
+ int options[COMEDI_NDEVCONFOPTS];
+};
+
+struct comedi_bufconfig {
+ unsigned int subdevice;
+ unsigned int flags;
+
+ unsigned int maximum_size;
+ unsigned int size;
+
+ unsigned int unused[4];
+};
+
+struct comedi_bufinfo {
+ unsigned int subdevice;
+ unsigned int bytes_read;
+
+ unsigned int buf_write_ptr;
+ unsigned int buf_read_ptr;
+ unsigned int buf_write_count;
+ unsigned int buf_read_count;
+
+ unsigned int bytes_written;
+
+ unsigned int unused[4];
+};
/* range stuff */
*/
- enum i8254_mode {
- I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */
- I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */
- I8254_MODE2 = (2 << 1), /* Rate generator */
- I8254_MODE3 = (3 << 1), /* Square wave mode */
- I8254_MODE4 = (4 << 1), /* Software triggered strobe */
- I8254_MODE5 = (5 << 1), /* Hardware triggered strobe
- * (retriggerable) */
- I8254_BCD = 1, /* use binary-coded decimal instead of binary
+enum i8254_mode {
+ I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */
+ I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */
+ I8254_MODE2 = (2 << 1), /* Rate generator */
+ I8254_MODE3 = (3 << 1), /* Square wave mode */
+ I8254_MODE4 = (4 << 1), /* Software triggered strobe */
+ I8254_MODE5 = (5 << 1), /* Hardware triggered strobe
+ * (retriggerable) */
+ I8254_BCD = 1, /* use binary-coded decimal instead of binary
* (pretty useless) */
- I8254_BINARY = 0
- };
-
- static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel)
- {
- if (pfi_channel < 10)
- return 0x1 + pfi_channel;
- else
- return 0xb + pfi_channel;
- }
-
- static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel)
- {
- if (rtsi_channel < 7)
- return 0xb + rtsi_channel;
- else
- return 0x1b;
- }
+ I8254_BINARY = 0
+};
+
+static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel)
+{
+ if (pfi_channel < 10)
+ return 0x1 + pfi_channel;
+ else
+ return 0xb + pfi_channel;
+}
+
+static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel)
+{
+ if (rtsi_channel < 7)
+ return 0xb + rtsi_channel;
+ else
+ return 0x1b;
+}
/* mode bits for NI general-purpose counters, set with
* INSN_CONFIG_SET_COUNTER_MODE */
#define NI_GPCT_COUNTING_MODE_SHIFT 16
#define NI_GPCT_INDEX_PHASE_BITSHIFT 20
#define NI_GPCT_COUNTING_DIRECTION_SHIFT 24
- enum ni_gpct_mode_bits {
- NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4,
- NI_GPCT_EDGE_GATE_MODE_MASK = 0x18,
- NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0,
- NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8,
- NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10,
- NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18,
- NI_GPCT_STOP_MODE_MASK = 0x60,
- NI_GPCT_STOP_ON_GATE_BITS = 0x00,
- NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20,
- NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40,
- NI_GPCT_LOAD_B_SELECT_BIT = 0x80,
- NI_GPCT_OUTPUT_MODE_MASK = 0x300,
- NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100,
- NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200,
- NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300,
- NI_GPCT_HARDWARE_DISARM_MASK = 0xc00,
- NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000,
- NI_GPCT_DISARM_AT_TC_BITS = 0x400,
- NI_GPCT_DISARM_AT_GATE_BITS = 0x800,
- NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00,
- NI_GPCT_LOADING_ON_TC_BIT = 0x1000,
- NI_GPCT_LOADING_ON_GATE_BIT = 0x4000,
- NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_NORMAL_BITS =
- 0x0 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS =
- 0x1 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS =
- 0x2 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS =
- 0x3 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS =
- 0x4 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS =
- 0x6 << NI_GPCT_COUNTING_MODE_SHIFT,
- NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
- NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS =
- 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT,
- NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS =
- 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT,
- NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS =
- 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT,
- NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS =
- 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
- NI_GPCT_INDEX_ENABLE_BIT = 0x400000,
- NI_GPCT_COUNTING_DIRECTION_MASK =
- 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
- NI_GPCT_COUNTING_DIRECTION_DOWN_BITS =
- 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
- NI_GPCT_COUNTING_DIRECTION_UP_BITS =
- 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
- NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS =
- 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
- NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS =
- 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
- NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000,
- NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0,
- NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000,
- NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000,
- NI_GPCT_OR_GATE_BIT = 0x10000000,
- NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000
- };
+enum ni_gpct_mode_bits {
+ NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4,
+ NI_GPCT_EDGE_GATE_MODE_MASK = 0x18,
+ NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0,
+ NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8,
+ NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10,
+ NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18,
+ NI_GPCT_STOP_MODE_MASK = 0x60,
+ NI_GPCT_STOP_ON_GATE_BITS = 0x00,
+ NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20,
+ NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40,
+ NI_GPCT_LOAD_B_SELECT_BIT = 0x80,
+ NI_GPCT_OUTPUT_MODE_MASK = 0x300,
+ NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100,
+ NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200,
+ NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300,
+ NI_GPCT_HARDWARE_DISARM_MASK = 0xc00,
+ NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000,
+ NI_GPCT_DISARM_AT_TC_BITS = 0x400,
+ NI_GPCT_DISARM_AT_GATE_BITS = 0x800,
+ NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00,
+ NI_GPCT_LOADING_ON_TC_BIT = 0x1000,
+ NI_GPCT_LOADING_ON_GATE_BIT = 0x4000,
+ NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_NORMAL_BITS =
+ 0x0 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS =
+ 0x1 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS =
+ 0x2 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS =
+ 0x3 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS =
+ 0x4 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS =
+ 0x6 << NI_GPCT_COUNTING_MODE_SHIFT,
+ NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+ NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS =
+ 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+ NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS =
+ 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+ NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS =
+ 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+ NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS =
+ 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT,
+ NI_GPCT_INDEX_ENABLE_BIT = 0x400000,
+ NI_GPCT_COUNTING_DIRECTION_MASK =
+ 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+ NI_GPCT_COUNTING_DIRECTION_DOWN_BITS =
+ 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+ NI_GPCT_COUNTING_DIRECTION_UP_BITS =
+ 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+ NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS =
+ 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+ NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS =
+ 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT,
+ NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000,
+ NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0,
+ NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000,
+ NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000,
+ NI_GPCT_OR_GATE_BIT = 0x10000000,
+ NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000
+};
/* Bits for setting a clock source with
* INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters. */
- enum ni_gpct_clock_source_bits {
- NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f,
- NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0,
- NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1,
- NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2,
- NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3,
- NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4,
- NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5,
- /* NI 660x-specific */
- NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6,
- NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7,
- NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8,
- NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9,
- NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000,
- NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0,
- /* divide source by 2 */
- NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000,
- /* divide source by 8 */
- NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000,
- NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000
- };
- static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n)
- {
- /* NI 660x-specific */
- return 0x10 + n;
- }
- static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n)
- {
- return 0x18 + n;
- }
- static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n)
- {
- /* no pfi on NI 660x */
- return 0x20 + n;
- }
+enum ni_gpct_clock_source_bits {
+ NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f,
+ NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0,
+ NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1,
+ NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2,
+ NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3,
+ NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4,
+ NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5,
+ /* NI 660x-specific */
+ NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6,
+ NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7,
+ NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8,
+ NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9,
+ NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000,
+ NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0,
+ /* divide source by 2 */
+ NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000,
+ /* divide source by 8 */
+ NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000,
+ NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000
+};
+static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n)
+{
+ /* NI 660x-specific */
+ return 0x10 + n;
+}
+static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n)
+{
+ return 0x18 + n;
+}
+static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n)
+{
+ /* no pfi on NI 660x */
+ return 0x20 + n;
+}
/* Possibilities for setting a gate source with
INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters.
May be bitwise-or'd with CR_EDGE or CR_INVERT. */
- enum ni_gpct_gate_select {
- /* m-series gates */
- NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0,
- NI_GPCT_AI_START2_GATE_SELECT = 0x12,
- NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13,
- NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14,
- NI_GPCT_AI_START1_GATE_SELECT = 0x1c,
- NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d,
- NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e,
- NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f,
- /* more gates for 660x */
- NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100,
- NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101,
- /* more gates for 660x "second gate" */
- NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201,
- NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e,
- /* m-series "second gate" sources are unknown,
- * we should add them here with an offset of 0x300 when
- * known. */
- NI_GPCT_DISABLED_GATE_SELECT = 0x8000,
- };
- static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n)
- {
- return 0x102 + n;
- }
- static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n)
- {
- return NI_USUAL_RTSI_SELECT(n);
- }
- static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n)
- {
- return NI_USUAL_PFI_SELECT(n);
- }
- static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n)
- {
- return 0x202 + n;
- }
+enum ni_gpct_gate_select {
+ /* m-series gates */
+ NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0,
+ NI_GPCT_AI_START2_GATE_SELECT = 0x12,
+ NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13,
+ NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14,
+ NI_GPCT_AI_START1_GATE_SELECT = 0x1c,
+ NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d,
+ NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e,
+ NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f,
+ /* more gates for 660x */
+ NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100,
+ NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101,
+ /* more gates for 660x "second gate" */
+ NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201,
+ NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e,
+ /* m-series "second gate" sources are unknown,
+ * we should add them here with an offset of 0x300 when
+ * known. */
+ NI_GPCT_DISABLED_GATE_SELECT = 0x8000,
+};
+static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n)
+{
+ return 0x102 + n;
+}
+static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n)
+{
+ return NI_USUAL_RTSI_SELECT(n);
+}
+static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n)
+{
+ return NI_USUAL_PFI_SELECT(n);
+}
+static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n)
+{
+ return 0x202 + n;
+}
/* Possibilities for setting a source with
INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */
- enum ni_gpct_other_index {
- NI_GPCT_SOURCE_ENCODER_A,
- NI_GPCT_SOURCE_ENCODER_B,
- NI_GPCT_SOURCE_ENCODER_Z
- };
- enum ni_gpct_other_select {
- /* m-series gates */
- /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */
- NI_GPCT_DISABLED_OTHER_SELECT = 0x8000,
- };
- static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n)
- {
- return NI_USUAL_PFI_SELECT(n);
- }
+enum ni_gpct_other_index {
+ NI_GPCT_SOURCE_ENCODER_A,
+ NI_GPCT_SOURCE_ENCODER_B,
+ NI_GPCT_SOURCE_ENCODER_Z
+};
+enum ni_gpct_other_select {
+ /* m-series gates */
+ /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */
+ NI_GPCT_DISABLED_OTHER_SELECT = 0x8000,
+};
+static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n)
+{
+ return NI_USUAL_PFI_SELECT(n);
+}
/* start sources for ni general-purpose counters for use with
INSN_CONFIG_ARM */
- enum ni_gpct_arm_source {
- NI_GPCT_ARM_IMMEDIATE = 0x0,
- NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter
- * and the adjacent paired
- * counter simultaneously */
- /* NI doesn't document bits for selecting hardware arm triggers.
- * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least
- * significant bits (3 bits for 660x or 5 bits for m-series)
- * through to the hardware. This will at least allow someone to
- * figure out what the bits do later. */
- NI_GPCT_ARM_UNKNOWN = 0x1000,
- };
+enum ni_gpct_arm_source {
+ NI_GPCT_ARM_IMMEDIATE = 0x0,
+ NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter
+ * and the adjacent paired
+ * counter simultaneously */
+ /* NI doesn't document bits for selecting hardware arm triggers.
+ * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least
+ * significant bits (3 bits for 660x or 5 bits for m-series)
+ * through to the hardware. This will at least allow someone to
+ * figure out what the bits do later. */
+ NI_GPCT_ARM_UNKNOWN = 0x1000,
+};
/* digital filtering options for ni 660x for use with INSN_CONFIG_FILTER. */
- enum ni_gpct_filter_select {
- NI_GPCT_FILTER_OFF = 0x0,
- NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1,
- NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2,
- NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3,
- NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4,
- NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5,
- NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6
- };
+enum ni_gpct_filter_select {
+ NI_GPCT_FILTER_OFF = 0x0,
+ NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1,
+ NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2,
+ NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3,
+ NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4,
+ NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5,
+ NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6
+};
/* PFI digital filtering options for ni m-series for use with
* INSN_CONFIG_FILTER. */
- enum ni_pfi_filter_select {
- NI_PFI_FILTER_OFF = 0x0,
- NI_PFI_FILTER_125ns = 0x1,
- NI_PFI_FILTER_6425ns = 0x2,
- NI_PFI_FILTER_2550us = 0x3
- };
+enum ni_pfi_filter_select {
+ NI_PFI_FILTER_OFF = 0x0,
+ NI_PFI_FILTER_125ns = 0x1,
+ NI_PFI_FILTER_6425ns = 0x2,
+ NI_PFI_FILTER_2550us = 0x3
+};
/* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */
- enum ni_mio_clock_source {
- NI_MIO_INTERNAL_CLOCK = 0,
- NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use
- NI_MIO_PLL_RTSI_CLOCK() */
- /* the NI_MIO_PLL_* sources are m-series only */
- NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
- NI_MIO_PLL_PXI10_CLOCK = 3,
- NI_MIO_PLL_RTSI0_CLOCK = 4
- };
- static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel)
- {
- return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel;
- }
+enum ni_mio_clock_source {
+ NI_MIO_INTERNAL_CLOCK = 0,
+ NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use
+ NI_MIO_PLL_RTSI_CLOCK() */
+ /* the NI_MIO_PLL_* sources are m-series only */
+ NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
+ NI_MIO_PLL_PXI10_CLOCK = 3,
+ NI_MIO_PLL_RTSI0_CLOCK = 4
+};
+static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel)
+{
+ return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel;
+}
/* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING.
The numbers assigned are not arbitrary, they correspond to the bits required
to program the board. */
- enum ni_rtsi_routing {
- NI_RTSI_OUTPUT_ADR_START1 = 0,
- NI_RTSI_OUTPUT_ADR_START2 = 1,
- NI_RTSI_OUTPUT_SCLKG = 2,
- NI_RTSI_OUTPUT_DACUPDN = 3,
- NI_RTSI_OUTPUT_DA_START1 = 4,
- NI_RTSI_OUTPUT_G_SRC0 = 5,
- NI_RTSI_OUTPUT_G_GATE0 = 6,
- NI_RTSI_OUTPUT_RGOUT0 = 7,
- NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
- NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI
- * clock on line 7 */
- };
- static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)
- {
- return NI_RTSI_OUTPUT_RTSI_BRD_0 + n;
- }
+enum ni_rtsi_routing {
+ NI_RTSI_OUTPUT_ADR_START1 = 0,
+ NI_RTSI_OUTPUT_ADR_START2 = 1,
+ NI_RTSI_OUTPUT_SCLKG = 2,
+ NI_RTSI_OUTPUT_DACUPDN = 3,
+ NI_RTSI_OUTPUT_DA_START1 = 4,
+ NI_RTSI_OUTPUT_G_SRC0 = 5,
+ NI_RTSI_OUTPUT_G_GATE0 = 6,
+ NI_RTSI_OUTPUT_RGOUT0 = 7,
+ NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
+ NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI
+ * clock on line 7 */
+};
+static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)
+{
+ return NI_RTSI_OUTPUT_RTSI_BRD_0 + n;
+}
/* Signals which can be routed to an NI PFI pin on an m-series board with
* INSN_CONFIG_SET_ROUTING. These numbers are also returned by
* INSN_CONFIG_GET_ROUTING on pre-m-series boards, even though their routing
* cannot be changed. The numbers assigned are not arbitrary, they correspond
* to the bits required to program the board. */
- enum ni_pfi_routing {
- NI_PFI_OUTPUT_PFI_DEFAULT = 0,
- NI_PFI_OUTPUT_AI_START1 = 1,
- NI_PFI_OUTPUT_AI_START2 = 2,
- NI_PFI_OUTPUT_AI_CONVERT = 3,
- NI_PFI_OUTPUT_G_SRC1 = 4,
- NI_PFI_OUTPUT_G_GATE1 = 5,
- NI_PFI_OUTPUT_AO_UPDATE_N = 6,
- NI_PFI_OUTPUT_AO_START1 = 7,
- NI_PFI_OUTPUT_AI_START_PULSE = 8,
- NI_PFI_OUTPUT_G_SRC0 = 9,
- NI_PFI_OUTPUT_G_GATE0 = 10,
- NI_PFI_OUTPUT_EXT_STROBE = 11,
- NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12,
- NI_PFI_OUTPUT_GOUT0 = 13,
- NI_PFI_OUTPUT_GOUT1 = 14,
- NI_PFI_OUTPUT_FREQ_OUT = 15,
- NI_PFI_OUTPUT_PFI_DO = 16,
- NI_PFI_OUTPUT_I_ATRIG = 17,
- NI_PFI_OUTPUT_RTSI0 = 18,
- NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26,
- NI_PFI_OUTPUT_SCXI_TRIG1 = 27,
- NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28,
- NI_PFI_OUTPUT_CDI_SAMPLE = 29,
- NI_PFI_OUTPUT_CDO_UPDATE = 30
- };
- static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel)
- {
- return NI_PFI_OUTPUT_RTSI0 + rtsi_channel;
- }
+enum ni_pfi_routing {
+ NI_PFI_OUTPUT_PFI_DEFAULT = 0,
+ NI_PFI_OUTPUT_AI_START1 = 1,
+ NI_PFI_OUTPUT_AI_START2 = 2,
+ NI_PFI_OUTPUT_AI_CONVERT = 3,
+ NI_PFI_OUTPUT_G_SRC1 = 4,
+ NI_PFI_OUTPUT_G_GATE1 = 5,
+ NI_PFI_OUTPUT_AO_UPDATE_N = 6,
+ NI_PFI_OUTPUT_AO_START1 = 7,
+ NI_PFI_OUTPUT_AI_START_PULSE = 8,
+ NI_PFI_OUTPUT_G_SRC0 = 9,
+ NI_PFI_OUTPUT_G_GATE0 = 10,
+ NI_PFI_OUTPUT_EXT_STROBE = 11,
+ NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12,
+ NI_PFI_OUTPUT_GOUT0 = 13,
+ NI_PFI_OUTPUT_GOUT1 = 14,
+ NI_PFI_OUTPUT_FREQ_OUT = 15,
+ NI_PFI_OUTPUT_PFI_DO = 16,
+ NI_PFI_OUTPUT_I_ATRIG = 17,
+ NI_PFI_OUTPUT_RTSI0 = 18,
+ NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26,
+ NI_PFI_OUTPUT_SCXI_TRIG1 = 27,
+ NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28,
+ NI_PFI_OUTPUT_CDI_SAMPLE = 29,
+ NI_PFI_OUTPUT_CDO_UPDATE = 30
+};
+static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel)
+{
+ return NI_PFI_OUTPUT_RTSI0 + rtsi_channel;
+}
/* Signals which can be routed to output on a NI PFI pin on a 660x board
with INSN_CONFIG_SET_ROUTING. The numbers assigned are
to program the board. Lines 0 to 7 can only be set to
NI_660X_PFI_OUTPUT_DIO. Lines 32 to 39 can only be set to
NI_660X_PFI_OUTPUT_COUNTER. */
- enum ni_660x_pfi_routing {
- NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */
- NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */
- };
+enum ni_660x_pfi_routing {
+ NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */
+ NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */
+};
/* NI External Trigger lines. These values are not arbitrary, but are related
* to the bits required to program the board (offset by 1 for historical
* reasons). */
- static inline unsigned NI_EXT_PFI(unsigned pfi_channel)
- {
- return NI_USUAL_PFI_SELECT(pfi_channel) - 1;
- }
- static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel)
- {
- return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1;
- }
+static inline unsigned NI_EXT_PFI(unsigned pfi_channel)
+{
+ return NI_USUAL_PFI_SELECT(pfi_channel) - 1;
+}
+static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel)
+{
+ return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1;
+}
/* status bits for INSN_CONFIG_GET_COUNTER_STATUS */
- enum comedi_counter_status_flags {
- COMEDI_COUNTER_ARMED = 0x1,
- COMEDI_COUNTER_COUNTING = 0x2,
- COMEDI_COUNTER_TERMINAL_COUNT = 0x4,
- };
+enum comedi_counter_status_flags {
+ COMEDI_COUNTER_ARMED = 0x1,
+ COMEDI_COUNTER_COUNTING = 0x2,
+ COMEDI_COUNTER_TERMINAL_COUNT = 0x4,
+};
/* Clock sources for CDIO subdevice on NI m-series boards. Used as the
* scan_begin_arg for a comedi_command. These sources may also be bitwise-or'd
* with CR_INVERT to change polarity. */
- enum ni_m_series_cdio_scan_begin_src {
- NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0,
- NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18,
- NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19,
- NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20,
- NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28,
- NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29,
- NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30,
- NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31,
- NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32,
- NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33
- };
- static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
- {
- return NI_USUAL_PFI_SELECT(pfi_channel);
- }
- static inline unsigned
- NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
- {
- return NI_USUAL_RTSI_SELECT(rtsi_channel);
- }
+enum ni_m_series_cdio_scan_begin_src {
+ NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0,
+ NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18,
+ NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19,
+ NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20,
+ NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28,
+ NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29,
+ NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30,
+ NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31,
+ NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32,
+ NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33
+};
+static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
+{
+ return NI_USUAL_PFI_SELECT(pfi_channel);
+}
+static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
+{
+ return NI_USUAL_RTSI_SELECT(rtsi_channel);
+}
/* scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI
* boards. These scan begin sources can also be bitwise-or'd with CR_INVERT to
* change polarity. */
- static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
- {
- return NI_USUAL_PFI_SELECT(pfi_channel);
- }
- static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
- {
- return NI_USUAL_RTSI_SELECT(rtsi_channel);
- }
+static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel)
+{
+ return NI_USUAL_PFI_SELECT(pfi_channel);
+}
+static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel)
+{
+ return NI_USUAL_RTSI_SELECT(rtsi_channel);
+}
/* Bits for setting a clock source with
* INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice. */
- enum ni_freq_out_clock_source_bits {
- NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */
- NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */
- };
+enum ni_freq_out_clock_source_bits {
+ NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */
+ NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */
+};
/* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for
* 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
- enum amplc_dio_clock_source {
- AMPLC_DIO_CLK_CLKN, /* per channel external clock
- input/output pin (pin is only an
- input when clock source set to this
- value, otherwise it is an output) */
- AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */
- AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */
- AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */
- AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */
- AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */
- AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel
- (for channel 0, preceding counter
- channel is channel 2 on preceding
- counter subdevice, for first counter
- subdevice, preceding counter
- subdevice is the last counter
- subdevice) */
- AMPLC_DIO_CLK_EXT /* per chip external input pin */
- };
+enum amplc_dio_clock_source {
+ AMPLC_DIO_CLK_CLKN, /* per channel external clock
+ input/output pin (pin is only an
+ input when clock source set to this
+ value, otherwise it is an output) */
+ AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */
+ AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */
+ AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */
+ AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */
+ AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */
+ AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel
+ (for channel 0, preceding counter
+ channel is channel 2 on preceding
+ counter subdevice, for first counter
+ subdevice, preceding counter
+ subdevice is the last counter
+ subdevice) */
+ AMPLC_DIO_CLK_EXT /* per chip external input pin */
+};
/* Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for
* 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */
- enum amplc_dio_gate_source {
- AMPLC_DIO_GAT_VCC, /* internal high logic level */
- AMPLC_DIO_GAT_GND, /* internal low logic level */
- AMPLC_DIO_GAT_GATN, /* per channel external gate input */
- AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel
- minus 2 (for channels 0 or 1,
- channel minus 2 is channel 1 or 2 on
- the preceding counter subdevice, for
- the first counter subdevice the
- preceding counter subdevice is the
- last counter subdevice) */
- AMPLC_DIO_GAT_RESERVED4,
- AMPLC_DIO_GAT_RESERVED5,
- AMPLC_DIO_GAT_RESERVED6,
- AMPLC_DIO_GAT_RESERVED7
- };
+enum amplc_dio_gate_source {
+ AMPLC_DIO_GAT_VCC, /* internal high logic level */
+ AMPLC_DIO_GAT_GND, /* internal low logic level */
+ AMPLC_DIO_GAT_GATN, /* per channel external gate input */
+ AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel
+ minus 2 (for channels 0 or 1,
+ channel minus 2 is channel 1 or 2 on
+ the preceding counter subdevice, for
+ the first counter subdevice the
+ preceding counter subdevice is the
+ last counter subdevice) */
+ AMPLC_DIO_GAT_RESERVED4,
+ AMPLC_DIO_GAT_RESERVED5,
+ AMPLC_DIO_GAT_RESERVED6,
+ AMPLC_DIO_GAT_RESERVED7
+};
#endif /* _COMEDI_H */
return -ENOMEM;
if (copy_from_user(aux_data,
- comedi_aux_data(it.options, 0), aux_len)) {
+ (unsigned char __user *
+ )comedi_aux_data(it.options, 0), aux_len)) {
vfree(aux_data);
return -EFAULT;
}
ret = -EAGAIN;
break;
}
- ret = s->async->inttrig(dev, s, insn->data[0]);
+ ret = s->async->inttrig(dev, s, data[0]);
if (ret >= 0)
ret = 1;
break;
}
static int do_cmd_ioctl(struct comedi_device *dev,
- struct comedi_cmd __user *cmd, void *file)
+ struct comedi_cmd __user *arg, void *file)
{
- struct comedi_cmd user_cmd;
+ struct comedi_cmd cmd;
struct comedi_subdevice *s;
struct comedi_async *async;
int ret = 0;
- unsigned int __user *chanlist_saver = NULL;
+ unsigned int __user *user_chanlist;
- if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
+ if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
DPRINTK("bad cmd address\n");
return -EFAULT;
}
/* save user's chanlist pointer so it can be restored later */
- chanlist_saver = user_cmd.chanlist;
+ user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (user_cmd.subdev >= dev->n_subdevices) {
- DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+ if (cmd.subdev >= dev->n_subdevices) {
+ DPRINTK("%d no such subdevice\n", cmd.subdev);
return -ENODEV;
}
- s = &dev->subdevices[user_cmd.subdev];
+ s = &dev->subdevices[cmd.subdev];
async = s->async;
if (s->type == COMEDI_SUBD_UNUSED) {
- DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+ DPRINTK("%d not valid subdevice\n", cmd.subdev);
return -EIO;
}
if (!s->do_cmd || !s->do_cmdtest || !s->async) {
DPRINTK("subdevice %i does not support commands\n",
- user_cmd.subdev);
+ cmd.subdev);
return -EIO;
}
s->busy = file;
/* make sure channel/gain list isn't too long */
- if (user_cmd.chanlist_len > s->len_chanlist) {
+ if (cmd.chanlist_len > s->len_chanlist) {
DPRINTK("channel/gain list too long %u > %d\n",
- user_cmd.chanlist_len, s->len_chanlist);
+ cmd.chanlist_len, s->len_chanlist);
ret = -EINVAL;
goto cleanup;
}
/* make sure channel/gain list isn't too short */
- if (user_cmd.chanlist_len < 1) {
+ if (cmd.chanlist_len < 1) {
DPRINTK("channel/gain list too short %u < 1\n",
- user_cmd.chanlist_len);
+ cmd.chanlist_len);
ret = -EINVAL;
goto cleanup;
}
- kfree(async->cmd.chanlist);
- async->cmd = user_cmd;
+ async->cmd = cmd;
async->cmd.data = NULL;
/* load channel/gain list */
async->cmd.chanlist =
goto cleanup;
}
- if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
+ if (copy_from_user(async->cmd.chanlist, user_chanlist,
async->cmd.chanlist_len * sizeof(int))) {
DPRINTK("fault reading chanlist\n");
ret = -EFAULT;
if (async->cmd.flags & TRIG_BOGUS || ret) {
DPRINTK("test returned %d\n", ret);
- user_cmd = async->cmd;
+ cmd = async->cmd;
/* restore chanlist pointer before copying back */
- user_cmd.chanlist = chanlist_saver;
- user_cmd.data = NULL;
- if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
+ cmd.chanlist = (unsigned int __force *)user_chanlist;
+ cmd.data = NULL;
+ if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
DPRINTK("fault writing cmd\n");
ret = -EFAULT;
goto cleanup;
static int do_cmdtest_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
- struct comedi_cmd user_cmd;
+ struct comedi_cmd cmd;
struct comedi_subdevice *s;
int ret = 0;
unsigned int *chanlist = NULL;
- unsigned int __user *chanlist_saver = NULL;
+ unsigned int __user *user_chanlist;
- if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
+ if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) {
DPRINTK("bad cmd address\n");
return -EFAULT;
}
/* save user's chanlist pointer so it can be restored later */
- chanlist_saver = user_cmd.chanlist;
+ user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (user_cmd.subdev >= dev->n_subdevices) {
- DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+ if (cmd.subdev >= dev->n_subdevices) {
+ DPRINTK("%d no such subdevice\n", cmd.subdev);
return -ENODEV;
}
- s = &dev->subdevices[user_cmd.subdev];
+ s = &dev->subdevices[cmd.subdev];
if (s->type == COMEDI_SUBD_UNUSED) {
- DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+ DPRINTK("%d not valid subdevice\n", cmd.subdev);
return -EIO;
}
if (!s->do_cmd || !s->do_cmdtest) {
DPRINTK("subdevice %i does not support commands\n",
- user_cmd.subdev);
+ cmd.subdev);
return -EIO;
}
/* make sure channel/gain list isn't too long */
- if (user_cmd.chanlist_len > s->len_chanlist) {
+ if (cmd.chanlist_len > s->len_chanlist) {
DPRINTK("channel/gain list too long %d > %d\n",
- user_cmd.chanlist_len, s->len_chanlist);
+ cmd.chanlist_len, s->len_chanlist);
ret = -EINVAL;
goto cleanup;
}
/* load channel/gain list */
- if (user_cmd.chanlist) {
+ if (cmd.chanlist) {
chanlist =
- kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
+ kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL);
if (!chanlist) {
DPRINTK("allocation failed\n");
ret = -ENOMEM;
goto cleanup;
}
- if (copy_from_user(chanlist, user_cmd.chanlist,
- user_cmd.chanlist_len * sizeof(int))) {
+ if (copy_from_user(chanlist, user_chanlist,
+ cmd.chanlist_len * sizeof(int))) {
DPRINTK("fault reading chanlist\n");
ret = -EFAULT;
goto cleanup;
}
/* make sure each element in channel/gain list is valid */
- ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
+ ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
if (ret < 0) {
DPRINTK("bad chanlist\n");
goto cleanup;
}
- user_cmd.chanlist = chanlist;
+ cmd.chanlist = chanlist;
}
- ret = s->do_cmdtest(dev, s, &user_cmd);
+ ret = s->do_cmdtest(dev, s, &cmd);
/* restore chanlist pointer before copying back */
- user_cmd.chanlist = chanlist_saver;
+ cmd.chanlist = (unsigned int __force *)user_chanlist;
- if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
+ if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) {
DPRINTK("bad cmd address\n");
ret = -EFAULT;
goto cleanup;
if (async) {
comedi_reset_async_buf(async);
async->inttrig = NULL;
+ kfree(async->cmd.chanlist);
+ async->cmd.chanlist = NULL;
} else {
dev_err(dev->class_dev,
"BUG: (?) do_become_nonbusy called with async=NULL\n");
new_insn.insn = INSN_BITS;
new_insn.chanspec = base_bitfield_channel;
new_insn.n = 2;
- new_insn.data = new_data;
new_insn.subdev = insn->subdev;
if (insn->insn == INSN_WRITE) {
return 0;
}
-static inline int i8254_mm_load(void *base_address, unsigned int regshift,
- unsigned int counter_number, unsigned int count,
+static inline int i8254_mm_load(void __iomem *base_address,
+ unsigned int regshift,
+ unsigned int counter_number,
+ unsigned int count,
unsigned int mode)
{
unsigned int byte;
return ret;
}
-static inline int i8254_mm_read(void *base_address, unsigned int regshift,
+static inline int i8254_mm_read(void __iomem *base_address,
+ unsigned int regshift,
unsigned int counter_number)
{
unsigned int byte;
outb(byte, base_address + (counter_number << regshift));
}
-static inline void i8254_mm_write(void *base_address,
+static inline void i8254_mm_write(void __iomem *base_address,
unsigned int regshift,
unsigned int counter_number,
unsigned int count)
return 0;
}
-static inline int i8254_mm_set_mode(void *base_address,
+static inline int i8254_mm_set_mode(void __iomem *base_address,
unsigned int regshift,
unsigned int counter_number,
unsigned int mode)
return inb(base_address + (counter_number << regshift));
}
-static inline int i8254_mm_status(void *base_address,
+static inline int i8254_mm_status(void __iomem *base_address,
unsigned int regshift,
unsigned int counter_number)
{
Much of the functionality of this driver was determined from reading
the source code for the Windows driver.
-The FPGA on the board requires initialization code, which can
-be loaded by comedi_config using the -i
-option. The initialization code is available from http://www.comedi.org
-in the comedi_nonfree_firmware tarball.
-
-Configuration options:
- [0] - PCI bus of device (optional)
- [1] - PCI slot of device (optional)
- If bus/slot is not specified, the first supported
- PCI device found will be used.
+The FPGA on the board requires fimware, which is available from
+http://www.comedi.org in the comedi_nonfree_firmware tarball.
+
+Configuration options: not applicable, uses PCI auto config
*/
/*
This card was obviously never intended to leave the Windows world,
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/firmware.h>
#include "8255.h"
+#define DAQBOARD2000_FIRMWARE "daqboard2000_firmware.bin"
+
#define PCI_VENDOR_ID_IOTECH 0x1616
#define DAQBOARD2000_SUBSYSTEM_IDS2 0x0002 /* Daqboard/2000 - 2 Dacs */
#define DAQBOARD2000_SUBSYSTEM_IDS4 0x0004 /* Daqboard/2000 - 4 Dacs */
-#define DAQBOARD2000_DAQ_SIZE 0x1002
-#define DAQBOARD2000_PLX_SIZE 0x100
-
/* Initialization bits for the Serial EEPROM Control Register */
#define DAQBOARD2000_SECRProgPinHi 0x8001767e
#define DAQBOARD2000_SECRProgPinLo 0x8000767e
#define DAQBOARD2000_CPLD_INIT 0x0002
#define DAQBOARD2000_CPLD_DONE 0x0004
-/* Available ranges */
-static const struct comedi_lrange range_daqboard2000_ai = { 13, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2.5,
- 2.5),
- RANGE(-1.25,
- 1.25),
- RANGE(-0.625,
- 0.625),
- RANGE(-0.3125,
- 0.3125),
- RANGE(-0.156,
- 0.156),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2.5),
- RANGE(0, 1.25),
- RANGE(0,
- 0.625),
- RANGE(0,
- 0.3125)
- }
-};
-
-static const struct comedi_lrange range_daqboard2000_ao = { 1, {
- RANGE(-10, 10)
- }
+static const struct comedi_lrange range_daqboard2000_ai = {
+ 13, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(0.3125),
+ BIP_RANGE(0.156),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ UNI_RANGE(0.625),
+ UNI_RANGE(0.3125)
+ }
};
-struct daqboard2000_hw {
- volatile u16 acqControl; /* 0x00 */
- volatile u16 acqScanListFIFO; /* 0x02 */
- volatile u32 acqPacerClockDivLow; /* 0x04 */
-
- volatile u16 acqScanCounter; /* 0x08 */
- volatile u16 acqPacerClockDivHigh; /* 0x0a */
- volatile u16 acqTriggerCount; /* 0x0c */
- volatile u16 fill2; /* 0x0e */
- volatile u16 acqResultsFIFO; /* 0x10 */
- volatile u16 fill3; /* 0x12 */
- volatile u16 acqResultsShadow; /* 0x14 */
- volatile u16 fill4; /* 0x16 */
- volatile u16 acqAdcResult; /* 0x18 */
- volatile u16 fill5; /* 0x1a */
- volatile u16 dacScanCounter; /* 0x1c */
- volatile u16 fill6; /* 0x1e */
-
- volatile u16 dacControl; /* 0x20 */
- volatile u16 fill7; /* 0x22 */
- volatile s16 dacFIFO; /* 0x24 */
- volatile u16 fill8[2]; /* 0x26 */
- volatile u16 dacPacerClockDiv; /* 0x2a */
- volatile u16 refDacs; /* 0x2c */
- volatile u16 fill9; /* 0x2e */
-
- volatile u16 dioControl; /* 0x30 */
- volatile s16 dioP3hsioData; /* 0x32 */
- volatile u16 dioP3Control; /* 0x34 */
- volatile u16 calEepromControl; /* 0x36 */
- volatile s16 dacSetting[4]; /* 0x38 */
- volatile s16 dioP2ExpansionIO8Bit[32]; /* 0x40 */
-
- volatile u16 ctrTmrControl; /* 0x80 */
- volatile u16 fill10[3]; /* 0x82 */
- volatile s16 ctrInput[4]; /* 0x88 */
- volatile u16 fill11[8]; /* 0x90 */
- volatile u16 timerDivisor[2]; /* 0xa0 */
- volatile u16 fill12[6]; /* 0xa4 */
-
- volatile u16 dmaControl; /* 0xb0 */
- volatile u16 trigControl; /* 0xb2 */
- volatile u16 fill13[2]; /* 0xb4 */
- volatile u16 calEeprom; /* 0xb8 */
- volatile u16 acqDigitalMark; /* 0xba */
- volatile u16 trigDacs; /* 0xbc */
- volatile u16 fill14; /* 0xbe */
- volatile s16 dioP2ExpansionIO16Bit[32]; /* 0xc0 */
-};
+/*
+ * Register Memory Map
+ */
+#define acqControl 0x00 /* u16 */
+#define acqScanListFIFO 0x02 /* u16 */
+#define acqPacerClockDivLow 0x04 /* u32 */
+#define acqScanCounter 0x08 /* u16 */
+#define acqPacerClockDivHigh 0x0a /* u16 */
+#define acqTriggerCount 0x0c /* u16 */
+#define acqResultsFIFO 0x10 /* u16 */
+#define acqResultsShadow 0x14 /* u16 */
+#define acqAdcResult 0x18 /* u16 */
+#define dacScanCounter 0x1c /* u16 */
+#define dacControl 0x20 /* u16 */
+#define dacFIFO 0x24 /* s16 */
+#define dacPacerClockDiv 0x2a /* u16 */
+#define refDacs 0x2c /* u16 */
+#define dioControl 0x30 /* u16 */
+#define dioP3hsioData 0x32 /* s16 */
+#define dioP3Control 0x34 /* u16 */
+#define calEepromControl 0x36 /* u16 */
+#define dacSetting(x) (0x38 + (x)*2) /* s16 */
+#define dioP2ExpansionIO8Bit 0x40 /* s16 */
+#define ctrTmrControl 0x80 /* u16 */
+#define ctrInput(x) (0x88 + (x)*2) /* s16 */
+#define timerDivisor(x) (0xa0 + (x)*2) /* u16 */
+#define dmaControl 0xb0 /* u16 */
+#define trigControl 0xb2 /* u16 */
+#define calEeprom 0xb8 /* u16 */
+#define acqDigitalMark 0xba /* u16 */
+#define trigDacs 0xbc /* u16 */
+#define dioP2ExpansionIO16Bit(x) (0xc0 + (x)*2) /* s16 */
/* Scan Sequencer programming */
#define DAQBOARD2000_SeqStartScanList 0x0011
{"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
};
-#define this_board ((const struct daq200_boardtype *)dev->board_ptr)
-
struct daqboard2000_private {
enum {
card_daqboard_2000
} card;
- void *daq;
+ void __iomem *daq;
void __iomem *plx;
unsigned int ao_readback[2];
};
-#define devpriv ((struct daqboard2000_private *)dev->private)
-
static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry)
{
- struct daqboard2000_hw *fpga = devpriv->daq;
+ struct daqboard2000_private *devpriv = dev->private;
-/* udelay(4); */
- fpga->acqScanListFIFO = entry & 0x00ff;
-/* udelay(4); */
- fpga->acqScanListFIFO = (entry >> 8) & 0x00ff;
+ /* udelay(4); */
+ writew(entry & 0x00ff, devpriv->daq + acqScanListFIFO);
+ /* udelay(4); */
+ writew((entry >> 8) & 0x00ff, devpriv->daq + acqScanListFIFO);
}
static void setup_sampling(struct comedi_device *dev, int chan, int gain)
/* These should be read from EEPROM */
word2 |= 0x0800;
word3 |= 0xc000;
-/* printk("%d %4.4x %4.4x %4.4x %4.4x\n", chan, word0, word1, word2, word3);*/
writeAcqScanListEntry(dev, word0);
writeAcqScanListEntry(dev, word1);
writeAcqScanListEntry(dev, word2);
struct comedi_insn *insn,
unsigned int *data)
{
- int i;
- struct daqboard2000_hw *fpga = devpriv->daq;
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int val;
int gain, chan, timeout;
+ int i;
- fpga->acqControl =
- DAQBOARD2000_AcqResetScanListFifo |
- DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
+ writew(DAQBOARD2000_AcqResetScanListFifo |
+ DAQBOARD2000_AcqResetResultsFifo |
+ DAQBOARD2000_AcqResetConfigPipe, devpriv->daq + acqControl);
/*
* If pacer clock is not set to some high value (> 10 us), we
* risk multiple samples to be put into the result FIFO.
*/
/* 1 second, should be long enough */
- fpga->acqPacerClockDivLow = 1000000;
- fpga->acqPacerClockDivHigh = 0;
+ writel(1000000, devpriv->daq + acqPacerClockDivLow);
+ writew(0, devpriv->daq + acqPacerClockDivHigh);
gain = CR_RANGE(insn->chanspec);
chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
setup_sampling(dev, chan, gain);
/* Enable reading from the scanlist FIFO */
- fpga->acqControl = DAQBOARD2000_SeqStartScanList;
+ writew(DAQBOARD2000_SeqStartScanList,
+ devpriv->daq + acqControl);
for (timeout = 0; timeout < 20; timeout++) {
- if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull)
+ val = readw(devpriv->daq + acqControl);
+ if (val & DAQBOARD2000_AcqConfigPipeFull)
break;
/* udelay(2); */
}
- fpga->acqControl = DAQBOARD2000_AdcPacerEnable;
+ writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl);
for (timeout = 0; timeout < 20; timeout++) {
- if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning)
+ val = readw(devpriv->daq + acqControl);
+ if (val & DAQBOARD2000_AcqLogicScanning)
break;
/* udelay(2); */
}
for (timeout = 0; timeout < 20; timeout++) {
- if (fpga->acqControl &
- DAQBOARD2000_AcqResultsFIFOHasValidData) {
+ val = readw(devpriv->daq + acqControl);
+ if (val & DAQBOARD2000_AcqResultsFIFOHasValidData)
break;
- }
/* udelay(2); */
}
- data[i] = fpga->acqResultsFIFO;
- fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
- fpga->acqControl = DAQBOARD2000_SeqStopScanList;
+ data[i] = readw(devpriv->daq + acqResultsFIFO);
+ writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
+ writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
}
return i;
struct comedi_insn *insn,
unsigned int *data)
{
- int i;
+ struct daqboard2000_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
+ int i;
for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
struct comedi_insn *insn,
unsigned int *data)
{
- int i;
+ struct daqboard2000_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
- struct daqboard2000_hw *fpga = devpriv->daq;
+ unsigned int val;
int timeout;
+ int i;
for (i = 0; i < insn->n; i++) {
+#if 0
/*
- * OK, since it works OK without enabling the DAC's, let's keep
- * it as simple as possible...
+ * OK, since it works OK without enabling the DAC's,
+ * let's keep it as simple as possible...
*/
- /* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */
- fpga->dacSetting[chan] = data[i];
+ writew((chan + 2) * 0x0010 | 0x0001,
+ devpriv->daq + dacControl);
+ udelay(1000);
+#endif
+ writew(data[i], devpriv->daq + dacSetting(chan));
for (timeout = 0; timeout < 20; timeout++) {
- if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0)
+ val = readw(devpriv->daq + dacControl);
+ if ((val & ((chan + 1) * 0x0010)) == 0)
break;
/* udelay(2); */
}
devpriv->ao_readback[chan] = data[i];
+#if 0
/*
- * Since we never enabled the DAC's, we don't need to disable it...
- * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; udelay(1000);
+ * Since we never enabled the DAC's, we don't need
+ * to disable it...
*/
+ writew((chan + 2) * 0x0010 | 0x0000,
+ devpriv->daq + dacControl);
+ udelay(1000);
+#endif
}
return i;
static void daqboard2000_resetLocalBus(struct comedi_device *dev)
{
- dev_dbg(dev->class_dev, "daqboard2000_resetLocalBus\n");
+ struct daqboard2000_private *devpriv = dev->private;
+
writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
udelay(10000);
writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
static void daqboard2000_reloadPLX(struct comedi_device *dev)
{
- dev_dbg(dev->class_dev, "daqboard2000_reloadPLX\n");
+ struct daqboard2000_private *devpriv = dev->private;
+
writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
udelay(10000);
writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
static void daqboard2000_pulseProgPin(struct comedi_device *dev)
{
- dev_dbg(dev->class_dev, "daqboard2000_pulseProgPin 1\n");
+ struct daqboard2000_private *devpriv = dev->private;
+
writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
udelay(10000);
writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask)
{
+ struct daqboard2000_private *devpriv = dev->private;
int result = 0;
int i;
int cpld;
static int daqboard2000_writeCPLD(struct comedi_device *dev, int data)
{
+ struct daqboard2000_private *devpriv = dev->private;
int result = 0;
udelay(10);
}
static int initialize_daqboard2000(struct comedi_device *dev,
- unsigned char *cpld_array, int len)
+ const u8 *cpld_array, size_t len)
{
+ struct daqboard2000_private *devpriv = dev->private;
int result = -EIO;
/* Read the serial EEPROM control register */
int secr;
int retry;
- int i;
+ size_t i;
/* Check to make sure the serial eeprom is present on the board */
secr = readl(devpriv->plx + 0x6c);
- if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) {
-#ifdef DEBUG_EEPROM
- dev_dbg(dev->class_dev, "no serial eeprom\n");
-#endif
+ if (!(secr & DAQBOARD2000_EEPROM_PRESENT))
return -EIO;
- }
for (retry = 0; retry < 3; retry++) {
-#ifdef DEBUG_EEPROM
- dev_dbg(dev->class_dev, "Programming EEPROM try %x\n", retry);
-#endif
-
daqboard2000_resetLocalBus(dev);
daqboard2000_reloadPLX(dev);
daqboard2000_pulseProgPin(dev);
if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) {
for (i = 0; i < len; i++) {
- if (cpld_array[i] == 0xff
- && cpld_array[i + 1] == 0x20) {
-#ifdef DEBUG_EEPROM
- dev_dbg(dev->class_dev,
- "Preamble found at %d\n", i);
-#endif
+ if (cpld_array[i] == 0xff &&
+ cpld_array[i + 1] == 0x20)
break;
- }
}
for (; i < len; i += 2) {
int data =
break;
}
if (i >= len) {
-#ifdef DEBUG_EEPROM
- dev_dbg(dev->class_dev, "Programmed\n");
-#endif
daqboard2000_resetLocalBus(dev);
daqboard2000_reloadPLX(dev);
result = 0;
return result;
}
+static int daqboard2000_upload_firmware(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, DAQBOARD2000_FIRMWARE, &pcidev->dev);
+ if (ret)
+ return ret;
+
+ ret = initialize_daqboard2000(dev, fw->data, fw->size);
+ release_firmware(fw);
+
+ return ret;
+}
+
static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev)
{
-/* printk("Implement: daqboard2000_adcStopDmaTransfer\n");*/
}
static void daqboard2000_adcDisarm(struct comedi_device *dev)
{
- struct daqboard2000_hw *fpga = devpriv->daq;
+ struct daqboard2000_private *devpriv = dev->private;
/* Disable hardware triggers */
udelay(2);
- fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable;
+ writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable,
+ devpriv->daq + trigControl);
udelay(2);
- fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable;
+ writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable,
+ devpriv->daq + trigControl);
/* Stop the scan list FIFO from loading the configuration pipe */
udelay(2);
- fpga->acqControl = DAQBOARD2000_SeqStopScanList;
+ writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
/* Stop the pacer clock */
udelay(2);
- fpga->acqControl = DAQBOARD2000_AdcPacerDisable;
+ writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
/* Stop the input dma (abort channel 1) */
daqboard2000_adcStopDmaTransfer(dev);
static void daqboard2000_activateReferenceDacs(struct comedi_device *dev)
{
- struct daqboard2000_hw *fpga = devpriv->daq;
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int val;
int timeout;
/* Set the + reference dac value in the FPGA */
- fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect;
+ writew(0x80 | DAQBOARD2000_PosRefDacSelect, devpriv->daq + refDacs);
for (timeout = 0; timeout < 20; timeout++) {
- if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0)
+ val = readw(devpriv->daq + dacControl);
+ if ((val & DAQBOARD2000_RefBusy) == 0)
break;
udelay(2);
}
-/* printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/
/* Set the - reference dac value in the FPGA */
- fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect;
+ writew(0x80 | DAQBOARD2000_NegRefDacSelect, devpriv->daq + refDacs);
for (timeout = 0; timeout < 20; timeout++) {
- if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0)
+ val = readw(devpriv->daq + dacControl);
+ if ((val & DAQBOARD2000_RefBusy) == 0)
break;
udelay(2);
}
-/* printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/
}
static void daqboard2000_initializeCtrs(struct comedi_device *dev)
{
-/* printk("Implement: daqboard2000_initializeCtrs\n");*/
}
static void daqboard2000_initializeTmrs(struct comedi_device *dev)
{
-/* printk("Implement: daqboard2000_initializeTmrs\n");*/
}
static void daqboard2000_dacDisarm(struct comedi_device *dev)
{
-/* printk("Implement: daqboard2000_dacDisarm\n");*/
}
static void daqboard2000_initializeAdc(struct comedi_device *dev)
daqboard2000_dacDisarm(dev);
}
-/*
-The test command, REMOVE!!:
-
-rmmod daqboard2000 ; rmmod comedi; make install ; modprobe daqboard2000; /usr/sbin/comedi_config /dev/comedi0 daqboard/2000 ; tail -40 /var/log/messages
-*/
-
static int daqboard2000_8255_cb(int dir, int port, int data,
unsigned long ioaddr)
{
- int result = 0;
+ void __iomem *mmio_base = (void __iomem *)ioaddr;
+
if (dir) {
- writew(data, ((void *)ioaddr) + port * 2);
- result = 0;
+ writew(data, mmio_base + port * 2);
+ return 0;
} else {
- result = readw(((void *)ioaddr) + port * 2);
+ return readw(mmio_base + port * 2);
}
-/*
- printk("daqboard2000_8255_cb %x %d %d %2.2x -> %2.2x\n",
- arg, dir, port, data, result);
-*/
- return result;
}
-static struct pci_dev *daqboard2000_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
+static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
+ struct pci_dev *pcidev)
{
- struct pci_dev *pcidev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
+ const struct daq200_boardtype *board;
int i;
- for_each_pci_dev(pcidev) {
- if (bus || slot) {
- if (bus != pcidev->bus->number ||
- slot != PCI_SLOT(pcidev->devfn))
- continue;
- }
- if (pcidev->vendor != PCI_VENDOR_ID_IOTECH ||
- pcidev->device != 0x0409 ||
- pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
- continue;
-
- for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
- if (boardtypes[i].id != pcidev->subsystem_device)
- continue;
- dev->board_ptr = boardtypes + i;
- return pcidev;
- }
+ if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
+ board = &boardtypes[i];
+ if (pcidev->subsystem_device == board->id)
+ return board;
}
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
return NULL;
}
-static int daqboard2000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
+static int daqboard2000_attach_pci(struct comedi_device *dev,
+ struct pci_dev *pcidev)
{
- struct pci_dev *pcidev;
+ const struct daq200_boardtype *board;
+ struct daqboard2000_private *devpriv;
struct comedi_subdevice *s;
- resource_size_t pci_base;
- void *aux_data;
- unsigned int aux_len;
int result;
- result = alloc_private(dev, sizeof(struct daqboard2000_private));
+ comedi_set_hw_dev(dev, &pcidev->dev);
+
+ board = daqboard2000_find_boardinfo(dev, pcidev);
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ result = alloc_private(dev, sizeof(*devpriv));
if (result < 0)
return -ENOMEM;
+ devpriv = dev->private;
- pcidev = daqboard2000_find_pci_dev(dev, it);
- if (!pcidev)
- return -EIO;
- comedi_set_hw_dev(dev, &pcidev->dev);
-
- result = comedi_pci_enable(pcidev, "daqboard2000");
- if (result < 0) {
- dev_err(dev->class_dev,
- "failed to enable PCI device and request regions\n");
- return -EIO;
- }
+ result = comedi_pci_enable(pcidev, dev->driver->driver_name);
+ if (result < 0)
+ return result;
dev->iobase = 1; /* the "detach" needs this */
- pci_base = pci_resource_start(pcidev, 0);
- devpriv->plx = ioremap(pci_base, DAQBOARD2000_PLX_SIZE);
- pci_base = pci_resource_start(pcidev, 2);
- devpriv->daq = ioremap(pci_base, DAQBOARD2000_DAQ_SIZE);
+ devpriv->plx = ioremap(pci_resource_start(pcidev, 0),
+ pci_resource_len(pcidev, 0));
+ devpriv->daq = ioremap(pci_resource_start(pcidev, 2),
+ pci_resource_len(pcidev, 2));
if (!devpriv->plx || !devpriv->daq)
return -ENOMEM;
readl(devpriv->plx + 0x6c);
- /*
- u8 interrupt;
- Windows code does restore interrupts, but since we don't use them...
- pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt);
- printk("Interrupt before is: %x\n", interrupt);
- */
-
- aux_data = comedi_aux_data(it->options, 0);
- aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-
- if (aux_data && aux_len) {
- result = initialize_daqboard2000(dev, aux_data, aux_len);
- } else {
- dev_dbg(dev->class_dev,
- "no FPGA initialization code, aborting\n");
- result = -EIO;
- }
+ result = daqboard2000_upload_firmware(dev);
if (result < 0)
- goto out;
+ return result;
+
daqboard2000_initializeAdc(dev);
daqboard2000_initializeDac(dev);
- /*
- Windows code does restore interrupts, but since we don't use them...
- pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt);
- printk("Interrupt after is: %x\n", interrupt);
- */
-
- dev->board_name = this_board->name;
s = &dev->subdevices[0];
/* ai subdevice */
s->maxdata = 0xffff;
s->insn_read = daqboard2000_ao_insn_read;
s->insn_write = daqboard2000_ao_insn_write;
- s->range_table = &range_daqboard2000_ao;
+ s->range_table = &range_bipolar10;
s = &dev->subdevices[2];
result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
- (unsigned long)(devpriv->daq + 0x40));
+ (unsigned long)(devpriv->daq + dioP2ExpansionIO8Bit));
+ if (result)
+ return result;
-out:
- return result;
+ dev_info(dev->class_dev, "%s: %s attached\n",
+ dev->driver->driver_name, dev->board_name);
+
+ return 0;
}
static void daqboard2000_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct daqboard2000_private *devpriv = dev->private;
if (dev->subdevices)
subdev_8255_cleanup(dev, &dev->subdevices[2]);
static struct comedi_driver daqboard2000_driver = {
.driver_name = "daqboard2000",
.module = THIS_MODULE,
- .attach = daqboard2000_attach,
+ .attach_pci = daqboard2000_attach_pci,
.detach = daqboard2000_detach,
};
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE);
/* utility function that suggests a dma transfer size in bytes */
static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- struct comedi_cmd cmd)
+ const struct comedi_cmd *cmd)
{
unsigned int size;
unsigned int freq;
/* otherwise, we are relying on dma terminal count interrupt,
* so pick a reasonable size */
- if (cmd.convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd.convert_arg;
- else if (cmd.scan_begin_src == TRIG_TIMER)
- freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
+ else if (cmd->scan_begin_src == TRIG_TIMER)
+ freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len;
/* return some default value */
else
freq = 0xffffffff;
- if (cmd.flags & TRIG_WAKE_EOS) {
- size = sample_size * cmd.chanlist_len;
+ if (cmd->flags & TRIG_WAKE_EOS) {
+ size = sample_size * cmd->chanlist_len;
} else {
/* make buffer fill in no more than 1/3 second */
size = (freq / 3) * sample_size;
else if (size < sample_size)
size = sample_size;
- if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
+ if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
size = devpriv->adc_byte_count;
return size;
set_dma_addr(devpriv->dma_chan,
devpriv->dma_buffer_addr[devpriv->current_buffer]);
/* set appropriate size of transfer */
- devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd);
+ devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd);
set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
enable_dma(devpriv->dma_chan);
release_dma_lock(flags);
}
/* returns appropriate bits for control register a, depending on command */
-static int control_a_bits(struct comedi_cmd cmd)
+static int control_a_bits(const struct comedi_cmd *cmd)
{
int control_a;
control_a = FFEN; /* enable fifo */
- if (cmd.stop_src == TRIG_EXT)
+ if (cmd->stop_src == TRIG_EXT)
control_a |= ATEN;
- switch (cmd.start_src) {
+ switch (cmd->start_src) {
case TRIG_EXT:
control_a |= TGEN | CGSL;
break;
}
/* returns appropriate bits for control register c, depending on command */
-static int control_c_bits(struct comedi_cmd cmd)
+static int control_c_bits(const struct comedi_cmd *cmd)
{
int control_c;
int aref;
/* set clock source to internal or external, select analog reference,
* select unipolar / bipolar
*/
- aref = CR_AREF(cmd.chanlist[0]);
+ aref = CR_AREF(cmd->chanlist[0]);
control_c = UQEN; /* enable upper qram addresses */
if (aref != AREF_DIFF)
control_c |= SD;
if (aref == AREF_COMMON)
control_c |= CMEN;
/* if a unipolar range was selected */
- if (CR_RANGE(cmd.chanlist[0]) & UNIPOLAR)
+ if (CR_RANGE(cmd->chanlist[0]) & UNIPOLAR)
control_c |= UB;
- switch (cmd.scan_begin_src) {
+ switch (cmd->scan_begin_src) {
case TRIG_FOLLOW: /* not in burst mode */
- switch (cmd.convert_src) {
+ switch (cmd->convert_src) {
case TRIG_TIMER:
/* trig on cascaded counters */
control_c |= IPCLK;
}
/* sets up counters */
-static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd)
+static int setup_counters(struct comedi_device *dev,
+ const struct comedi_cmd *cmd)
{
+ unsigned int period;
+
/* setup cascaded counters for conversion/scan frequency */
- switch (cmd.scan_begin_src) {
+ switch (cmd->scan_begin_src) {
case TRIG_FOLLOW: /* not in burst mode */
- if (cmd.convert_src == TRIG_TIMER) {
+ if (cmd->convert_src == TRIG_TIMER) {
/* set conversion frequency */
+ period = cmd->convert_arg;
i8253_cascade_ns_to_timer_2div(TIMER_BASE,
- &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(cmd.convert_arg),
- cmd.
- flags & TRIG_ROUND_MASK);
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &period,
+ cmd->flags &
+ TRIG_ROUND_MASK);
if (das1800_set_frequency(dev) < 0)
return -1;
}
break;
case TRIG_TIMER: /* in burst mode */
/* set scan frequency */
- i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(cmd.scan_begin_arg),
- cmd.flags & TRIG_ROUND_MASK);
+ period = cmd->scan_begin_arg;
+ i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1,
+ &devpriv->divisor2, &period,
+ cmd->flags & TRIG_ROUND_MASK);
if (das1800_set_frequency(dev) < 0)
return -1;
break;
}
/* setup counter 0 for 'about triggering' */
- if (cmd.stop_src == TRIG_EXT) {
+ if (cmd->stop_src == TRIG_EXT) {
/* load counter 0 in mode 0 */
i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0);
}
}
/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
-static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
+static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd)
{
unsigned int size = DMA_BUF_SIZE;
static const int sample_size = 2; /* size in bytes of one sample from board */
}
/* sets up dma */
-static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd)
+static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
{
unsigned long lock_flags;
const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
return;
/* determine a reasonable dma transfer size */
- devpriv->dma_transfer_size = suggest_transfer_size(&cmd);
+ devpriv->dma_transfer_size = suggest_transfer_size(cmd);
lock_flags = claim_dma_lock();
disable_dma(devpriv->dma0);
/* clear flip-flop to make sure 2-byte registers for
}
/* programs channel/gain list into card */
-static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd)
+static void program_chanlist(struct comedi_device *dev,
+ const struct comedi_cmd *cmd)
{
int i, n, chan_range;
unsigned long irq_flags;
const int range_mask = 0x3; /* masks unipolar/bipolar bit off range */
const int range_bitshift = 8;
- n = cmd.chanlist_len;
+ n = cmd->chanlist_len;
/* spinlock protects indirect addressing */
spin_lock_irqsave(&dev->spinlock, irq_flags);
outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */
/* make channel / gain list */
for (i = 0; i < n; i++) {
chan_range =
- CR_CHAN(cmd.
- chanlist[i]) | ((CR_RANGE(cmd.chanlist[i]) &
- range_mask) << range_bitshift);
+ CR_CHAN(cmd->chanlist[i]) |
+ ((CR_RANGE(cmd->chanlist[i]) & range_mask) <<
+ range_bitshift);
outw(chan_range, dev->iobase + DAS1800_QRAM);
}
outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */
int ret;
int control_a, control_c;
struct comedi_async *async = s->async;
- struct comedi_cmd cmd = async->cmd;
+ const struct comedi_cmd *cmd = &async->cmd;
if (!dev->irq) {
comedi_error(dev,
/* disable dma on TRIG_WAKE_EOS, or TRIG_RT
* (because dma in handler is unsafe at hard real-time priority) */
- if (cmd.flags & (TRIG_WAKE_EOS | TRIG_RT))
+ if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT))
devpriv->irq_dma_bits &= ~DMA_ENABLED;
else
devpriv->irq_dma_bits |= devpriv->dma_bits;
/* interrupt on end of conversion for TRIG_WAKE_EOS */
- if (cmd.flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & TRIG_WAKE_EOS) {
/* interrupt fifo not empty */
devpriv->irq_dma_bits &= ~FIMD;
} else {
devpriv->irq_dma_bits |= FIMD;
}
/* determine how many conversions we need */
- if (cmd.stop_src == TRIG_COUNT)
- devpriv->count = cmd.stop_arg * cmd.chanlist_len;
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->count = cmd->stop_arg * cmd->chanlist_len;
das1800_cancel(dev, s);
/* set conversion rate and length for burst mode */
if (control_c & BMDE) {
/* program conversion period with number of microseconds minus 1 */
- outb(cmd.convert_arg / 1000 - 1,
+ outb(cmd->convert_arg / 1000 - 1,
dev->iobase + DAS1800_BURST_RATE);
- outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);
+ outb(cmd->chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);
}
outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); /* enable irq/dma */
outb(control_a, dev->iobase + DAS1800_CONTROL_A); /* enable fifo and triggering */
If bus/slot is not specified, the first available PCI
device will be used.
-
-The 2600 requires a firmware upload, which can be accomplished
-using the -i or --init-data option of comedi_config.
-The firmware can be
-found in the comedi_nonfree_firmware tarball available
-from http://www.comedi.org
-
*/
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/firmware.h>
#include "../comedidev.h"
-/*#include "me2600_fw.h" */
-
-#define ME_DRIVER_NAME "me_daq"
+#define ME2600_FIRMWARE "me2600_firmware.bin"
#define PCI_VENDOR_ID_MEILHAUS 0x1402
#define ME2000_DEVICE_ID 0x2000
static const struct me_board me_boards[] = {
{
- /* -- ME-2600i -- */
- .name = ME_DRIVER_NAME,
+ .name = "me-2600i",
.device_id = ME2600_DEVICE_ID,
/* Analog Output */
.ao_channel_nbr = 4,
.dio_channel_nbr = 32,
},
{
- /* -- ME-2000i -- */
- .name = ME_DRIVER_NAME,
+ .name = "me-2000i",
.device_id = ME2000_DEVICE_ID,
/* Analog Output */
.ao_channel_nbr = 0,
/* Xilinx firmware download for card: ME-2600i */
static int me2600_xilinx_download(struct comedi_device *dev,
- unsigned char *me2600_firmware,
- unsigned int length)
+ const u8 *data, size_t size)
{
unsigned int value;
unsigned int file_length;
* Byte 8-11: date
* Byte 12-15: reserved
*/
- if (length < 16)
+ if (size < 16)
return -EINVAL;
- file_length = (((unsigned int)me2600_firmware[0] & 0xff) << 24) +
- (((unsigned int)me2600_firmware[1] & 0xff) << 16) +
- (((unsigned int)me2600_firmware[2] & 0xff) << 8) +
- ((unsigned int)me2600_firmware[3] & 0xff);
+
+ file_length = (((unsigned int)data[0] & 0xff) << 24) +
+ (((unsigned int)data[1] & 0xff) << 16) +
+ (((unsigned int)data[2] & 0xff) << 8) +
+ ((unsigned int)data[3] & 0xff);
/*
* Loop for writing firmware byte by byte to xilinx
* Firmware data start at offfset 16
*/
for (i = 0; i < file_length; i++)
- writeb((me2600_firmware[16 + i] & 0xff),
+ writeb((data[16 + i] & 0xff),
dev_private->me_regbase + 0x0);
/* Write 5 dummy values to xilinx */
return 0;
}
+static int me2600_upload_firmware(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, ME2600_FIRMWARE, &pcidev->dev);
+ if (ret)
+ return ret;
+
+ ret = me2600_xilinx_download(dev, fw->data, fw->size);
+ release_firmware(fw);
+
+ return ret;
+}
+
/* Reset device */
static int me_reset(struct comedi_device *dev)
{
return 0;
}
-static struct pci_dev *me_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
+static const void *me_find_boardinfo(struct comedi_device *dev,
+ struct pci_dev *pcidev)
{
const struct me_board *board;
- struct pci_dev *pcidev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
int i;
- for_each_pci_dev(pcidev) {
- if (bus || slot) {
- if (pcidev->bus->number != bus ||
- PCI_SLOT(pcidev->devfn) != slot)
- continue;
- }
- if (pcidev->vendor != PCI_VENDOR_ID_MEILHAUS)
- continue;
-
- for (i = 0; i < ARRAY_SIZE(me_boards); i++) {
- board = &me_boards[i];
- if (board->device_id != pcidev->device)
- continue;
-
- dev->board_ptr = board;
- return pcidev;
- }
+ for (i = 0; i < ARRAY_SIZE(me_boards); i++) {
+ board = &me_boards[i];
+ if (board->device_id == pcidev->device)
+ return board;
}
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
return NULL;
}
-static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int me_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev)
{
- struct pci_dev *pci_device;
+ const struct me_board *board;
struct comedi_subdevice *s;
- struct me_board *board;
resource_size_t plx_regbase_tmp;
unsigned long plx_regbase_size_tmp;
resource_size_t me_regbase_tmp;
resource_size_t regbase_tmp;
int result, error;
+ comedi_set_hw_dev(dev, &pcidev->dev);
+
+ board = me_find_boardinfo(dev, pcidev);
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
/* Allocate private memory */
if (alloc_private(dev, sizeof(struct me_private_data)) < 0)
return -ENOMEM;
- pci_device = me_find_pci_dev(dev, it);
- if (!pci_device)
- return -EIO;
- comedi_set_hw_dev(dev, &pci_device->dev);
- board = (struct me_board *)dev->board_ptr;
-
/* Enable PCI device and request PCI regions */
- if (comedi_pci_enable(pci_device, ME_DRIVER_NAME) < 0) {
+ if (comedi_pci_enable(pcidev, dev->board_name) < 0) {
printk(KERN_ERR "comedi%d: Failed to enable PCI device and "
"request regions\n", dev->minor);
return -EIO;
}
- /* Set data in device structure */
- dev->board_name = board->name;
-
/* Read PLX register base address [PCI_BASE_ADDRESS #0]. */
- plx_regbase_tmp = pci_resource_start(pci_device, 0);
- plx_regbase_size_tmp = pci_resource_len(pci_device, 0);
+ plx_regbase_tmp = pci_resource_start(pcidev, 0);
+ plx_regbase_size_tmp = pci_resource_len(pcidev, 0);
dev_private->plx_regbase =
ioremap(plx_regbase_tmp, plx_regbase_size_tmp);
dev_private->plx_regbase_size = plx_regbase_size_tmp;
/* Read Swap base address [PCI_BASE_ADDRESS #5]. */
- swap_regbase_tmp = pci_resource_start(pci_device, 5);
- swap_regbase_size_tmp = pci_resource_len(pci_device, 5);
+ swap_regbase_tmp = pci_resource_start(pcidev, 5);
+ swap_regbase_size_tmp = pci_resource_len(pcidev, 5);
if (!swap_regbase_tmp)
printk(KERN_ERR "comedi%d: Swap not present\n", dev->minor);
plx_regbase_tmp = swap_regbase_tmp;
swap_regbase_tmp = regbase_tmp;
- result = pci_write_config_dword(pci_device,
+ result = pci_write_config_dword(pcidev,
PCI_BASE_ADDRESS_0,
plx_regbase_tmp);
if (result != PCIBIOS_SUCCESSFUL)
return -EIO;
- result = pci_write_config_dword(pci_device,
+ result = pci_write_config_dword(pcidev,
PCI_BASE_ADDRESS_5,
swap_regbase_tmp);
if (result != PCIBIOS_SUCCESSFUL)
return -EIO;
} else {
plx_regbase_tmp -= 0x80;
- result = pci_write_config_dword(pci_device,
+ result = pci_write_config_dword(pcidev,
PCI_BASE_ADDRESS_0,
plx_regbase_tmp);
if (result != PCIBIOS_SUCCESSFUL)
/* Read Meilhaus register base address [PCI_BASE_ADDRESS #2]. */
- me_regbase_tmp = pci_resource_start(pci_device, 2);
- me_regbase_size_tmp = pci_resource_len(pci_device, 2);
+ me_regbase_tmp = pci_resource_start(pcidev, 2);
+ me_regbase_size_tmp = pci_resource_len(pcidev, 2);
dev_private->me_regbase_size = me_regbase_size_tmp;
dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp);
if (!dev_private->me_regbase) {
dev->minor);
return -ENOMEM;
}
+
/* Download firmware and reset card */
if (board->device_id == ME2600_DEVICE_ID) {
- unsigned char *aux_data;
- int aux_len;
-
- aux_data = comedi_aux_data(it->options, 0);
- aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
-
- if (!aux_data || aux_len < 1) {
- comedi_error(dev, "You must provide me2600 firmware "
- "using the --init-data option of "
- "comedi_config");
- return -EINVAL;
- }
- me2600_xilinx_download(dev, aux_data, aux_len);
+ result = me2600_upload_firmware(dev);
+ if (result < 0)
+ return result;
}
-
me_reset(dev);
error = comedi_alloc_subdevices(dev, 3);
s->insn_config = me_dio_insn_config;
s->io_bits = 0;
- printk(KERN_INFO "comedi%d: " ME_DRIVER_NAME " attached.\n",
- dev->minor);
+ dev_info(dev->class_dev, "%s: %s attached\n",
+ dev->driver->driver_name, dev->board_name);
+
return 0;
}
static struct comedi_driver me_daq_driver = {
.driver_name = "me_daq",
.module = THIS_MODULE,
- .attach = me_attach,
+ .attach_pci = me_attach_pci,
.detach = me_detach,
};
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(ME2600_FIRMWARE);
#define INIT_A1_BITS 0x70
#define COUNTER_B_BASE_REG 0x18
+enum scan_mode {
+ MODE_SINGLE_CHAN,
+ MODE_SINGLE_CHAN_INTERVAL,
+ MODE_MULT_CHAN_UP,
+ MODE_MULT_CHAN_DOWN,
+};
+
static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
static irqreturn_t labpc_interrupt(int irq, void *d);
static int labpc_drain_fifo(struct comedi_device *dev);
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data);
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode scan_mode);
#ifdef CONFIG_ISA_DMA_API
-static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd);
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd);
#endif
static int labpc_dio_mem_callback(int dir, int port, int data,
unsigned long arg);
static void write_caldac(struct comedi_device *dev, unsigned int channel,
unsigned int value);
-enum scan_mode {
- MODE_SINGLE_CHAN,
- MODE_SINGLE_CHAN_INTERVAL,
- MODE_MULT_CHAN_UP,
- MODE_MULT_CHAN_DOWN,
-};
-
/* analog input ranges */
#define NUM_LABPC_PLUS_AI_RANGES 16
/* indicates unipolar ranges */
static inline unsigned int labpc_readb(unsigned long address)
{
- return readb((void *)address);
+ return readb((void __iomem *)address);
}
static inline void labpc_writeb(unsigned int byte, unsigned long address)
{
- writeb(byte, (void *)address);
+ writeb(byte, (void __iomem *)address);
}
static const struct labpc_board_struct labpc_boards[] = {
unsigned int count, unsigned int mode)
{
if (thisboard->memory_mapped_io)
- return i8254_mm_load((void *)base_address, 0, counter_number,
- count, mode);
+ return i8254_mm_load((void __iomem *)base_address, 0,
+ counter_number, count, mode);
else
return i8254_load(base_address, 0, counter_number, count, mode);
}
}
static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
- const struct comedi_cmd *cmd)
+ const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- int mode, channel, range, aref, i;
+ int channel, range, aref, i;
if (cmd->chanlist == NULL)
return 0;
- mode = labpc_ai_scan_mode(cmd);
-
if (mode == MODE_SINGLE_CHAN)
return 0;
return 0;
}
-static int labpc_use_continuous_mode(const struct comedi_cmd *cmd)
+static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN)
+ if (mode == MODE_SINGLE_CHAN)
return 1;
if (cmd->scan_begin_src == TRIG_FOLLOW)
return 0;
}
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd)
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
if (cmd->convert_src != TRIG_TIMER)
return 0;
- if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
- cmd->scan_begin_src == TRIG_TIMER)
+ if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
return cmd->scan_begin_arg;
return cmd->convert_arg;
}
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns)
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
{
if (cmd->convert_src != TRIG_TIMER)
return;
- if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
+ if (mode == MODE_SINGLE_CHAN &&
cmd->scan_begin_src == TRIG_TIMER) {
cmd->scan_begin_arg = ns;
if (cmd->convert_arg > cmd->scan_begin_arg)
cmd->convert_arg = ns;
}
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd)
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
if (cmd->scan_begin_src != TRIG_TIMER)
return 0;
- if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
- cmd->convert_src == TRIG_TIMER)
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
return 0;
return cmd->scan_begin_arg;
}
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, unsigned int ns)
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
{
if (cmd->scan_begin_src != TRIG_TIMER)
return;
- if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN &&
- cmd->convert_src == TRIG_TIMER)
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
return;
cmd->scan_begin_arg = ns;
int err = 0;
int tmp, tmp2;
int stop_mask;
+ enum scan_mode mode;
/* step 1: make sure trigger sources are trivially valid */
tmp = cmd->convert_arg;
tmp2 = cmd->scan_begin_arg;
- labpc_adc_timing(dev, cmd);
+ mode = labpc_ai_scan_mode(cmd);
+ labpc_adc_timing(dev, cmd, mode);
if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg)
err++;
if (err)
return 4;
- if (labpc_ai_chanlist_invalid(dev, cmd))
+ if (labpc_ai_chanlist_invalid(dev, cmd, mode))
return 5;
return 0;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
enum transfer_type xfer;
+ enum scan_mode mode;
unsigned long flags;
if (!dev->irq) {
} else
xfer = fifo_not_empty_transfer;
devpriv->current_transfer = xfer;
+ mode = labpc_ai_scan_mode(cmd);
/* setup command6 register for 1200 boards */
if (thisboard->register_layout == labpc_1200_layout) {
else
devpriv->command6_bits &= ~A1_INTR_EN_BIT;
/* are we scanning up or down through channels? */
- if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
+ if (mode == MODE_MULT_CHAN_UP)
devpriv->command6_bits |= ADC_SCAN_UP_BIT;
else
devpriv->command6_bits &= ~ADC_SCAN_UP_BIT;
/* setup channel list, etc (command1 register) */
devpriv->command1_bits = 0;
- if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP)
+ if (mode == MODE_MULT_CHAN_UP)
channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
else
channel = CR_CHAN(cmd->chanlist[0]);
/* munge channel bits for differential / scan disabled mode */
- if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF)
+ if (mode != MODE_SINGLE_CHAN && aref == AREF_DIFF)
channel *= 2;
devpriv->command1_bits |= ADC_CHAN_BITS(channel);
devpriv->command1_bits |= thisboard->ai_range_code[range];
devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
/* manual says to set scan enable bit on second pass */
- if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP ||
- labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) {
+ if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
devpriv->command1_bits |= ADC_SCAN_EN_BIT;
/* need a brief delay before enabling scan, or scan
* list will get screwed when you switch
devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
/* XXX should discard first scan when using interval scanning
* since manual says it is not synced with scan clock */
- if (labpc_use_continuous_mode(cmd) == 0) {
+ if (labpc_use_continuous_mode(cmd, mode) == 0) {
devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT;
if (cmd->scan_begin_src == TRIG_EXT)
devpriv->command4_bits |= EXT_SCAN_EN_BIT;
if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) {
/* set up pacing */
- labpc_adc_timing(dev, cmd);
+ labpc_adc_timing(dev, cmd, mode);
/* load counter b0 in mode 3 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
0, devpriv->divisor_b0, 3);
}
}
/* set up conversion pacing */
- if (labpc_ai_convert_period(cmd)) {
+ if (labpc_ai_convert_period(cmd, mode)) {
/* load counter a0 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
0, devpriv->divisor_a0, 2);
dev->iobase + COUNTER_A_CONTROL_REG);
/* set up scan pacing */
- if (labpc_ai_scan_period(cmd)) {
+ if (labpc_ai_scan_period(cmd, mode)) {
/* load counter b1 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
1, devpriv->divisor_b1, 2);
set_dma_addr(devpriv->dma_chan,
virt_to_bus(devpriv->dma_buffer));
/* set appropriate size of transfer */
- devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd);
+ devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
if (cmd->stop_src == TRIG_COUNT &&
devpriv->count * sample_size < devpriv->dma_transfer_size) {
devpriv->dma_transfer_size =
#ifdef CONFIG_ISA_DMA_API
/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd)
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
{
unsigned int size;
unsigned int freq;
- if (cmd.convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd.convert_arg;
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
/* return some default value */
else
freq = 0xffffffff;
#endif
/* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
/* max value for 16 bit counter in mode 2 */
const int max_counter_value = 0x10000;
/* min value for 16 bit counter in mode 2 */
const int min_counter_value = 2;
unsigned int base_period;
+ unsigned int scan_period;
+ unsigned int convert_period;
/*
* if both convert and scan triggers are TRIG_TIMER, then they
* both rely on counter b0
*/
- if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) {
+ convert_period = labpc_ai_convert_period(cmd, mode);
+ scan_period = labpc_ai_scan_period(cmd, mode);
+ if (convert_period && scan_period) {
/*
* pick the lowest b0 divisor value we can (for maximum input
* clock speed on convert and scan counters)
*/
- devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) /
+ devpriv->divisor_b0 = (scan_period - 1) /
(LABPC_TIMER_BASE * max_counter_value) + 1;
if (devpriv->divisor_b0 < min_counter_value)
devpriv->divisor_b0 = min_counter_value;
default:
case TRIG_ROUND_NEAREST:
devpriv->divisor_a0 =
- (labpc_ai_convert_period(cmd) +
- (base_period / 2)) / base_period;
+ (convert_period + (base_period / 2)) / base_period;
devpriv->divisor_b1 =
- (labpc_ai_scan_period(cmd) +
- (base_period / 2)) / base_period;
+ (scan_period + (base_period / 2)) / base_period;
break;
case TRIG_ROUND_UP:
devpriv->divisor_a0 =
- (labpc_ai_convert_period(cmd) + (base_period -
- 1)) / base_period;
+ (convert_period + (base_period - 1)) / base_period;
devpriv->divisor_b1 =
- (labpc_ai_scan_period(cmd) + (base_period -
- 1)) / base_period;
+ (scan_period + (base_period - 1)) / base_period;
break;
case TRIG_ROUND_DOWN:
- devpriv->divisor_a0 =
- labpc_ai_convert_period(cmd) / base_period;
- devpriv->divisor_b1 =
- labpc_ai_scan_period(cmd) / base_period;
+ devpriv->divisor_a0 = convert_period / base_period;
+ devpriv->divisor_b1 = scan_period / base_period;
break;
}
/* make sure a0 and b1 values are acceptable */
if (devpriv->divisor_b1 > max_counter_value)
devpriv->divisor_b1 = max_counter_value;
/* write corrected timings to command */
- labpc_set_ai_convert_period(cmd,
+ labpc_set_ai_convert_period(cmd, mode,
base_period * devpriv->divisor_a0);
- labpc_set_ai_scan_period(cmd,
+ labpc_set_ai_scan_period(cmd, mode,
base_period * devpriv->divisor_b1);
/*
* if only one TRIG_TIMER is used, we can employ the generic
* cascaded timing functions
*/
- } else if (labpc_ai_scan_period(cmd)) {
- unsigned int scan_period;
-
- scan_period = labpc_ai_scan_period(cmd);
+ } else if (scan_period) {
/*
* calculate cascaded counter values
* that give desired scan timing
&(devpriv->divisor_b0),
&scan_period,
cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_scan_period(cmd, scan_period);
- } else if (labpc_ai_convert_period(cmd)) {
- unsigned int convert_period;
-
- convert_period = labpc_ai_convert_period(cmd);
+ labpc_set_ai_scan_period(cmd, mode, scan_period);
+ } else if (convert_period) {
/*
* calculate cascaded counter values
* that give desired conversion timing
&(devpriv->divisor_b0),
&convert_period,
cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_convert_period(cmd, convert_period);
+ labpc_set_ai_convert_period(cmd, mode, convert_period);
}
}
unsigned long iobase)
{
if (dir) {
- writeb(data, (void *)(iobase + port));
+ writeb(data, (void __iomem *)(iobase + port));
return 0;
} else {
- return readb((void *)(iobase + port));
+ return readb((void __iomem *)(iobase + port));
}
}
/*
cmdtest tests a particular command to see if it is valid.
Using the cmdtest ioctl, a user can create a valid cmd
- and then have it executed by the cmd ioctl (asyncronously).
+ and then have it executed by the cmd ioctl (asynchronously).
cmdtest returns 1,2,3,4 or 0, depending on which tests
the command passes.
#define REG_EED 0x32
#define REG_EEC 0x34
-static const int s526_ports[] = {
- REG_TCR,
- REG_WDC,
- REG_DAC,
- REG_ADC,
- REG_ADD,
- REG_DIO,
- REG_IER,
- REG_ISR,
- REG_MSC,
- REG_C0L,
- REG_C0H,
- REG_C0M,
- REG_C0C,
- REG_C1L,
- REG_C1H,
- REG_C1M,
- REG_C1C,
- REG_C2L,
- REG_C2H,
- REG_C2M,
- REG_C2C,
- REG_C3L,
- REG_C3H,
- REG_C3M,
- REG_C3C,
- REG_EED,
- REG_EEC
-};
-
struct counter_mode_register_t {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned short coutSource:1;
unsigned short value;
};
-#define MAX_GPCT_CONFIG_DATA 6
-
-/* Different Application Classes for GPCT Subdevices */
-/* The list is not exhaustive and needs discussion! */
-enum S526_GPCT_APP_CLASS {
- CountingAndTimeMeasurement,
- SinglePulseGeneration,
- PulseTrainGeneration,
- PositionMeasurement,
- Miscellaneous
-};
-
-/* Config struct for different GPCT subdevice Application Classes and
- their options
-*/
-struct s526GPCTConfig {
- enum S526_GPCT_APP_CLASS app;
- int data[MAX_GPCT_CONFIG_DATA];
-};
-
-/*
- * Board descriptions for two imaginary boards. Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
-struct s526_board {
- const char *name;
- int gpct_chans;
- int gpct_bits;
- int ad_chans;
- int ad_bits;
- int da_chans;
- int da_bits;
- int have_dio;
-};
-
-static const struct s526_board s526_boards[] = {
- {
- .name = "s526",
- .gpct_chans = 4,
- .gpct_bits = 24,
- .ad_chans = 8,
- .ad_bits = 16,
- .da_chans = 4,
- .da_bits = 16,
- .have_dio = 1,
- }
-};
-
-#define ADDR_REG(reg) (dev->iobase + (reg))
-#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
-
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device
- struct.
-*/
struct s526_private {
unsigned int ao_readback[2];
- struct s526GPCTConfig s526_gpct_config[4];
- unsigned short s526_ai_config;
+ unsigned int gpct_config[4];
+ unsigned short ai_config;
};
-/*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct s526_private *)dev->private)
-
static int s526_gpct_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
unsigned int *data)
{
- int i; /* counts the Data */
- int counter_channel = CR_CHAN(insn->chanspec);
- unsigned short datalow;
- unsigned short datahigh;
-
- /* Check if (n > 0) */
- if (insn->n <= 0) {
- printk(KERN_ERR "s526: INSN_READ: n should be > 0\n");
- return -EINVAL;
- }
- /* Read the low word first */
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned long chan_iobase = dev->iobase + chan * 8;
+ unsigned int lo;
+ unsigned int hi;
+ int i;
+
for (i = 0; i < insn->n; i++) {
- datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
- datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
- data[i] = (int)(datahigh & 0x00FF);
- data[i] = (data[i] << 16) | (datalow & 0xFFFF);
- /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n",
- counter_channel, data[i], datahigh, datalow); */
+ /* Read the low word first */
+ lo = inw(chan_iobase + REG_C0L) & 0xffff;
+ hi = inw(chan_iobase + REG_C0H) & 0xff;
+
+ data[i] = (hi << 16) | lo;
}
- return i;
+
+ return insn->n;
}
static int s526_gpct_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */
- int i;
- short value;
+ struct s526_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned long chan_iobase = dev->iobase + chan * 8;
+ unsigned int val;
union cmReg cmReg;
- /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n",
- subdev_channel); */
-
- for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
- devpriv->s526_gpct_config[subdev_channel].data[i] =
- insn->data[i];
-/* printk("data[%d]=%x\n", i, insn->data[i]); */
- }
-
/* Check what type of Counter the user requested, data[0] contains */
/* the Application type */
- switch (insn->data[0]) {
+ switch (data[0]) {
case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
/*
data[0]: Application Type
data[2]: Pre-load Register Value
data[3]: Conter Control Register
*/
- printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
- devpriv->s526_gpct_config[subdev_channel].app =
- PositionMeasurement;
+ devpriv->gpct_config[chan] = data[0];
#if 0
/* Example of Counter Application */
cmReg.reg.preloadRegSel = 0; /* PR0 */
cmReg.reg.reserved = 0;
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ outw(cmReg.value, chan_iobase + REG_C0M);
- outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ outw(0x0001, chan_iobase + REG_C0H);
+ outw(0x3C68, chan_iobase + REG_C0L);
/* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x8000, chan_iobase + REG_C0C);
/* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x4000, chan_iobase + REG_C0C);
/* Reset RCAP (fires one-shot) */
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x0008, chan_iobase + REG_C0C);
#endif
#if 1
/* Set Counter Mode Register */
- cmReg.value = insn->data[1] & 0xFFFF;
-
-/* printk("s526: Counter Mode register=%x\n", cmReg.value); */
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ cmReg.value = data[1] & 0xffff;
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Reset the counter if it is software preload */
if (cmReg.reg.autoLoadResetRcap == 0) {
/* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x8000, chan_iobase + REG_C0C);
/* Load the counter from PR0
- * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ * outw(0x4000, chan_iobase + REG_C0C);
*/
}
#else
cmReg.reg.countDirCtrl = 0;
/* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */
- if (insn->data[1] == GPCT_X2)
+ if (data[1] == GPCT_X2)
cmReg.reg.clockSource = 1;
- else if (insn->data[1] == GPCT_X4)
+ else if (data[1] == GPCT_X4)
cmReg.reg.clockSource = 2;
else
cmReg.reg.clockSource = 0;
/* When to take into account the indexpulse: */
- /*if (insn->data[2] == GPCT_IndexPhaseLowLow) {
- } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) {
- } else if (insn->data[2] == GPCT_IndexPhaseHighLow) {
- } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) {
+ /*if (data[2] == GPCT_IndexPhaseLowLow) {
+ } else if (data[2] == GPCT_IndexPhaseLowHigh) {
+ } else if (data[2] == GPCT_IndexPhaseHighLow) {
+ } else if (data[2] == GPCT_IndexPhaseHighHigh) {
}*/
/* Take into account the index pulse? */
- if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
+ if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
/* Auto load with INDEX^ */
cmReg.reg.autoLoadResetRcap = 4;
/* Set Counter Mode Register */
- cmReg.value = (short)(insn->data[1] & 0xFFFF);
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ cmReg.value = data[1] & 0xffff;
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Load the pre-load register high word */
- value = (short)((insn->data[2] >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ val = (data[2] >> 16) & 0xffff;
+ outw(val, chan_iobase + REG_C0H);
/* Load the pre-load register low word */
- value = (short)(insn->data[2] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ val = data[2] & 0xffff;
+ outw(val, chan_iobase + REG_C0L);
/* Write the Counter Control Register */
- if (insn->data[3] != 0) {
- value = (short)(insn->data[3] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ if (data[3]) {
+ val = data[3] & 0xffff;
+ outw(val, chan_iobase + REG_C0C);
}
/* Reset the counter if it is software preload */
if (cmReg.reg.autoLoadResetRcap == 0) {
/* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x8000, chan_iobase + REG_C0C);
/* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ outw(0x4000, chan_iobase + REG_C0C);
}
#endif
break;
data[3]: Pre-load Register 1 Value
data[4]: Conter Control Register
*/
- printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n");
- devpriv->s526_gpct_config[subdev_channel].app =
- SinglePulseGeneration;
+ devpriv->gpct_config[chan] = data[0];
/* Set Counter Mode Register */
- cmReg.value = (short)(insn->data[1] & 0xFFFF);
+ cmReg.value = data[1] & 0xffff;
cmReg.reg.preloadRegSel = 0; /* PR0 */
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Load the pre-load register 0 high word */
- value = (short)((insn->data[2] >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ val = (data[2] >> 16) & 0xffff;
+ outw(val, chan_iobase + REG_C0H);
/* Load the pre-load register 0 low word */
- value = (short)(insn->data[2] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ val = data[2] & 0xffff;
+ outw(val, chan_iobase + REG_C0L);
/* Set Counter Mode Register */
- cmReg.value = (short)(insn->data[1] & 0xFFFF);
+ cmReg.value = data[1] & 0xffff;
cmReg.reg.preloadRegSel = 1; /* PR1 */
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Load the pre-load register 1 high word */
- value = (short)((insn->data[3] >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ val = (data[3] >> 16) & 0xffff;
+ outw(val, chan_iobase + REG_C0H);
/* Load the pre-load register 1 low word */
- value = (short)(insn->data[3] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ val = data[3] & 0xffff;
+ outw(val, chan_iobase + REG_C0L);
/* Write the Counter Control Register */
- if (insn->data[4] != 0) {
- value = (short)(insn->data[4] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ if (data[4]) {
+ val = data[4] & 0xffff;
+ outw(val, chan_iobase + REG_C0C);
}
break;
data[3]: Pre-load Register 1 Value
data[4]: Conter Control Register
*/
- printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n");
- devpriv->s526_gpct_config[subdev_channel].app =
- PulseTrainGeneration;
+ devpriv->gpct_config[chan] = data[0];
/* Set Counter Mode Register */
- cmReg.value = (short)(insn->data[1] & 0xFFFF);
+ cmReg.value = data[1] & 0xffff;
cmReg.reg.preloadRegSel = 0; /* PR0 */
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Load the pre-load register 0 high word */
- value = (short)((insn->data[2] >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ val = (data[2] >> 16) & 0xffff;
+ outw(val, chan_iobase + REG_C0H);
/* Load the pre-load register 0 low word */
- value = (short)(insn->data[2] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ val = data[2] & 0xffff;
+ outw(val, chan_iobase + REG_C0L);
/* Set Counter Mode Register */
- cmReg.value = (short)(insn->data[1] & 0xFFFF);
+ cmReg.value = data[1] & 0xffff;
cmReg.reg.preloadRegSel = 1; /* PR1 */
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+ outw(cmReg.value, chan_iobase + REG_C0M);
/* Load the pre-load register 1 high word */
- value = (short)((insn->data[3] >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ val = (data[3] >> 16) & 0xffff;
+ outw(val, chan_iobase + REG_C0H);
/* Load the pre-load register 1 low word */
- value = (short)(insn->data[3] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ val = data[3] & 0xffff;
+ outw(val, chan_iobase + REG_C0L);
/* Write the Counter Control Register */
- if (insn->data[4] != 0) {
- value = (short)(insn->data[4] & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ if (data[4]) {
+ val = data[4] & 0xffff;
+ outw(val, chan_iobase + REG_C0C);
}
break;
default:
- printk(KERN_ERR "s526: unsupported GPCT_insn_config\n");
return -EINVAL;
break;
}
}
static int s526_gpct_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
unsigned int *data)
{
- int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */
- short value;
- union cmReg cmReg;
-
- printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n",
- subdev_channel);
- cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
- printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value);
- /* Check what Application of Counter this channel is configured for */
- switch (devpriv->s526_gpct_config[subdev_channel].app) {
- case PositionMeasurement:
- printk(KERN_INFO "S526: INSN_WRITE: PM\n");
- outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
- subdev_channel));
- outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
- break;
+ struct s526_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned long chan_iobase = dev->iobase + chan * 8;
- case SinglePulseGeneration:
- printk(KERN_INFO "S526: INSN_WRITE: SPG\n");
- outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
- subdev_channel));
- outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
- break;
+ inw(chan_iobase + REG_C0M); /* Is this read required? */
- case PulseTrainGeneration:
+ /* Check what Application of Counter this channel is configured for */
+ switch (devpriv->gpct_config[chan]) {
+ case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
/* data[0] contains the PULSE_WIDTH
data[1] contains the PULSE_PERIOD
@pre PULSE_PERIOD > PULSE_WIDTH > 0
The above periods must be expressed as a multiple of the
pulse frequency on the selected source
*/
- printk(KERN_INFO "S526: INSN_WRITE: PTG\n");
- if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
- (devpriv->s526_gpct_config[subdev_channel]).data[0] =
- insn->data[0];
- (devpriv->s526_gpct_config[subdev_channel]).data[1] =
- insn->data[1];
- } else {
- printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
- insn->data[0], insn->data[1]);
+ if ((data[1] < data[0]) || !data[0])
return -EINVAL;
- }
- value = (short)((*data >> 16) & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- value = (short)(*data & 0xFFFF);
- outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+ /* Fall thru to write the PULSE_WIDTH */
+
+ case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
+ case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
+ outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H);
+ outw(data[0] & 0xffff, chan_iobase + REG_C0L);
break;
- default: /* Impossible */
- printk
- ("s526: INSN_WRITE: Functionality %d not implemented yet\n",
- devpriv->s526_gpct_config[subdev_channel].app);
+
+ default:
return -EINVAL;
- break;
}
- /* return the number of samples written */
+
return insn->n;
}
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct s526_private *devpriv = dev->private;
int result = -EINVAL;
if (insn->n < 1)
* INSN_READ handler. */
/* Enable ADC interrupt */
- outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
-/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */
- devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
+ outw(ISR_ADC_DONE, dev->iobase + REG_IER);
+ devpriv->ai_config = (data[0] & 0x3ff) << 5;
if (data[1] > 0)
- devpriv->s526_ai_config |= 0x8000; /* set the delay */
+ devpriv->ai_config |= 0x8000; /* set the delay */
- devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */
+ devpriv->ai_config |= 0x0001; /* ADC start bit */
return result;
}
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct s526_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int n, i;
- int chan = CR_CHAN(insn->chanspec);
unsigned short value;
unsigned int d;
unsigned int status;
/* Set configured delay, enable channel for this channel only,
* select "ADC read" channel, set "ADC start" bit. */
- value = (devpriv->s526_ai_config & 0x8000) |
- ((1 << 5) << chan) | (chan << 1) | 0x0001;
+ value = (devpriv->ai_config & 0x8000) |
+ ((1 << 5) << chan) | (chan << 1) | 0x0001;
/* convert n samples */
for (n = 0; n < insn->n; n++) {
/* trigger conversion */
- outw(value, ADDR_REG(REG_ADC));
-/* printk("s526: Wrote 0x%04x to ADC\n", value); */
-/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */
+ outw(value, dev->iobase + REG_ADC);
#define TIMEOUT 100
/* wait for conversion to end */
for (i = 0; i < TIMEOUT; i++) {
- status = inw(ADDR_REG(REG_ISR));
+ status = inw(dev->iobase + REG_ISR);
if (status & ISR_ADC_DONE) {
- outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
+ outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
break;
}
}
- if (i == TIMEOUT) {
- /* printk() should be used instead of printk()
- * whenever the code can be called from real-time. */
- printk(KERN_ERR "s526: ADC(0x%04x) timeout\n",
- inw(ADDR_REG(REG_ISR)));
+ if (i == TIMEOUT)
return -ETIMEDOUT;
- }
/* read data */
- d = inw(ADDR_REG(REG_ADD));
-/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */
+ d = inw(dev->iobase + REG_ADD);
/* munge data */
data[n] = d ^ 0x8000;
static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int i;
- int chan = CR_CHAN(insn->chanspec);
+ struct s526_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
unsigned short val;
+ int i;
-/* printk("s526_ao_winsn\n"); */
val = chan << 1;
-/* outw(val, dev->iobase + REG_DAC); */
- outw(val, ADDR_REG(REG_DAC));
+ outw(val, dev->iobase + REG_DAC);
- /* Writing a list of values to an AO channel is probably not
- * very useful, but that's how the interface is defined. */
for (i = 0; i < insn->n; i++) {
- /* a typical programming sequence */
- /* write the data to preload register
- * outw(data[i], dev->iobase + REG_ADD);
- */
- /* write the data to preload register */
- outw(data[i], ADDR_REG(REG_ADD));
+ outw(data[i], dev->iobase + REG_ADD);
devpriv->ao_readback[chan] = data[i];
-/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */
- outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/
+ /* starts the D/A conversion */
+ outw(val + 1, dev->iobase + REG_DAC);
}
- /* return the number of samples read/written */
return i;
}
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct s526_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
- int chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
return i;
}
-/* DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The
- * comedi core can convert between insn_bits and insn_read/write */
static int s526_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- /* The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit. */
if (data[0]) {
s->state &= ~data[0];
s->state |= data[0] & data[1];
- /* Write out the new digital output lines */
- outw(s->state, ADDR_REG(REG_DIO));
+
+ outw(s->state, dev->iobase + REG_DIO);
}
- /* on return, data[1] contains the value of the digital
- * input and output lines. */
- data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */
- /* or we could just return the software copy of the output values if
- * it was a purely digital output subdevice */
- /* data[1]=s->state & 0xFF; */
+ data[1] = inw(dev->iobase + REG_DIO) & 0xff;
return insn->n;
}
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
int group, mask;
- printk(KERN_INFO "S526 DIO insn_config\n");
-
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
-
group = chan >> 2;
mask = 0xF << (group << 2);
switch (data[0]) {
default:
return -EINVAL;
}
- outw(s->state, ADDR_REG(REG_DIO));
+ outw(s->state, dev->iobase + REG_DIO);
return 1;
}
static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct s526_board *board = comedi_board(dev);
+ struct s526_private *devpriv;
struct comedi_subdevice *s;
int iobase;
- int i, n;
int ret;
-/* short value; */
-/* int subdev_channel = 0; */
- union cmReg cmReg;
- printk(KERN_INFO "comedi%d: s526: ", dev->minor);
+ dev->board_name = dev->driver->driver_name;
iobase = it->options[0];
- if (!iobase || !request_region(iobase, S526_IOSIZE, board->name)) {
+ if (!iobase || !request_region(iobase, S526_IOSIZE, dev->board_name)) {
comedi_error(dev, "I/O port conflict");
return -EIO;
}
dev->iobase = iobase;
- printk("iobase=0x%lx\n", dev->iobase);
-
- /*** make it a little quieter, exw, 8/29/06
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
- inw(ADDR_REG(s526_ports[i])));
- }
- ***/
-
- dev->board_name = board->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct s526_private)) < 0)
- return -ENOMEM;
+ ret = alloc_private(dev, sizeof(*devpriv));
+ if (ret)
+ return ret;
+ devpriv = dev->private;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
- /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
- s->n_chan = board->gpct_chans;
+ s->n_chan = 4;
s->maxdata = 0x00ffffff; /* 24 bit counter */
s->insn_read = s526_gpct_rinsn;
s->insn_config = s526_gpct_insn_config;
s->insn_write = s526_gpct_winsn;
- /* Command are not implemented yet, however they are necessary to
- allocate the necessary memory for the comedi_async struct (used
- to trigger the GPCT in case of pulsegenerator function */
- /* s->do_cmd = s526_gpct_cmd; */
- /* s->do_cmdtest = s526_gpct_cmdtest; */
- /* s->cancel = s526_gpct_cancel; */
-
s = &dev->subdevices[1];
- /* dev->read_subdev=s; */
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
- /* we support differential */
s->subdev_flags = SDF_READABLE | SDF_DIFF;
/* channels 0 to 7 are the regular differential inputs */
/* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
s->n_chan = 10;
s->maxdata = 0xffff;
s->range_table = &range_bipolar10;
- s->len_chanlist = 16; /* This is the maximum chanlist length that
- the board can handle */
+ s->len_chanlist = 16;
s->insn_read = s526_ai_rinsn;
s->insn_config = s526_ai_insn_config;
s = &dev->subdevices[3];
/* digital i/o subdevice */
- if (board->have_dio) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = s526_dio_insn_bits;
- s->insn_config = s526_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-
-#if 0
- /* Example of Counter Application */
- /* One-shot (software trigger) */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 1; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
- cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 2; /* Hardware */
- cmReg.reg.clockSource = 2; /* Internal */
- cmReg.reg.countDir = 1; /* Down */
- cmReg.reg.countDirCtrl = 1; /* Software */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
-
- outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
-
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Reset RCAP (fires one-shot) */
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-
-#else
-
- /* Set Counter Mode Register */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 0; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
- cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
- cmReg.reg.clockSource = 3; /* x4 */
- cmReg.reg.countDir = 0; /* up */
- cmReg.reg.countDirCtrl = 0; /* quadrature */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- n = 0;
- printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
- cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
-
- /* Load the pre-load register high word */
-/* value = (short) (0x55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
-
- /* Load the pre-load register low word */
-/* value = (short)(0xaa55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
-
- /* Write the Counter Control Register */
-/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
-
- /* Reset the counter if it is software preload */
- if (cmReg.reg.autoLoadResetRcap == 0) {
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
- }
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = s526_dio_insn_bits;
+ s->insn_config = s526_dio_insn_config;
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
+ dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-#endif
- printk(KERN_INFO "Current registres:\n");
-
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk(KERN_INFO "0x%02lx: 0x%04x\n",
- ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
- }
return 1;
}
.module = THIS_MODULE,
.attach = s526_attach,
.detach = s526_detach,
- .board_name = &s526_boards[0].name,
- .offset = sizeof(struct s526_board),
- .num_names = ARRAY_SIZE(s526_boards),
};
module_comedi_driver(s526_driver);
usbduxsub_tmp->pwm_cmd_running = 0;
}
-/* common part of attach and attach_usb */
static int usbdux_attach_common(struct comedi_device *dev,
- struct usbduxsub *udev,
- void *aux_data, int aux_len)
+ struct usbduxsub *udev)
{
int ret;
struct comedi_subdevice *s = NULL;
/* pointer back to the corresponding comedi device */
udev->comedidev = dev;
- /* trying to upload the firmware into the chip */
- if (aux_data)
- firmwareUpload(udev, aux_data, aux_len);
-
dev->board_name = "usbdux";
/* set number of subdevices */
return 0;
}
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- int ret;
- int index;
- int i;
- void *aux_data;
- int aux_len;
-
- dev->private = NULL;
-
- aux_data = comedi_aux_data(it->options, 0);
- aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
- if (aux_data == NULL)
- aux_len = 0;
- else if (aux_len == 0)
- aux_data = NULL;
-
- down(&start_stop_sem);
- /* find a valid device which has been detected by the probe function of
- * the usb */
- index = -1;
- for (i = 0; i < NUMUSBDUX; i++) {
- if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
- index = i;
- break;
- }
- }
-
- if (index < 0) {
- printk(KERN_ERR
- "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
- dev->minor);
- ret = -ENODEV;
- } else
- ret = usbdux_attach_common(dev, &usbduxsub[index],
- aux_data, aux_len);
- up(&start_stop_sem);
- return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
static int usbdux_attach_usb(struct comedi_device *dev,
struct usb_interface *uinterf)
{
dev->minor);
ret = -ENODEV;
} else
- ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+ ret = usbdux_attach_common(dev, this_usbduxsub);
up(&start_stop_sem);
return ret;
}
static struct comedi_driver usbdux_driver = {
.driver_name = "usbdux",
.module = THIS_MODULE,
- .attach = usbdux_attach,
- .detach = usbdux_detach,
.attach_usb = usbdux_attach_usb,
+ .detach = usbdux_detach,
};
static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
udfs->ai_cmd_running = 0;
}
-/* common part of attach and attach_usb */
static int usbduxfast_attach_common(struct comedi_device *dev,
- struct usbduxfastsub_s *udfs,
- void *aux_data, int aux_len)
+ struct usbduxfastsub_s *udfs)
{
int ret;
struct comedi_subdevice *s;
down(&udfs->sem);
/* pointer back to the corresponding comedi device */
udfs->comedidev = dev;
- /* trying to upload the firmware into the chip */
- if (aux_data)
- firmwareUpload(udfs, aux_data, aux_len);
dev->board_name = "usbduxfast";
ret = comedi_alloc_subdevices(dev, 1);
if (ret) {
return 0;
}
-/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
-static int usbduxfast_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- int ret;
- int index;
- int i;
- void *aux_data;
- int aux_len;
-
- dev->private = NULL;
-
- aux_data = comedi_aux_data(it->options, 0);
- aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
- if (aux_data == NULL)
- aux_len = 0;
- else if (aux_len == 0)
- aux_data = NULL;
- down(&start_stop_sem);
- /*
- * find a valid device which has been detected by the
- * probe function of the usb
- */
- index = -1;
- for (i = 0; i < NUMUSBDUXFAST; i++) {
- if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) {
- index = i;
- break;
- }
- }
- if (index < 0) {
- dev_err(dev->class_dev,
- "usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n");
- ret = -ENODEV;
- } else
- ret = usbduxfast_attach_common(dev, &usbduxfastsub[index],
- aux_data, aux_len);
- up(&start_stop_sem);
- return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
static int usbduxfast_attach_usb(struct comedi_device *dev,
struct usb_interface *uinterf)
{
"usbduxfast: error: attach_usb failed, already attached\n");
ret = -ENODEV;
} else
- ret = usbduxfast_attach_common(dev, udfs, NULL, 0);
+ ret = usbduxfast_attach_common(dev, udfs);
up(&start_stop_sem);
return ret;
}
static struct comedi_driver usbduxfast_driver = {
.driver_name = "usbduxfast",
.module = THIS_MODULE,
- .attach = usbduxfast_attach,
- .detach = usbduxfast_detach,
.attach_usb = usbduxfast_attach_usb,
+ .detach = usbduxfast_detach,
};
static void usbduxfast_firmware_request_complete_handler(const struct firmware
usbduxsub_tmp->pwm_cmd_running = 0;
}
-/* common part of attach and attach_usb */
static int usbduxsigma_attach_common(struct comedi_device *dev,
- struct usbduxsub *uds,
- void *aux_data, int aux_len)
+ struct usbduxsub *uds)
{
int ret;
struct comedi_subdevice *s;
down(&uds->sem);
/* pointer back to the corresponding comedi device */
uds->comedidev = dev;
- /* trying to upload the firmware into the FX2 */
- if (aux_data)
- firmwareUpload(uds, aux_data, aux_len);
dev->board_name = "usbduxsigma";
/* set number of subdevices */
if (uds->high_speed)
return 0;
}
-/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */
-static int usbduxsigma_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- int ret;
- int index;
- int i;
- void *aux_data;
- int aux_len;
-
- dev->private = NULL;
-
- aux_data = comedi_aux_data(it->options, 0);
- aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
- if (aux_data == NULL)
- aux_len = 0;
- else if (aux_len == 0)
- aux_data = NULL;
-
- down(&start_stop_sem);
- /* find a valid device which has been detected by the probe function of
- * the usb */
- index = -1;
- for (i = 0; i < NUMUSBDUX; i++) {
- if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
- index = i;
- break;
- }
- }
- if (index < 0) {
- dev_err(dev->class_dev,
- "usbduxsigma: error: attach failed, dev not connected to the usb bus.\n");
- ret = -ENODEV;
- } else
- ret = usbduxsigma_attach_common(dev, &usbduxsub[index],
- aux_data, aux_len);
- up(&start_stop_sem);
- return ret;
-}
-
-/* is called from comedi_usb_auto_config() */
static int usbduxsigma_attach_usb(struct comedi_device *dev,
struct usb_interface *uinterf)
{
"usbduxsigma: error: attach_usb failed, already attached\n");
ret = -ENODEV;
} else
- ret = usbduxsigma_attach_common(dev, uds, NULL, 0);
+ ret = usbduxsigma_attach_common(dev, uds);
up(&start_stop_sem);
return ret;
}
static struct comedi_driver usbduxsigma_driver = {
.driver_name = "usbduxsigma",
.module = THIS_MODULE,
- .attach = usbduxsigma_attach,
- .detach = usbduxsigma_detach,
.attach_usb = usbduxsigma_attach_usb,
+ .detach = usbduxsigma_detach,
};
static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
}
EXPORT_SYMBOL(comedi_close);
-static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
+static int comedi_do_insn(struct comedi_device *dev,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct comedi_subdevice *s;
int ret = 0;
switch (insn->insn) {
case INSN_BITS:
- ret = s->insn_bits(dev, s, insn, insn->data);
+ ret = s->insn_bits(dev, s, insn, data);
break;
case INSN_CONFIG:
/* XXX should check instruction length */
- ret = s->insn_config(dev, s, insn, insn->data);
+ ret = s->insn_config(dev, s, insn, data);
break;
default:
ret = -EINVAL;
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_CONFIG;
insn.n = 1;
- insn.data = &io;
insn.subdev = subdev;
insn.chanspec = CR_PACK(chan, 0, 0);
- return comedi_do_insn(dev, &insn);
+ return comedi_do_insn(dev, &insn, &io);
}
EXPORT_SYMBOL(comedi_dio_config);
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_BITS;
insn.n = 2;
- insn.data = data;
insn.subdev = subdev;
data[0] = mask;
data[1] = *bits;
- ret = comedi_do_insn(dev, &insn);
+ ret = comedi_do_insn(dev, &insn, data);
*bits = data[1];
/*
- * This file also contains the implementation of the asyncronous
+ * This file also contains the implementation of the asynchronous
* requests to the SME.
*
- * Before calling an asyncronous SME function, we call sme_init_request()
+ * Before calling an asynchronous SME function, we call sme_init_request()
* which gets hold of the SME semaphore and updates the request status.
* The semaphore makes sure that there is only one pending request to
* the SME at a time.
--- /dev/null
+config DRM_IMX
+ tristate "DRM Support for Freescale i.MX"
+ select DRM_KMS_HELPER
+ select DRM_GEM_CMA_HELPER
+ select DRM_KMS_CMA_HELPER
+ depends on DRM && ARCH_MXC
+ help
+ enable i.MX graphics support
+
+config DRM_IMX_FB_HELPER
+ tristate "provide legacy framebuffer /dev/fb0"
+ select DRM_KMS_CMA_HELPER
+ depends on DRM_IMX
+ help
+ The DRM framework can provide a legacy /dev/fb0 framebuffer
+ for your device. This is necessary to get a framebuffer console
+ and also for appplications using the legacy framebuffer API
+
+config DRM_IMX_PARALLEL_DISPLAY
+ tristate "Support for parallel displays"
+ depends on DRM_IMX
+
+config DRM_IMX_IPUV3_CORE
+ tristate "IPUv3 core support"
+ depends on DRM_IMX
+ help
+ Choose this if you have a i.MX5/6 system and want
+ to use the IPU. This option only enables IPU base
+ support.
+
+config DRM_IMX_IPUV3
+ tristate "DRM Support for i.MX IPUv3"
+ depends on DRM_IMX
+ help
+ Choose this if you have a i.MX5 or i.MX6 processor.
--- /dev/null
+
+imxdrm-objs := imx-drm-core.o imx-fb.o
+
+obj-$(CONFIG_DRM_IMX) += imxdrm.o
+
+obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
+obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
+obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
+obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o
--- /dev/null
+TODO:
+- get DRM Maintainer review for this code
+- Factor out more code to common helper functions
+- decide where to put the base driver. It is not specific to a subsystem
+ and would be used by DRM/KMS and media/V4L2
+- convert irq driver to irq_domain_add_linear
+
+Missing features (not necessarily for moving out of staging):
+
+- Add KMS plane support for CRTC driver
+- Add LDB (LVDS Display Bridge) support
+- Add i.MX6 HDMI support
+- Add support for IC (Image converter)
+- Add support for CSI (CMOS Sensor interface)
+- Add support for VDIC (Video Deinterlacer)
+
+Many work-in-progress patches for the above features exist. Contact
+Sascha Hauer <kernel@pengutronix.de> if you are interested in working
+on a specific feature.
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and
+Sascha Hauer <kernel@pengutronix.de>
--- /dev/null
+/*
+ * Freescale i.MX drm driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+#define MAX_CRTC 4
+
+struct crtc_cookie {
+ void *cookie;
+ int id;
+ struct list_head list;
+};
+
+struct imx_drm_device {
+ struct drm_device *drm;
+ struct device *dev;
+ struct list_head crtc_list;
+ struct list_head encoder_list;
+ struct list_head connector_list;
+ struct mutex mutex;
+ int references;
+ int pipes;
+ struct drm_fbdev_cma *fbhelper;
+};
+
+struct imx_drm_crtc {
+ struct drm_crtc *crtc;
+ struct list_head list;
+ struct imx_drm_device *imxdrm;
+ int pipe;
+ struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
+ struct module *owner;
+ struct crtc_cookie cookie;
+};
+
+struct imx_drm_encoder {
+ struct drm_encoder *encoder;
+ struct list_head list;
+ struct module *owner;
+ struct list_head possible_crtcs;
+};
+
+struct imx_drm_connector {
+ struct drm_connector *connector;
+ struct list_head list;
+ struct module *owner;
+};
+
+static int imx_drm_driver_firstopen(struct drm_device *drm)
+{
+ if (!imx_drm_device_get())
+ return -EINVAL;
+
+ return 0;
+}
+
+static void imx_drm_driver_lastclose(struct drm_device *drm)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+
+ if (imxdrm->fbhelper)
+ drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+
+ imx_drm_device_put();
+}
+
+static int imx_drm_driver_unload(struct drm_device *drm)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+
+ drm_mode_config_cleanup(imxdrm->drm);
+ drm_kms_helper_poll_fini(imxdrm->drm);
+
+ return 0;
+}
+
+/*
+ * We don't care at all for crtc numbers, but the core expects the
+ * crtcs to be numbered
+ */
+static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
+ int num)
+{
+ struct imx_drm_crtc *imx_drm_crtc;
+
+ list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
+ if (imx_drm_crtc->pipe == num)
+ return imx_drm_crtc;
+ return NULL;
+}
+
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+ u32 interface_pix_fmt)
+{
+ struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+ struct imx_drm_crtc *imx_crtc;
+ struct imx_drm_crtc_helper_funcs *helper;
+
+ mutex_lock(&imxdrm->mutex);
+
+ list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+ if (imx_crtc->crtc == crtc)
+ goto found;
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return -EINVAL;
+found:
+ mutex_unlock(&imxdrm->mutex);
+
+ helper = &imx_crtc->imx_drm_helper_funcs;
+ if (helper->set_interface_pix_fmt)
+ return helper->set_interface_pix_fmt(crtc,
+ encoder_type, interface_pix_fmt);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
+{
+ return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
+
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
+{
+ drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
+
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
+{
+ drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
+
+static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+ struct imx_drm_crtc *imx_drm_crtc;
+ int ret;
+
+ imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
+ if (!imx_drm_crtc)
+ return -EINVAL;
+
+ if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
+ return -ENOSYS;
+
+ ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
+ imx_drm_crtc->crtc);
+
+ return ret;
+}
+
+static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+ struct imx_drm_crtc *imx_drm_crtc;
+
+ imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
+ if (!imx_drm_crtc)
+ return;
+
+ if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
+ return;
+
+ imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
+}
+
+static const struct file_operations imx_drm_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = drm_gem_cma_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+ .read = drm_read,
+ .llseek = noop_llseek,
+};
+
+static struct imx_drm_device *imx_drm_device;
+
+static struct imx_drm_device *__imx_drm_device(void)
+{
+ return imx_drm_device;
+}
+
+struct drm_device *imx_drm_device_get(void)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_encoder *enc;
+ struct imx_drm_connector *con;
+ struct imx_drm_crtc *crtc;
+
+ mutex_lock(&imxdrm->mutex);
+
+ list_for_each_entry(enc, &imxdrm->encoder_list, list) {
+ if (!try_module_get(enc->owner)) {
+ dev_err(imxdrm->dev, "could not get module %s\n",
+ module_name(enc->owner));
+ goto unwind_enc;
+ }
+ }
+
+ list_for_each_entry(con, &imxdrm->connector_list, list) {
+ if (!try_module_get(con->owner)) {
+ dev_err(imxdrm->dev, "could not get module %s\n",
+ module_name(con->owner));
+ goto unwind_con;
+ }
+ }
+
+ list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
+ if (!try_module_get(crtc->owner)) {
+ dev_err(imxdrm->dev, "could not get module %s\n",
+ module_name(crtc->owner));
+ goto unwind_crtc;
+ }
+ }
+
+ imxdrm->references++;
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return imxdrm->drm;
+
+unwind_crtc:
+ list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
+ module_put(crtc->owner);
+unwind_con:
+ list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
+ module_put(con->owner);
+unwind_enc:
+ list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
+ module_put(enc->owner);
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return NULL;
+
+}
+EXPORT_SYMBOL_GPL(imx_drm_device_get);
+
+void imx_drm_device_put(void)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_encoder *enc;
+ struct imx_drm_connector *con;
+ struct imx_drm_crtc *crtc;
+
+ mutex_lock(&imxdrm->mutex);
+
+ list_for_each_entry(crtc, &imxdrm->crtc_list, list)
+ module_put(crtc->owner);
+
+ list_for_each_entry(con, &imxdrm->connector_list, list)
+ module_put(con->owner);
+
+ list_for_each_entry(enc, &imxdrm->encoder_list, list)
+ module_put(enc->owner);
+
+ imxdrm->references--;
+
+ mutex_unlock(&imxdrm->mutex);
+}
+EXPORT_SYMBOL_GPL(imx_drm_device_put);
+
+static int drm_mode_group_reinit(struct drm_device *dev)
+{
+ struct drm_mode_group *group = &dev->primary->mode_group;
+ uint32_t *id_list = group->id_list;
+ int ret;
+
+ ret = drm_mode_group_init_legacy_group(dev, group);
+ if (ret < 0)
+ return ret;
+
+ kfree(id_list);
+ return 0;
+}
+
+/*
+ * register an encoder to the drm core
+ */
+static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
+
+ drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
+ imx_drm_encoder->encoder->funcs,
+ imx_drm_encoder->encoder->encoder_type);
+
+ drm_mode_group_reinit(imxdrm->drm);
+
+ return 0;
+}
+
+/*
+ * unregister an encoder from the drm core
+ */
+static void imx_drm_encoder_unregister(struct imx_drm_encoder
+ *imx_drm_encoder)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ drm_encoder_cleanup(imx_drm_encoder->encoder);
+
+ drm_mode_group_reinit(imxdrm->drm);
+}
+
+/*
+ * register a connector to the drm core
+ */
+static int imx_drm_connector_register(
+ struct imx_drm_connector *imx_drm_connector)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
+ imx_drm_connector->connector->funcs,
+ imx_drm_connector->connector->connector_type);
+ drm_mode_group_reinit(imxdrm->drm);
+
+ return drm_sysfs_connector_add(imx_drm_connector->connector);
+}
+
+/*
+ * unregister a connector from the drm core
+ */
+static void imx_drm_connector_unregister(
+ struct imx_drm_connector *imx_drm_connector)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ drm_sysfs_connector_remove(imx_drm_connector->connector);
+ drm_connector_cleanup(imx_drm_connector->connector);
+
+ drm_mode_group_reinit(imxdrm->drm);
+}
+
+/*
+ * register a crtc to the drm core
+ */
+static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ int ret;
+
+ drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
+ imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+ ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
+ if (ret)
+ return ret;
+
+ drm_crtc_helper_add(imx_drm_crtc->crtc,
+ imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+ drm_mode_group_reinit(imxdrm->drm);
+
+ return 0;
+}
+
+/*
+ * Called by the CRTC driver when all CRTCs are registered. This
+ * puts all the pieces together and initializes the driver.
+ * Once this is called no more CRTCs can be registered since
+ * the drm core has hardcoded the number of crtcs in several
+ * places.
+ */
+static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ int ret;
+
+ imxdrm->drm = drm;
+
+ drm->dev_private = imxdrm;
+
+ /*
+ * enable drm irq mode.
+ * - with irq_enabled = 1, we can use the vblank feature.
+ *
+ * P.S. note that we wouldn't use drm irq handler but
+ * just specific driver own one instead because
+ * drm framework supports only one irq handler and
+ * drivers can well take care of their interrupts
+ */
+ drm->irq_enabled = 1;
+
+ drm_mode_config_init(drm);
+ imx_drm_mode_config_init(drm);
+
+ mutex_lock(&imxdrm->mutex);
+
+ drm_kms_helper_poll_init(imxdrm->drm);
+
+ /* setup the grouping for the legacy output */
+ ret = drm_mode_group_init_legacy_group(imxdrm->drm,
+ &imxdrm->drm->primary->mode_group);
+ if (ret)
+ goto err_init;
+
+ ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+ if (ret)
+ goto err_init;
+
+ /*
+ * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+ * by drm timer once a current process gives up ownership of
+ * vblank event.(after drm_vblank_put function is called)
+ */
+ imxdrm->drm->vblank_disable_allowed = 1;
+
+ ret = 0;
+
+err_init:
+ mutex_unlock(&imxdrm->mutex);
+
+ return ret;
+}
+
+static void imx_drm_update_possible_crtcs(void)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_encoder *enc;
+ struct crtc_cookie *cookie;
+
+ list_for_each_entry(enc, &imxdrm->encoder_list, list) {
+ u32 possible_crtcs = 0;
+
+ list_for_each_entry(cookie, &enc->possible_crtcs, list) {
+ list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
+ if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
+ imx_drm_crtc->cookie.id == cookie->id) {
+ possible_crtcs |= 1 << imx_drm_crtc->pipe;
+ }
+ }
+ }
+ enc->encoder->possible_crtcs = possible_crtcs;
+ enc->encoder->possible_clones = possible_crtcs;
+ }
+}
+
+/*
+ * imx_drm_add_crtc - add a new crtc
+ *
+ * The return value if !NULL is a cookie for the caller to pass to
+ * imx_drm_remove_crtc later.
+ */
+int imx_drm_add_crtc(struct drm_crtc *crtc,
+ struct imx_drm_crtc **new_crtc,
+ const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
+ struct module *owner, void *cookie, int id)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_crtc *imx_drm_crtc;
+ const struct drm_crtc_funcs *crtc_funcs;
+ int ret;
+
+ mutex_lock(&imxdrm->mutex);
+
+ if (imxdrm->references) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
+
+ imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
+ if (!imx_drm_crtc) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
+ imx_drm_crtc->pipe = imxdrm->pipes++;
+ imx_drm_crtc->cookie.cookie = cookie;
+ imx_drm_crtc->cookie.id = id;
+
+ crtc_funcs = imx_drm_helper_funcs->crtc_funcs;
+
+ imx_drm_crtc->crtc = crtc;
+ imx_drm_crtc->imxdrm = imxdrm;
+
+ imx_drm_crtc->owner = owner;
+
+ list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+
+ *new_crtc = imx_drm_crtc;
+
+ ret = imx_drm_crtc_register(imx_drm_crtc);
+ if (ret)
+ goto err_register;
+
+ imx_drm_update_possible_crtcs();
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return 0;
+
+err_register:
+ kfree(imx_drm_crtc);
+err_alloc:
+err_busy:
+ mutex_unlock(&imxdrm->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
+
+/*
+ * imx_drm_remove_crtc - remove a crtc
+ */
+int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
+{
+ struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
+
+ mutex_lock(&imxdrm->mutex);
+
+ drm_crtc_cleanup(imx_drm_crtc->crtc);
+
+ list_del(&imx_drm_crtc->list);
+
+ drm_mode_group_reinit(imxdrm->drm);
+
+ mutex_unlock(&imxdrm->mutex);
+
+ kfree(imx_drm_crtc);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
+
+/*
+ * imx_drm_add_encoder - add a new encoder
+ */
+int imx_drm_add_encoder(struct drm_encoder *encoder,
+ struct imx_drm_encoder **newenc, struct module *owner)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_encoder *imx_drm_encoder;
+ int ret;
+
+ mutex_lock(&imxdrm->mutex);
+
+ if (imxdrm->references) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
+
+ imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
+ if (!imx_drm_encoder) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ imx_drm_encoder->encoder = encoder;
+ imx_drm_encoder->owner = owner;
+
+ ret = imx_drm_encoder_register(imx_drm_encoder);
+ if (ret) {
+ kfree(imx_drm_encoder);
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
+
+ *newenc = imx_drm_encoder;
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return 0;
+
+err_register:
+ kfree(imx_drm_encoder);
+err_alloc:
+err_busy:
+ mutex_unlock(&imxdrm->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
+
+int imx_drm_encoder_add_possible_crtcs(
+ struct imx_drm_encoder *imx_drm_encoder,
+ struct device_node *np)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct of_phandle_args args;
+ struct crtc_cookie *c;
+ int ret = 0;
+ int i;
+
+ if (!list_empty(&imx_drm_encoder->possible_crtcs))
+ return -EBUSY;
+
+ for (i = 0; !ret; i++) {
+ ret = of_parse_phandle_with_args(np, "crtcs",
+ "#crtc-cells", i, &args);
+ if (ret < 0)
+ break;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ of_node_put(args.np);
+ return -ENOMEM;
+ }
+
+ c->cookie = args.np;
+ c->id = args.args_count > 0 ? args.args[0] : 0;
+
+ of_node_put(args.np);
+
+ mutex_lock(&imxdrm->mutex);
+
+ list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
+
+ mutex_unlock(&imxdrm->mutex);
+ }
+
+ imx_drm_update_possible_crtcs();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
+
+int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
+ struct drm_crtc *crtc)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_crtc *imx_crtc;
+ int i = 0;
+
+ mutex_lock(&imxdrm->mutex);
+
+ list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
+ if (imx_crtc->crtc == crtc)
+ goto found;
+ i++;
+ }
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return -EINVAL;
+found:
+ mutex_unlock(&imxdrm->mutex);
+
+ return i;
+}
+
+/*
+ * imx_drm_remove_encoder - remove an encoder
+ */
+int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct crtc_cookie *c, *tmp;
+
+ mutex_lock(&imxdrm->mutex);
+
+ imx_drm_encoder_unregister(imx_drm_encoder);
+
+ list_del(&imx_drm_encoder->list);
+
+ list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
+ list)
+ kfree(c);
+
+ mutex_unlock(&imxdrm->mutex);
+
+ kfree(imx_drm_encoder);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
+
+/*
+ * imx_drm_add_connector - add a connector
+ */
+int imx_drm_add_connector(struct drm_connector *connector,
+ struct imx_drm_connector **new_con,
+ struct module *owner)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_connector *imx_drm_connector;
+ int ret;
+
+ mutex_lock(&imxdrm->mutex);
+
+ if (imxdrm->references) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
+
+ imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
+ if (!imx_drm_connector) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ imx_drm_connector->connector = connector;
+ imx_drm_connector->owner = owner;
+
+ ret = imx_drm_connector_register(imx_drm_connector);
+ if (ret)
+ goto err_register;
+
+ list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
+
+ *new_con = imx_drm_connector;
+
+ mutex_unlock(&imxdrm->mutex);
+
+ return 0;
+
+err_register:
+ kfree(imx_drm_connector);
+err_alloc:
+err_busy:
+ mutex_unlock(&imxdrm->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_connector);
+
+void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ imxdrm->fbhelper = fbdev_helper;
+}
+EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
+
+/*
+ * imx_drm_remove_connector - remove a connector
+ */
+int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
+{
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+
+ mutex_lock(&imxdrm->mutex);
+
+ imx_drm_connector_unregister(imx_drm_connector);
+
+ list_del(&imx_drm_connector->list);
+
+ mutex_unlock(&imxdrm->mutex);
+
+ kfree(imx_drm_connector);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
+
+static struct drm_ioctl_desc imx_drm_ioctls[] = {
+ /* none so far */
+};
+
+static struct drm_driver imx_drm_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM,
+ .load = imx_drm_driver_load,
+ .unload = imx_drm_driver_unload,
+ .firstopen = imx_drm_driver_firstopen,
+ .lastclose = imx_drm_driver_lastclose,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_cma_dumb_destroy,
+
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = imx_drm_enable_vblank,
+ .disable_vblank = imx_drm_disable_vblank,
+ .ioctls = imx_drm_ioctls,
+ .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
+ .fops = &imx_drm_driver_fops,
+ .name = "imx-drm",
+ .desc = "i.MX DRM graphics",
+ .date = "20120507",
+ .major = 1,
+ .minor = 0,
+ .patchlevel = 0,
+};
+
+static int imx_drm_platform_probe(struct platform_device *pdev)
+{
+ imx_drm_device->dev = &pdev->dev;
+
+ return drm_platform_init(&imx_drm_driver, pdev);
+}
+
+static int imx_drm_platform_remove(struct platform_device *pdev)
+{
+ drm_platform_exit(&imx_drm_driver, pdev);
+
+ return 0;
+}
+
+static struct platform_driver imx_drm_pdrv = {
+ .probe = imx_drm_platform_probe,
+ .remove = __devexit_p(imx_drm_platform_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "imx-drm",
+ },
+};
+
+static struct platform_device *imx_drm_pdev;
+
+static int __init imx_drm_init(void)
+{
+ int ret;
+
+ imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
+ if (!imx_drm_device)
+ return -ENOMEM;
+
+ mutex_init(&imx_drm_device->mutex);
+ INIT_LIST_HEAD(&imx_drm_device->crtc_list);
+ INIT_LIST_HEAD(&imx_drm_device->connector_list);
+ INIT_LIST_HEAD(&imx_drm_device->encoder_list);
+
+ imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
+ if (!imx_drm_pdev) {
+ ret = -EINVAL;
+ goto err_pdev;
+ }
+
+ imx_drm_pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32),
+
+ ret = platform_driver_register(&imx_drm_pdrv);
+ if (ret)
+ goto err_pdrv;
+
+ return 0;
+
+err_pdrv:
+ platform_device_unregister(imx_drm_pdev);
+err_pdev:
+ kfree(imx_drm_device);
+
+ return ret;
+}
+
+static void __exit imx_drm_exit(void)
+{
+ platform_device_unregister(imx_drm_pdev);
+ platform_driver_unregister(&imx_drm_pdrv);
+
+ kfree(imx_drm_device);
+}
+
+module_init(imx_drm_init);
+module_exit(imx_drm_exit);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX drm driver core");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef _IMX_DRM_H_
+#define _IMX_DRM_H_
+
+struct imx_drm_crtc;
+struct drm_fbdev_cma;
+
+struct imx_drm_crtc_helper_funcs {
+ int (*enable_vblank)(struct drm_crtc *crtc);
+ void (*disable_vblank)(struct drm_crtc *crtc);
+ int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
+ u32 pix_fmt);
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs;
+ const struct drm_crtc_funcs *crtc_funcs;
+};
+
+int imx_drm_add_crtc(struct drm_crtc *crtc,
+ struct imx_drm_crtc **new_crtc,
+ const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
+ struct module *owner, void *cookie, int id);
+int imx_drm_remove_crtc(struct imx_drm_crtc *);
+int imx_drm_init_drm(struct platform_device *pdev,
+ int preferred_bpp);
+int imx_drm_exit_drm(void);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
+
+struct imx_drm_encoder;
+int imx_drm_add_encoder(struct drm_encoder *encoder,
+ struct imx_drm_encoder **new_enc,
+ struct module *owner);
+int imx_drm_remove_encoder(struct imx_drm_encoder *);
+
+struct imx_drm_connector;
+int imx_drm_add_connector(struct drm_connector *connector,
+ struct imx_drm_connector **new_con,
+ struct module *owner);
+int imx_drm_remove_connector(struct imx_drm_connector *);
+
+void imx_drm_mode_config_init(struct drm_device *drm);
+
+struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+
+struct drm_device *imx_drm_device_get(void);
+void imx_drm_device_put(void);
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+ u32 interface_pix_fmt);
+void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
+
+struct device_node;
+
+int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
+ struct drm_crtc *crtc);
+int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
+ struct device_node *np);
+
+#endif /* _IMX_DRM_H_ */
--- /dev/null
+/*
+ * i.MX drm driver
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * Based on Samsung Exynos code
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+};
+
+void imx_drm_mode_config_init(struct drm_device *dev)
+{
+ dev->mode_config.min_width = 64;
+ dev->mode_config.min_height = 64;
+
+ /*
+ * set max width and height as default value(4096x4096).
+ * this value would be used to check framebuffer size limitation
+ * at drm_mode_addfb().
+ */
+ dev->mode_config.max_width = 4096;
+ dev->mode_config.max_height = 4096;
+
+ dev->mode_config.funcs = &imx_drm_mode_config_funcs;
+}
--- /dev/null
+/*
+ * i.MX drm driver
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * Based on Samsung Exynos code
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "imx-drm.h"
+
+#define MAX_CONNECTOR 4
+#define PREFERRED_BPP 16
+
+static struct drm_fbdev_cma *fbdev_cma;
+
+static int legacyfb_depth = 16;
+
+module_param(legacyfb_depth, int, 0444);
+
+static int __init imx_fb_helper_init(void)
+{
+ struct drm_device *drm = imx_drm_device_get();
+
+ if (!drm)
+ return -EINVAL;
+
+ if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+ pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
+ legacyfb_depth = 16;
+ }
+
+ fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
+ drm->mode_config.num_crtc, MAX_CONNECTOR);
+
+ if (IS_ERR(fbdev_cma)) {
+ imx_drm_device_put();
+ return PTR_ERR(fbdev_cma);
+ }
+
+ imx_drm_fb_helper_set(fbdev_cma);
+
+ return 0;
+}
+
+static void __exit imx_fb_helper_exit(void)
+{
+ imx_drm_fb_helper_set(NULL);
+ drm_fbdev_cma_fini(fbdev_cma);
+ imx_drm_device_put();
+}
+
+late_initcall(imx_fb_helper_init);
+module_exit(imx_fb_helper_exit);
+
+MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
--- /dev/null
+obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
--- /dev/null
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __DRM_IPU_H__
+#define __DRM_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+#include <linux/fb.h>
+#include <linux/videodev2.h>
+
+struct ipu_soc;
+
+enum ipuv3_type {
+ IPUV3EX,
+ IPUV3M,
+ IPUV3H,
+};
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+ unsigned datamask_en:1;
+ unsigned interlaced:1;
+ unsigned odd_field_first:1;
+ unsigned clksel_en:1;
+ unsigned clkidle_en:1;
+ unsigned data_pol:1; /* true = inverted */
+ unsigned clk_pol:1; /* true = rising edge */
+ unsigned enable_pol:1;
+ unsigned Hsync_pol:1; /* true = active high */
+ unsigned Vsync_pol:1;
+
+ u16 width;
+ u16 height;
+ u32 pixel_fmt;
+ u16 h_start_width;
+ u16 h_sync_width;
+ u16 h_end_width;
+ u16 v_start_width;
+ u16 v_sync_width;
+ u16 v_end_width;
+ u32 v_to_h_sync;
+ unsigned long pixelclock;
+#define IPU_DI_CLKMODE_SYNC (1 << 0)
+#define IPU_DI_CLKMODE_EXT (1 << 1)
+ unsigned long clkflags;
+};
+
+enum ipu_color_space {
+ IPUV3_COLORSPACE_RGB,
+ IPUV3_COLORSPACE_YUV,
+ IPUV3_COLORSPACE_UNKNOWN,
+};
+
+struct ipuv3_channel;
+
+enum ipu_channel_irq {
+ IPU_IRQ_EOF = 0,
+ IPU_IRQ_NFACK = 64,
+ IPU_IRQ_NFB4EOF = 128,
+ IPU_IRQ_EOS = 192,
+};
+
+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+ enum ipu_channel_irq irq);
+
+#define IPU_IRQ_DP_SF_START (448 + 2)
+#define IPU_IRQ_DP_SF_END (448 + 3)
+#define IPU_IRQ_BG_SF_END IPU_IRQ_DP_SF_END,
+#define IPU_IRQ_DC_FC_0 (448 + 8)
+#define IPU_IRQ_DC_FC_1 (448 + 9)
+#define IPU_IRQ_DC_FC_2 (448 + 10)
+#define IPU_IRQ_DC_FC_3 (448 + 11)
+#define IPU_IRQ_DC_FC_4 (448 + 12)
+#define IPU_IRQ_DC_FC_6 (448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0 (448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1 (448 + 15)
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
+void ipu_idmac_put(struct ipuv3_channel *);
+
+int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
+int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+ bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+struct ipu_dc;
+struct ipu_di;
+struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
+void ipu_dc_put(struct ipu_dc *dc);
+int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+ u32 pixel_fmt, u32 width);
+void ipu_dc_enable_channel(struct ipu_dc *dc);
+void ipu_dc_disable_channel(struct ipu_dc *dc);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp);
+void ipu_di_put(struct ipu_di *);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_get_num(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+ unsigned long bandwidth_mbs, int burstsize);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC_BG 0
+#define IPU_DP_FLOW_SYNC_FG 1
+#define IPU_DP_FLOW_ASYNC0_BG 2
+#define IPU_DP_FLOW_ASYNC0_FG 3
+#define IPU_DP_FLOW_ASYNC1_BG 4
+#define IPU_DP_FLOW_ASYNC1_FG 5
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp,
+ enum ipu_color_space in, enum ipu_color_space out);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+ bool bg_chan);
+
+#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
+#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
+#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
+#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
+#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
+#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
+
+#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
+#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
+#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
+#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
+#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
+#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
+#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
+#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
+#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
+#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
+#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
+#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
+#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
+#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
+#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
+#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
+#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
+#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
+#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
+#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
+#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
+#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
+#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
+#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
+#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
+#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
+#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
+#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
+#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
+#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
+#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
+#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
+#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
+#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
+#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
+#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
+#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
+#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
+#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
+#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
+#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
+#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
+#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
+#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
+#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
+#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
+#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
+
+struct ipu_cpmem_word {
+ u32 data[5];
+ u32 res[3];
+};
+
+struct ipu_ch_param {
+ struct ipu_cpmem_word word[2];
+};
+
+void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
+u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
+struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
+void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
+
+static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
+{
+ int i;
+ void __iomem *base = p;
+
+ for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+ writel(0, base + i * sizeof(u32));
+}
+
+static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
+ int bufnum, dma_addr_t buf)
+{
+ if (bufnum)
+ ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
+ else
+ ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
+}
+
+static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
+ int xres, int yres)
+{
+ ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
+}
+
+static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
+ int stride)
+{
+ ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
+}
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
+
+struct ipu_rgb {
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+ int bits_per_pixel;
+};
+
+struct ipu_image {
+ struct v4l2_pix_format pix;
+ struct v4l2_rect rect;
+ dma_addr_t phys;
+};
+
+int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
+ int width);
+
+int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
+ struct ipu_rgb *rgb);
+
+static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
+ int stride)
+{
+ ipu_ch_param_write_field(p, IPU_FIELD_SO, 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8);
+ ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1);
+};
+
+void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
+ int stride, int height);
+void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
+ u32 pixel_format, int stride, int u_offset, int v_offset);
+int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
+int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
+ struct ipu_image *image);
+
+enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
+
+static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
+ int burstsize)
+{
+ ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1);
+};
+
+struct ipu_client_platformdata {
+ int di;
+ int dc;
+ int dp;
+ int dmfc;
+ int dma[2];
+};
+
+#endif /* __DRM_IPU_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <asm/mach/irq.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
+{
+ writel(value, ipu->cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+ unsigned offset)
+{
+ writel(value, ipu->idmac_reg + offset);
+}
+
+void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
+{
+ u32 val;
+
+ val = ipu_cm_read(ipu, IPU_SRM_PRI2);
+ val |= 0x8;
+ ipu_cm_write(ipu, val, IPU_SRM_PRI2);
+}
+EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
+
+struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+
+ return ipu->cpmem_base + channel->num;
+}
+EXPORT_SYMBOL_GPL(ipu_get_cpmem);
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
+ u32 val;
+
+ if (ipu->ipu_type == IPUV3EX)
+ ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
+
+ val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
+ val |= 1 << (channel->num % 32);
+ ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+
+void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
+{
+ u32 bit = (wbs >> 8) % 160;
+ u32 size = wbs & 0xff;
+ u32 word = (wbs >> 8) / 160;
+ u32 i = bit / 32;
+ u32 ofs = bit % 32;
+ u32 mask = (1 << size) - 1;
+ u32 val;
+
+ pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+ val = readl(&base->word[word].data[i]);
+ val &= ~(mask << ofs);
+ val |= v << ofs;
+ writel(val, &base->word[word].data[i]);
+
+ if ((bit + size - 1) / 32 > i) {
+ val = readl(&base->word[word].data[i + 1]);
+ val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+ val |= v >> (ofs ? (32 - ofs) : 0);
+ writel(val, &base->word[word].data[i + 1]);
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
+
+u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
+{
+ u32 bit = (wbs >> 8) % 160;
+ u32 size = wbs & 0xff;
+ u32 word = (wbs >> 8) / 160;
+ u32 i = bit / 32;
+ u32 ofs = bit % 32;
+ u32 mask = (1 << size) - 1;
+ u32 val = 0;
+
+ pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+ val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+
+ if ((bit + size - 1) / 32 > i) {
+ u32 tmp;
+ tmp = readl(&base->word[word].data[i + 1]);
+ tmp &= mask >> (ofs ? (32 - ofs) : 0);
+ val |= tmp << (ofs ? (32 - ofs) : 0);
+ }
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
+
+int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
+ struct ipu_rgb *rgb)
+{
+ int bpp = 0, npb = 0, ro, go, bo, to;
+
+ ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+ go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+ bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+ to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+
+ ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
+ ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
+ ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
+
+ if (rgb->transp.length) {
+ ipu_ch_param_write_field(p, IPU_FIELD_WID3,
+ rgb->transp.length - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
+ } else {
+ ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
+ ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
+ rgb->bits_per_pixel);
+ }
+
+ switch (rgb->bits_per_pixel) {
+ case 32:
+ bpp = 0;
+ npb = 15;
+ break;
+ case 24:
+ bpp = 1;
+ npb = 19;
+ break;
+ case 16:
+ bpp = 3;
+ npb = 31;
+ break;
+ case 8:
+ bpp = 5;
+ npb = 63;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
+ ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
+ ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+
+int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
+ int width)
+{
+ int bpp = 0, npb = 0;
+
+ switch (width) {
+ case 32:
+ bpp = 0;
+ npb = 15;
+ break;
+ case 24:
+ bpp = 1;
+ npb = 19;
+ break;
+ case 16:
+ bpp = 3;
+ npb = 31;
+ break;
+ case 8:
+ bpp = 5;
+ npb = 63;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
+ ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
+ ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+
+void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
+ u32 pixel_format, int stride, int u_offset, int v_offset)
+{
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_YUV420:
+ ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
+ ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
+ ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+
+void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
+ int stride, int height)
+{
+ int u_offset, v_offset;
+ int uv_stride = 0;
+
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_YUV420:
+ uv_stride = stride / 2;
+ u_offset = stride * height;
+ v_offset = u_offset + (uv_stride * height / 2);
+ ipu_cpmem_set_yuv_planar_full(p, V4L2_PIX_FMT_YUV420, stride,
+ u_offset, v_offset);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
+
+static struct ipu_rgb def_rgb_32 = {
+ .red = { .offset = 16, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
+ .transp = { .offset = 24, .length = 8, },
+ .bits_per_pixel = 32,
+};
+
+static struct ipu_rgb def_bgr_32 = {
+ .red = { .offset = 16, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
+ .transp = { .offset = 24, .length = 8, },
+ .bits_per_pixel = 32,
+};
+
+static struct ipu_rgb def_rgb_24 = {
+ .red = { .offset = 0, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 16, .length = 8, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 24,
+};
+
+static struct ipu_rgb def_bgr_24 = {
+ .red = { .offset = 16, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 24,
+};
+
+static struct ipu_rgb def_rgb_16 = {
+ .red = { .offset = 11, .length = 5, },
+ .green = { .offset = 5, .length = 6, },
+ .blue = { .offset = 0, .length = 5, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 16,
+};
+
+#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
+#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * pix->height / 4) + \
+ (pix->width * (y) / 4) + (x) / 2)
+
+int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ /* pix format */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
+ /* burst size */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ /* bits/pixel */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
+ /* pix format */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
+ /* burst size */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ /* bits/pixel */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
+ /* pix format */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
+ /* burst size */
+ ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+
+int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
+ struct ipu_image *image)
+{
+ struct v4l2_pix_format *pix = &image->pix;
+ int y_offset, u_offset, v_offset;
+
+ pr_debug("%s: resolution: %dx%d stride: %d\n",
+ __func__, pix->width, pix->height,
+ pix->bytesperline);
+
+ ipu_cpmem_set_resolution(cpmem, image->rect.width,
+ image->rect.height);
+ ipu_cpmem_set_stride(cpmem, pix->bytesperline);
+
+ ipu_cpmem_set_fmt(cpmem, pix->pixelformat);
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = U_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+ v_offset = V_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+
+ ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
+ pix->bytesperline, u_offset, v_offset);
+ ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+ image->rect.left * 2 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+ image->rect.left * 4 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+ image->rect.left * 2 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ ipu_cpmem_set_buffer(cpmem, 0, image->phys +
+ image->rect.left * 3 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+
+enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YVYU:
+ return IPUV3_COLORSPACE_YUV;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB565:
+ return IPUV3_COLORSPACE_RGB;
+ default:
+ return IPUV3_COLORSPACE_UNKNOWN;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+
+struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+{
+ struct ipuv3_channel *channel;
+
+ dev_dbg(ipu->dev, "%s %d\n", __func__, num);
+
+ if (num > 63)
+ return ERR_PTR(-ENODEV);
+
+ mutex_lock(&ipu->channel_lock);
+
+ channel = &ipu->channel[num];
+
+ if (channel->busy) {
+ channel = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ channel->busy = 1;
+ channel->num = num;
+
+out:
+ mutex_unlock(&ipu->channel_lock);
+
+ return channel;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+
+ dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
+
+ mutex_lock(&ipu->channel_lock);
+
+ channel->busy = 0;
+
+ mutex_unlock(&ipu->channel_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_put);
+
+#define idma_mask(ch) (1 << (ch & 0x1f))
+
+void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
+ bool doublebuffer)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+ if (doublebuffer)
+ reg |= idma_mask(channel->num);
+ else
+ reg &= ~idma_mask(channel->num);
+ ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+{
+ unsigned long lock_flags;
+ u32 val;
+
+ spin_lock_irqsave(&ipu->lock, lock_flags);
+
+ val = ipu_cm_read(ipu, IPU_DISP_GEN);
+
+ if (mask & IPU_CONF_DI0_EN)
+ val |= IPU_DI0_COUNTER_RELEASE;
+ if (mask & IPU_CONF_DI1_EN)
+ val |= IPU_DI1_COUNTER_RELEASE;
+
+ ipu_cm_write(ipu, val, IPU_DISP_GEN);
+
+ val = ipu_cm_read(ipu, IPU_CONF);
+ val |= mask;
+ ipu_cm_write(ipu, val, IPU_CONF);
+
+ spin_unlock_irqrestore(&ipu->lock, lock_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_module_enable);
+
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+{
+ unsigned long lock_flags;
+ u32 val;
+
+ spin_lock_irqsave(&ipu->lock, lock_flags);
+
+ val = ipu_cm_read(ipu, IPU_CONF);
+ val &= ~mask;
+ ipu_cm_write(ipu, val, IPU_CONF);
+
+ val = ipu_cm_read(ipu, IPU_DISP_GEN);
+
+ if (mask & IPU_CONF_DI0_EN)
+ val &= ~IPU_DI0_COUNTER_RELEASE;
+ if (mask & IPU_CONF_DI1_EN)
+ val &= ~IPU_DI1_COUNTER_RELEASE;
+
+ ipu_cm_write(ipu, val, IPU_DISP_GEN);
+
+ spin_unlock_irqrestore(&ipu->lock, lock_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_module_disable);
+
+void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned int chno = channel->num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ /* Mark buffer as ready. */
+ if (buf_num == 0)
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+ else
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+ val |= idma_mask(channel->num);
+ ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ u32 val;
+ unsigned long flags;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(50);
+ while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
+ idma_mask(channel->num)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(ipu->dev, "disabling busy idmac channel %d\n",
+ channel->num);
+ break;
+ }
+ cpu_relax();
+ }
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ /* Disable DMA channel(s) */
+ val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+ val &= ~idma_mask(channel->num);
+ ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+ /* Set channel buffers NOT to be ready */
+ ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+
+ if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
+ idma_mask(channel->num)) {
+ ipu_cm_write(ipu, idma_mask(channel->num),
+ IPU_CHA_BUF0_RDY(channel->num));
+ }
+
+ if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
+ idma_mask(channel->num)) {
+ ipu_cm_write(ipu, idma_mask(channel->num),
+ IPU_CHA_BUF1_RDY(channel->num));
+ }
+
+ ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+ /* Reset the double buffer */
+ val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+ val &= ~idma_mask(channel->num);
+ ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+
+static int ipu_reset(struct ipu_soc *ipu)
+{
+ unsigned long timeout;
+
+ ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+ if (time_after(jiffies, timeout))
+ return -ETIME;
+ cpu_relax();
+ }
+
+ mdelay(300);
+
+ return 0;
+}
+
+struct ipu_devtype {
+ const char *name;
+ unsigned long cm_ofs;
+ unsigned long cpmem_ofs;
+ unsigned long srm_ofs;
+ unsigned long tpm_ofs;
+ unsigned long disp0_ofs;
+ unsigned long disp1_ofs;
+ unsigned long dc_tmpl_ofs;
+ unsigned long vdi_ofs;
+ enum ipuv3_type type;
+};
+
+static struct ipu_devtype ipu_type_imx51 = {
+ .name = "IPUv3EX",
+ .cm_ofs = 0x1e000000,
+ .cpmem_ofs = 0x1f000000,
+ .srm_ofs = 0x1f040000,
+ .tpm_ofs = 0x1f060000,
+ .disp0_ofs = 0x1e040000,
+ .disp1_ofs = 0x1e048000,
+ .dc_tmpl_ofs = 0x1f080000,
+ .vdi_ofs = 0x1e068000,
+ .type = IPUV3EX,
+};
+
+static struct ipu_devtype ipu_type_imx53 = {
+ .name = "IPUv3M",
+ .cm_ofs = 0x06000000,
+ .cpmem_ofs = 0x07000000,
+ .srm_ofs = 0x07040000,
+ .tpm_ofs = 0x07060000,
+ .disp0_ofs = 0x06040000,
+ .disp1_ofs = 0x06048000,
+ .dc_tmpl_ofs = 0x07080000,
+ .vdi_ofs = 0x06068000,
+ .type = IPUV3M,
+};
+
+static struct ipu_devtype ipu_type_imx6q = {
+ .name = "IPUv3H",
+ .cm_ofs = 0x00200000,
+ .cpmem_ofs = 0x00300000,
+ .srm_ofs = 0x00340000,
+ .tpm_ofs = 0x00360000,
+ .disp0_ofs = 0x00240000,
+ .disp1_ofs = 0x00248000,
+ .dc_tmpl_ofs = 0x00380000,
+ .vdi_ofs = 0x00268000,
+ .type = IPUV3H,
+};
+
+static const struct of_device_id imx_ipu_dt_ids[] = {
+ { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+ { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+ { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
+
+static int ipu_submodules_init(struct ipu_soc *ipu,
+ struct platform_device *pdev, unsigned long ipu_base,
+ struct clk *ipu_clk)
+{
+ char *unit;
+ int ret;
+ struct device *dev = &pdev->dev;
+ const struct ipu_devtype *devtype = ipu->devtype;
+
+ ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
+ IPU_CONF_DI0_EN, ipu_clk);
+ if (ret) {
+ unit = "di0";
+ goto err_di_0;
+ }
+
+ ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
+ IPU_CONF_DI1_EN, ipu_clk);
+ if (ret) {
+ unit = "di1";
+ goto err_di_1;
+ }
+
+ ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
+ IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
+ if (ret) {
+ unit = "dc_template";
+ goto err_dc;
+ }
+
+ ret = ipu_dmfc_init(ipu, dev, ipu_base +
+ devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
+ if (ret) {
+ unit = "dmfc";
+ goto err_dmfc;
+ }
+
+ ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
+ if (ret) {
+ unit = "dp";
+ goto err_dp;
+ }
+
+ return 0;
+
+err_dp:
+ ipu_dmfc_exit(ipu);
+err_dmfc:
+ ipu_dc_exit(ipu);
+err_dc:
+ ipu_di_exit(ipu, 1);
+err_di_1:
+ ipu_di_exit(ipu, 0);
+err_di_0:
+ dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+ return ret;
+}
+
+static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
+{
+ unsigned long status;
+ int i, bit, irq_base;
+
+ for (i = 0; i < num_regs; i++) {
+
+ status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
+ status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
+
+ irq_base = ipu->irq_start + regs[i] * 32;
+ for_each_set_bit(bit, &status, 32)
+ generic_handle_irq(irq_base + bit);
+ }
+}
+
+static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+ const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+ struct irq_chip *chip = irq_get_chip(irq);
+
+ chained_irq_enter(chip, desc);
+
+ ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+
+ chained_irq_exit(chip, desc);
+}
+
+static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+ const int int_reg[] = { 4, 5, 8, 9};
+ struct irq_chip *chip = irq_get_chip(irq);
+
+ chained_irq_enter(chip, desc);
+
+ ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
+
+ chained_irq_exit(chip, desc);
+}
+
+static void ipu_ack_irq(struct irq_data *d)
+{
+ struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq - ipu->irq_start;
+
+ ipu_cm_write(ipu, 1 << (irq % 32), IPU_INT_STAT(irq / 32));
+}
+
+static void ipu_unmask_irq(struct irq_data *d)
+{
+ struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq - ipu->irq_start;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32));
+ reg |= 1 << (irq % 32);
+ ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
+static void ipu_mask_irq(struct irq_data *d)
+{
+ struct ipu_soc *ipu = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq - ipu->irq_start;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32));
+ reg &= ~(1 << (irq % 32));
+ ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
+static struct irq_chip ipu_irq_chip = {
+ .name = "IPU",
+ .irq_ack = ipu_ack_irq,
+ .irq_mask = ipu_mask_irq,
+ .irq_unmask = ipu_unmask_irq,
+};
+
+int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
+ enum ipu_channel_irq irq_type)
+{
+ return ipu->irq_start + irq_type + channel->num;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
+
+static void ipu_submodules_exit(struct ipu_soc *ipu)
+{
+ ipu_dp_exit(ipu);
+ ipu_dmfc_exit(ipu);
+ ipu_dc_exit(ipu);
+ ipu_di_exit(ipu, 1);
+ ipu_di_exit(ipu, 0);
+}
+
+static int platform_remove_devices_fn(struct device *dev, void *unused)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+}
+
+struct ipu_platform_reg {
+ struct ipu_client_platformdata pdata;
+ const char *name;
+};
+
+static const struct ipu_platform_reg client_reg[] = {
+ {
+ .pdata = {
+ .di = 0,
+ .dc = 5,
+ .dp = IPU_DP_FLOW_SYNC_BG,
+ .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
+ .dma[1] = -EINVAL,
+ },
+ .name = "imx-ipuv3-crtc",
+ }, {
+ .pdata = {
+ .di = 1,
+ .dc = 1,
+ .dp = -EINVAL,
+ .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
+ .dma[1] = -EINVAL,
+ },
+ .name = "imx-ipuv3-crtc",
+ },
+};
+
+static int ipu_client_id;
+
+static int ipu_add_subdevice_pdata(struct device *dev,
+ const struct ipu_platform_reg *reg)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(dev, reg->name, ipu_client_id++,
+ ®->pdata, sizeof(struct ipu_platform_reg));
+
+ return pdev ? 0 : -EINVAL;
+}
+
+static int ipu_add_client_devices(struct ipu_soc *ipu)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+ const struct ipu_platform_reg *reg = &client_reg[i];
+ ret = ipu_add_subdevice_pdata(ipu->dev, reg);
+ if (ret)
+ goto err_register;
+ }
+
+ return 0;
+
+err_register:
+ platform_device_unregister_children(to_platform_device(ipu->dev));
+
+ return ret;
+}
+
+static int ipu_irq_init(struct ipu_soc *ipu)
+{
+ int i;
+
+ ipu->irq_start = irq_alloc_descs(-1, 0, IPU_NUM_IRQS, 0);
+ if (ipu->irq_start < 0)
+ return ipu->irq_start;
+
+ for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) {
+ irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ irq_set_chip_data(i, ipu);
+ }
+
+ irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler);
+ irq_set_handler_data(ipu->irq_sync, ipu);
+ irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler);
+ irq_set_handler_data(ipu->irq_err, ipu);
+
+ return 0;
+}
+
+static void ipu_irq_exit(struct ipu_soc *ipu)
+{
+ int i;
+
+ irq_set_chained_handler(ipu->irq_err, NULL);
+ irq_set_handler_data(ipu->irq_err, NULL);
+ irq_set_chained_handler(ipu->irq_sync, NULL);
+ irq_set_handler_data(ipu->irq_sync, NULL);
+
+ for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) {
+ set_irq_flags(i, 0);
+ irq_set_chip(i, NULL);
+ irq_set_chip_data(i, NULL);
+ }
+
+ irq_free_descs(ipu->irq_start, IPU_NUM_IRQS);
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(imx_ipu_dt_ids, &pdev->dev);
+ struct ipu_soc *ipu;
+ struct resource *res;
+ unsigned long ipu_base;
+ int i, ret, irq_sync, irq_err;
+ const struct ipu_devtype *devtype;
+
+ devtype = of_id->data;
+
+ dev_info(&pdev->dev, "Initializing %s\n", devtype->name);
+
+ irq_sync = platform_get_irq(pdev, 0);
+ irq_err = platform_get_irq(pdev, 1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ dev_info(&pdev->dev, "irq_sync: %d irq_err: %d\n",
+ irq_sync, irq_err);
+
+ if (!res || irq_sync < 0 || irq_err < 0)
+ return -ENODEV;
+
+ ipu_base = res->start;
+
+ ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
+ if (!ipu)
+ return -ENODEV;
+
+ for (i = 0; i < 64; i++)
+ ipu->channel[i].ipu = ipu;
+ ipu->devtype = devtype;
+ ipu->ipu_type = devtype->type;
+
+ spin_lock_init(&ipu->lock);
+ mutex_init(&ipu->channel_lock);
+
+ dev_info(&pdev->dev, "cm_reg: 0x%08lx\n",
+ ipu_base + devtype->cm_ofs);
+ dev_info(&pdev->dev, "idmac: 0x%08lx\n",
+ ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
+ dev_info(&pdev->dev, "cpmem: 0x%08lx\n",
+ ipu_base + devtype->cpmem_ofs);
+ dev_info(&pdev->dev, "disp0: 0x%08lx\n",
+ ipu_base + devtype->disp0_ofs);
+ dev_info(&pdev->dev, "disp1: 0x%08lx\n",
+ ipu_base + devtype->disp1_ofs);
+ dev_info(&pdev->dev, "srm: 0x%08lx\n",
+ ipu_base + devtype->srm_ofs);
+ dev_info(&pdev->dev, "tpm: 0x%08lx\n",
+ ipu_base + devtype->tpm_ofs);
+ dev_info(&pdev->dev, "dc: 0x%08lx\n",
+ ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
+ dev_info(&pdev->dev, "ic: 0x%08lx\n",
+ ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
+ dev_info(&pdev->dev, "dmfc: 0x%08lx\n",
+ ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
+ dev_info(&pdev->dev, "vdi: 0x%08lx\n",
+ ipu_base + devtype->vdi_ofs);
+
+ ipu->cm_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->cm_ofs, PAGE_SIZE);
+ ipu->idmac_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
+ PAGE_SIZE);
+ ipu->cpmem_base = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
+
+ if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) {
+ ret = -ENOMEM;
+ goto failed_ioremap;
+ }
+
+ ipu->clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(ipu->clk)) {
+ ret = PTR_ERR(ipu->clk);
+ dev_err(&pdev->dev, "clk_get failed with %d", ret);
+ goto failed_clk_get;
+ }
+
+ platform_set_drvdata(pdev, ipu);
+
+ clk_prepare_enable(ipu->clk);
+
+ ipu->dev = &pdev->dev;
+ ipu->irq_sync = irq_sync;
+ ipu->irq_err = irq_err;
+
+ ret = ipu_irq_init(ipu);
+ if (ret)
+ goto out_failed_irq;
+
+ ipu_reset(ipu);
+
+ /* Set MCU_T to divide MCU access window into 2 */
+ ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+ IPU_DISP_GEN);
+
+ ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
+ if (ret)
+ goto failed_submodules_init;
+
+ ret = ipu_add_client_devices(ipu);
+ if (ret) {
+ dev_err(&pdev->dev, "adding client devices failed with %d\n",
+ ret);
+ goto failed_add_clients;
+ }
+
+ return 0;
+
+failed_add_clients:
+ ipu_submodules_exit(ipu);
+failed_submodules_init:
+ ipu_irq_exit(ipu);
+out_failed_irq:
+ clk_disable_unprepare(ipu->clk);
+failed_clk_get:
+failed_ioremap:
+ return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+ struct ipu_soc *ipu = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ platform_device_unregister_children(pdev);
+ ipu_submodules_exit(ipu);
+ ipu_irq_exit(ipu);
+
+ clk_disable_unprepare(ipu->clk);
+
+ return 0;
+}
+
+static struct platform_driver imx_ipu_driver = {
+ .driver = {
+ .name = "imx-ipuv3",
+ .of_match_table = imx_ipu_dt_ids,
+ },
+ .probe = ipu_probe,
+ .remove = __devexit_p(ipu_remove),
+};
+
+module_platform_driver(imx_ipu_driver);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF 0
+#define DC_EVT_NL 1
+#define DC_EVT_EOF 2
+#define DC_EVT_NFIELD 3
+#define DC_EVT_EOL 4
+#define DC_EVT_EOFIELD 5
+#define DC_EVT_NEW_ADDR 6
+#define DC_EVT_NEW_CHAN 7
+#define DC_EVT_NEW_DATA 8
+
+#define DC_EVT_NEW_ADDR_W_0 0
+#define DC_EVT_NEW_ADDR_W_1 1
+#define DC_EVT_NEW_CHAN_W_0 2
+#define DC_EVT_NEW_CHAN_W_1 3
+#define DC_EVT_NEW_DATA_W_0 4
+#define DC_EVT_NEW_DATA_W_1 5
+#define DC_EVT_NEW_ADDR_R_0 6
+#define DC_EVT_NEW_ADDR_R_1 7
+#define DC_EVT_NEW_CHAN_R_0 8
+#define DC_EVT_NEW_CHAN_R_1 9
+#define DC_EVT_NEW_DATA_R_0 10
+#define DC_EVT_NEW_DATA_R_1 11
+
+#define DC_WR_CH_CONF 0x0
+#define DC_WR_CH_ADDR 0x4
+#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN 0xd4
+#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
+#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
+#define DC_STAT 0x1c8
+
+#define WROD(lf) (0x18 | ((lf) << 1))
+#define WRG 0x01
+
+#define SYNC_WAVE 0
+
+#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
+#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
+
+#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
+#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
+#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
+#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
+#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
+#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
+#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
+
+#define IPU_DC_NUM_CHANNELS 10
+
+struct ipu_dc_priv;
+
+enum ipu_dc_map {
+ IPU_DC_MAP_RGB24,
+ IPU_DC_MAP_RGB565,
+};
+
+struct ipu_dc {
+ /* The display interface number assigned to this dc channel */
+ unsigned int di;
+ void __iomem *base;
+ struct ipu_dc_priv *priv;
+ int chno;
+ bool in_use;
+};
+
+struct ipu_dc_priv {
+ void __iomem *dc_reg;
+ void __iomem *dc_tmpl_reg;
+ struct ipu_soc *ipu;
+ struct device *dev;
+ struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
+ struct mutex mutex;
+};
+
+static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
+{
+ u32 reg;
+
+ reg = readl(dc->base + DC_RL_CH(event));
+ reg &= ~(0xffff << (16 * (event & 0x1)));
+ reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+ writel(reg, dc->base + DC_RL_CH(event));
+}
+
+static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
+ int map, int wave, int glue, int sync)
+{
+ struct ipu_dc_priv *priv = dc->priv;
+ u32 reg;
+ int stop = 1;
+
+ reg = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
+ writel(reg, priv->dc_tmpl_reg + word * 8);
+ reg = operand >> 12 | opcode << 4 | stop << 9;
+ writel(reg, priv->dc_tmpl_reg + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+ switch (fmt) {
+ case V4L2_PIX_FMT_RGB24:
+ return IPU_DC_MAP_RGB24;
+ case V4L2_PIX_FMT_RGB565:
+ return IPU_DC_MAP_RGB565;
+ default:
+ return -EINVAL;
+ }
+}
+
+int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
+ u32 pixel_fmt, u32 width)
+{
+ struct ipu_dc_priv *priv = dc->priv;
+ u32 reg = 0, map;
+
+ dc->di = ipu_di_get_num(di);
+
+ map = ipu_pixfmt_to_map(pixel_fmt);
+ if (map < 0) {
+ dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
+ return -EINVAL;
+ }
+
+ if (interlaced) {
+ dc_link_event(dc, DC_EVT_NL, 0, 3);
+ dc_link_event(dc, DC_EVT_EOL, 0, 2);
+ dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1);
+
+ /* Init template microcode */
+ dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+ } else {
+ if (dc->di) {
+ dc_link_event(dc, DC_EVT_NL, 2, 3);
+ dc_link_event(dc, DC_EVT_EOL, 3, 2);
+ dc_link_event(dc, DC_EVT_NEW_DATA, 4, 1);
+ /* Init template microcode */
+ dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+ dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+ dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ } else {
+ dc_link_event(dc, DC_EVT_NL, 5, 3);
+ dc_link_event(dc, DC_EVT_EOL, 6, 2);
+ dc_link_event(dc, DC_EVT_NEW_DATA, 7, 1);
+ /* Init template microcode */
+ dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+ dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+ dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ }
+ }
+ dc_link_event(dc, DC_EVT_NF, 0, 0);
+ dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
+ dc_link_event(dc, DC_EVT_EOF, 0, 0);
+ dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
+ dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
+ dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
+
+ reg = readl(dc->base + DC_WR_CH_CONF);
+ if (interlaced)
+ reg |= DC_WR_CH_CONF_FIELD_MODE;
+ else
+ reg &= ~DC_WR_CH_CONF_FIELD_MODE;
+ writel(reg, dc->base + DC_WR_CH_CONF);
+
+ writel(0x0, dc->base + DC_WR_CH_ADDR);
+ writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
+
+ ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+
+void ipu_dc_enable_channel(struct ipu_dc *dc)
+{
+ int di;
+ u32 reg;
+
+ di = dc->di;
+
+ reg = readl(dc->base + DC_WR_CH_CONF);
+ reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
+ writel(reg, dc->base + DC_WR_CH_CONF);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(struct ipu_dc *dc)
+{
+ struct ipu_dc_priv *priv = dc->priv;
+ u32 val;
+ int irq = 0, timeout = 50;
+
+ if (dc->chno == 1)
+ irq = IPU_IRQ_DC_FC_1;
+ else if (dc->chno == 5)
+ irq = IPU_IRQ_DP_SF_END;
+ else
+ return;
+
+ /* should wait for the interrupt here */
+ mdelay(50);
+
+ if (dc->di == 0)
+ val = 0x00000002;
+ else
+ val = 0x00000020;
+
+ /* Wait for DC triple buffer to empty */
+ while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
+ msleep(2);
+ timeout -= 2;
+ if (timeout <= 0)
+ break;
+ }
+
+ val = readl(dc->base + DC_WR_CH_CONF);
+ val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ writel(val, dc->base + DC_WR_CH_CONF);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+
+static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
+ int byte_num, int offset, int mask)
+{
+ int ptr = map * 3 + byte_num;
+ u32 reg;
+
+ reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+ reg &= ~(0xffff << (16 * (ptr & 0x1)));
+ reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+ writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
+
+ reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+ reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+ reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+ writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
+{
+ u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
+
+ writel(reg & ~(0xffff << (16 * (map & 0x1))),
+ priv->dc_reg + DC_MAP_CONF_PTR(map));
+}
+
+struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
+{
+ struct ipu_dc_priv *priv = ipu->dc_priv;
+ struct ipu_dc *dc;
+
+ if (channel >= IPU_DC_NUM_CHANNELS)
+ return ERR_PTR(-ENODEV);
+
+ dc = &priv->channels[channel];
+
+ mutex_lock(&priv->mutex);
+
+ if (dc->in_use) {
+ mutex_unlock(&priv->mutex);
+ return ERR_PTR(-EBUSY);
+ }
+
+ dc->in_use = 1;
+
+ mutex_unlock(&priv->mutex);
+
+ return dc;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_get);
+
+void ipu_dc_put(struct ipu_dc *dc)
+{
+ struct ipu_dc_priv *priv = dc->priv;
+
+ mutex_lock(&priv->mutex);
+ dc->in_use = 0;
+ mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_put);
+
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
+ unsigned long base, unsigned long template_base)
+{
+ struct ipu_dc_priv *priv;
+ static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
+ 0x78, 0, 0x94, 0xb4};
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->mutex);
+
+ priv->dev = dev;
+ priv->ipu = ipu;
+ priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
+ priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
+ if (!priv->dc_reg || !priv->dc_tmpl_reg)
+ return -ENOMEM;
+
+ for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
+ priv->channels[i].chno = i;
+ priv->channels[i].priv = priv;
+ priv->channels[i].base = priv->dc_reg + channel_offsets[i];
+ }
+
+ writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
+ DC_WR_CH_CONF_PROG_DI_ID,
+ priv->channels[1].base + DC_WR_CH_CONF);
+ writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
+ priv->channels[5].base + DC_WR_CH_CONF);
+
+ writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN);
+
+ ipu->dc_priv = priv;
+
+ dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
+ base, template_base);
+
+ /* rgb24 */
+ ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
+
+ /* rgb565 */
+ ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
+ ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
+
+ return 0;
+}
+
+void ipu_dc_exit(struct ipu_soc *ipu)
+{
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+struct ipu_di {
+ void __iomem *base;
+ int id;
+ u32 module;
+ struct clk *clk_di; /* display input clock */
+ struct clk *clk_ipu; /* IPU bus clock */
+ struct clk *clk_di_pixel; /* resulting pixel clock */
+ struct clk_hw clk_hw_out;
+ char *clk_name;
+ bool inuse;
+ unsigned long clkflags;
+ struct ipu_soc *ipu;
+};
+
+static DEFINE_MUTEX(di_mutex);
+
+struct di_sync_config {
+ int run_count;
+ int run_src;
+ int offset_count;
+ int offset_src;
+ int repeat_count;
+ int cnt_clr_src;
+ int cnt_polarity_gen_en;
+ int cnt_polarity_clr_src;
+ int cnt_polarity_trigger_src;
+ int cnt_up;
+ int cnt_down;
+};
+
+enum di_pins {
+ DI_PIN11 = 0,
+ DI_PIN12 = 1,
+ DI_PIN13 = 2,
+ DI_PIN14 = 3,
+ DI_PIN15 = 4,
+ DI_PIN16 = 5,
+ DI_PIN17 = 6,
+ DI_PIN_CS = 7,
+
+ DI_PIN_SER_CLK = 0,
+ DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+ DI_SYNC_NONE = 0,
+ DI_SYNC_CLK = 1,
+ DI_SYNC_INT_HSYNC = 2,
+ DI_SYNC_HSYNC = 3,
+ DI_SYNC_VSYNC = 4,
+ DI_SYNC_DE = 6,
+};
+
+#define SYNC_WAVE 0
+
+#define DI_GENERAL 0x0000
+#define DI_BS_CLKGEN0 0x0004
+#define DI_BS_CLKGEN1 0x0008
+#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN 0x0054
+#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF 0x015c
+#define DI_SSC 0x0160
+#define DI_POL 0x0164
+#define DI_AW0 0x0168
+#define DI_AW1 0x016c
+#define DI_SCR_CONF 0x0170
+#define DI_STAT 0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x) (x)
+#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
+
+#define DI_GEN_POLARITY_1 (1 << 0)
+#define DI_GEN_POLARITY_2 (1 << 1)
+#define DI_GEN_POLARITY_3 (1 << 2)
+#define DI_GEN_POLARITY_4 (1 << 3)
+#define DI_GEN_POLARITY_5 (1 << 4)
+#define DI_GEN_POLARITY_6 (1 << 5)
+#define DI_GEN_POLARITY_7 (1 << 6)
+#define DI_GEN_POLARITY_8 (1 << 7)
+#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
+#define DI_GEN_DI_CLK_EXT (1 << 20)
+#define DI_GEN_DI_VSYNC_EXT (1 << 21)
+
+#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
+#define DI_POL_DRDY_POLARITY_15 (1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET 13
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+ return readl(di->base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+ writel(value, di->base + offset);
+}
+
+static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
+{
+ u64 tmp = inrate;
+ int div;
+
+ tmp *= 16;
+
+ do_div(tmp, outrate);
+
+ div = tmp;
+
+ if (div < 0x10)
+ div = 0x10;
+
+#ifdef WTF_IS_THIS
+ /*
+ * Freescale has this in their Kernel. It is neither clear what
+ * it does nor why it does it
+ */
+ if (div & 0x10)
+ div &= ~0x7;
+ else {
+ /* Round up divider if it gets us closer to desired pix clk */
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ }
+#endif
+ return div;
+}
+
+static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+ unsigned long outrate;
+ u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
+
+ if (div < 0x10)
+ div = 0x10;
+
+ outrate = (parent_rate / div) * 16;
+
+ return outrate;
+}
+
+static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+ unsigned long outrate;
+ int div;
+ u32 val;
+
+ div = ipu_di_clk_calc_div(*prate, rate);
+
+ outrate = (*prate / div) * 16;
+
+ val = ipu_di_read(di, DI_GENERAL);
+
+ if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
+ outrate = *prate / 2;
+
+ dev_dbg(di->ipu->dev,
+ "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
+ __func__, *prate, div, outrate, rate);
+
+ return outrate;
+}
+
+static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+ int div;
+ u32 clkgen0;
+
+ clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
+
+ div = ipu_di_clk_calc_div(parent_rate, rate);
+
+ ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
+
+ dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
+ __func__, parent_rate, rate, div);
+ return 0;
+}
+
+static u8 clk_di_get_parent(struct clk_hw *hw)
+{
+ struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+ u32 val;
+
+ val = ipu_di_read(di, DI_GENERAL);
+
+ return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
+}
+
+static int clk_di_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
+ u32 val;
+
+ val = ipu_di_read(di, DI_GENERAL);
+
+ if (index)
+ val |= DI_GEN_DI_CLK_EXT;
+ else
+ val &= ~DI_GEN_DI_CLK_EXT;
+
+ ipu_di_write(di, val, DI_GENERAL);
+
+ return 0;
+}
+
+static struct clk_ops clk_di_ops = {
+ .round_rate = clk_di_round_rate,
+ .set_rate = clk_di_set_rate,
+ .recalc_rate = clk_di_recalc_rate,
+ .set_parent = clk_di_set_parent,
+ .get_parent = clk_di_get_parent,
+};
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+ int wave_gen,
+ int access_size, int component_size)
+{
+ u32 reg;
+ reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+ (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+ ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
+ int set, int up, int down)
+{
+ u32 reg;
+
+ reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+ reg &= ~(0x3 << (di_pin * 2));
+ reg |= set << (di_pin * 2);
+ ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+ ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
+ int start, int count)
+{
+ u32 reg;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ struct di_sync_config *c = &config[i];
+ int wave_gen = start + i + 1;
+
+ if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
+ (c->repeat_count >= 0x1000) ||
+ (c->cnt_up >= 0x400) ||
+ (c->cnt_down >= 0x400)) {
+ dev_err(di->ipu->dev, "DI%d counters out of range.\n",
+ di->id);
+ return;
+ }
+
+ reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+ DI_SW_GEN0_RUN_SRC(c->run_src) |
+ DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+ DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+ ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+ reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+ DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+ DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
+ c->cnt_polarity_trigger_src) |
+ DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+ DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+ DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+ /* Enable auto reload */
+ if (c->repeat_count == 0)
+ reg |= DI_SW_GEN1_AUTO_RELOAD;
+
+ ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+ reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+ reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+ reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+ ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+ }
+}
+
+static void ipu_di_sync_config_interlaced(struct ipu_di *di,
+ struct ipu_di_signal_cfg *sig)
+{
+ u32 h_total = sig->width + sig->h_sync_width +
+ sig->h_start_width + sig->h_end_width;
+ u32 v_total = sig->height + sig->v_sync_width +
+ sig->v_start_width + sig->v_end_width;
+ u32 reg;
+ struct di_sync_config cfg[] = {
+ {
+ .run_count = h_total / 2 - 1,
+ .run_src = DI_SYNC_CLK,
+ }, {
+ .run_count = h_total - 11,
+ .run_src = DI_SYNC_CLK,
+ .cnt_down = 4,
+ }, {
+ .run_count = v_total * 2 - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ .offset_count = 1,
+ .offset_src = DI_SYNC_INT_HSYNC,
+ .cnt_down = 4,
+ }, {
+ .run_count = v_total / 2 - 1,
+ .run_src = DI_SYNC_HSYNC,
+ .offset_count = sig->v_start_width,
+ .offset_src = DI_SYNC_HSYNC,
+ .repeat_count = 2,
+ .cnt_clr_src = DI_SYNC_VSYNC,
+ }, {
+ .run_src = DI_SYNC_HSYNC,
+ .repeat_count = sig->height / 2,
+ .cnt_clr_src = 4,
+ }, {
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_HSYNC,
+ }, {
+ .run_count = v_total / 2 - 1,
+ .run_src = DI_SYNC_HSYNC,
+ .offset_count = 9,
+ .offset_src = DI_SYNC_HSYNC,
+ .repeat_count = 2,
+ .cnt_clr_src = DI_SYNC_VSYNC,
+ }, {
+ .run_src = DI_SYNC_CLK,
+ .offset_count = sig->h_start_width,
+ .offset_src = DI_SYNC_CLK,
+ .repeat_count = sig->width,
+ .cnt_clr_src = 5,
+ }, {
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ .offset_count = v_total / 2,
+ .offset_src = DI_SYNC_INT_HSYNC,
+ .cnt_clr_src = DI_SYNC_HSYNC,
+ .cnt_down = 4,
+ }
+ };
+
+ ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+
+ /* set gentime select and tag sel */
+ reg = ipu_di_read(di, DI_SW_GEN1(9));
+ reg &= 0x1FFFFFFF;
+ reg |= (3 - 1) << 29 | 0x00008000;
+ ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+ ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+}
+
+static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+ struct ipu_di_signal_cfg *sig, int div)
+{
+ u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+ sig->h_end_width;
+ u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+ sig->v_end_width;
+ struct di_sync_config cfg[] = {
+ {
+ .run_count = h_total - 1,
+ .run_src = DI_SYNC_CLK,
+ } , {
+ .run_count = h_total - 1,
+ .run_src = DI_SYNC_CLK,
+ .offset_count = div * sig->v_to_h_sync,
+ .offset_src = DI_SYNC_CLK,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_CLK,
+ .cnt_down = sig->h_sync_width * 2,
+ } , {
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+ .cnt_down = sig->v_sync_width * 2,
+ } , {
+ .run_src = DI_SYNC_HSYNC,
+ .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_src = DI_SYNC_HSYNC,
+ .repeat_count = sig->height,
+ .cnt_clr_src = DI_SYNC_VSYNC,
+ } , {
+ .run_src = DI_SYNC_CLK,
+ .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_src = DI_SYNC_CLK,
+ .repeat_count = sig->width,
+ .cnt_clr_src = 5,
+ } , {
+ /* unused */
+ } , {
+ /* unused */
+ } , {
+ /* unused */
+ } , {
+ /* unused */
+ },
+ };
+
+ ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+ ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+ u32 reg;
+ u32 di_gen, vsync_cnt;
+ u32 div;
+ u32 h_total, v_total;
+ int ret;
+ unsigned long round;
+ struct clk *parent;
+
+ dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+ di->id, sig->width, sig->height);
+
+ if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+ return -EINVAL;
+
+ if (sig->clkflags & IPU_DI_CLKMODE_EXT)
+ parent = di->clk_di;
+ else
+ parent = di->clk_ipu;
+
+ ret = clk_set_parent(di->clk_di_pixel, parent);
+ if (ret) {
+ dev_err(di->ipu->dev,
+ "setting pixel clock to parent %s failed with %d\n",
+ __clk_get_name(parent), ret);
+ return ret;
+ }
+
+ if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
+ round = clk_get_rate(parent);
+ else
+ round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
+
+ ret = clk_set_rate(di->clk_di_pixel, round);
+
+ h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+ sig->h_end_width;
+ v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+ sig->v_end_width;
+
+ mutex_lock(&di_mutex);
+
+ div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
+ div = div / 16; /* Now divider is integer portion */
+
+ /* Setup pixel clock timing */
+ /* Down time is half of period */
+ ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
+
+ ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
+ ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+ di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
+ di_gen |= DI_GEN_DI_VSYNC_EXT;
+
+ if (sig->interlaced) {
+ ipu_di_sync_config_interlaced(di, sig);
+
+ /* set y_sel = 1 */
+ di_gen |= 0x10000000;
+ di_gen |= DI_GEN_POLARITY_5;
+ di_gen |= DI_GEN_POLARITY_8;
+
+ vsync_cnt = 7;
+
+ if (sig->Hsync_pol)
+ di_gen |= DI_GEN_POLARITY_3;
+ if (sig->Vsync_pol)
+ di_gen |= DI_GEN_POLARITY_2;
+ } else {
+ ipu_di_sync_config_noninterlaced(di, sig, div);
+
+ vsync_cnt = 3;
+
+ if (sig->Hsync_pol)
+ di_gen |= DI_GEN_POLARITY_2;
+ if (sig->Vsync_pol)
+ di_gen |= DI_GEN_POLARITY_3;
+ }
+
+ if (!sig->clk_pol)
+ di_gen |= DI_GEN_POLARITY_DISP_CLK;
+
+ ipu_di_write(di, di_gen, DI_GENERAL);
+
+ ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+ DI_SYNC_AS_GEN);
+
+ reg = ipu_di_read(di, DI_POL);
+ reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+ if (sig->enable_pol)
+ reg |= DI_POL_DRDY_POLARITY_15;
+ if (sig->data_pol)
+ reg |= DI_POL_DRDY_DATA_POLARITY;
+
+ ipu_di_write(di, reg, DI_POL);
+
+ mutex_unlock(&di_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+ clk_prepare_enable(di->clk_di_pixel);
+
+ ipu_module_enable(di->ipu, di->module);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+ ipu_module_disable(di->ipu, di->module);
+
+ clk_disable_unprepare(di->clk_di_pixel);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_disable);
+
+int ipu_di_get_num(struct ipu_di *di)
+{
+ return di->id;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get_num);
+
+static DEFINE_MUTEX(ipu_di_lock);
+
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+{
+ struct ipu_di *di;
+
+ if (disp > 1)
+ return ERR_PTR(-EINVAL);
+
+ di = ipu->di_priv[disp];
+
+ mutex_lock(&ipu_di_lock);
+
+ if (di->inuse) {
+ di = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ di->inuse = true;
+out:
+ mutex_unlock(&ipu_di_lock);
+
+ return di;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+ mutex_lock(&ipu_di_lock);
+
+ di->inuse = false;
+
+ mutex_unlock(&ipu_di_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_di_put);
+
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+ unsigned long base,
+ u32 module, struct clk *clk_ipu)
+{
+ struct ipu_di *di;
+ int ret;
+ const char *di_parent[2];
+ struct clk_init_data init = {
+ .ops = &clk_di_ops,
+ .num_parents = 2,
+ .flags = 0,
+ };
+
+ if (id > 1)
+ return -ENODEV;
+
+ di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+ if (!di)
+ return -ENOMEM;
+
+ ipu->di_priv[id] = di;
+
+ di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
+ if (IS_ERR(di->clk_di))
+ return PTR_ERR(di->clk_di);
+
+ di->module = module;
+ di->id = id;
+ di->clk_ipu = clk_ipu;
+ di->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!di->base)
+ return -ENOMEM;
+
+ di_parent[0] = __clk_get_name(di->clk_ipu);
+ di_parent[1] = __clk_get_name(di->clk_di);
+
+ ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
+
+ init.parent_names = (const char **)&di_parent;
+ di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
+ dev_name(dev), id);
+ if (!di->clk_name)
+ return -ENOMEM;
+
+ init.name = di->clk_name;
+
+ di->clk_hw_out.init = &init;
+ di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
+
+ if (IS_ERR(di->clk_di_pixel)) {
+ ret = PTR_ERR(di->clk_di_pixel);
+ goto failed_clk_register;
+ }
+
+ dev_info(dev, "DI%d base: 0x%08lx remapped to %p\n",
+ id, base, di->base);
+ di->inuse = false;
+ di->ipu = ipu;
+
+ return 0;
+
+failed_clk_register:
+
+ kfree(di->clk_name);
+
+ return ret;
+}
+
+void ipu_di_exit(struct ipu_soc *ipu, int id)
+{
+ struct ipu_di *di = ipu->di_priv[id];
+
+ clk_unregister(di->clk_di_pixel);
+ kfree(di->clk_name);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN 0x0000
+#define DMFC_WR_CHAN 0x0004
+#define DMFC_WR_CHAN_DEF 0x0008
+#define DMFC_DP_CHAN 0x000c
+#define DMFC_DP_CHAN_DEF 0x0010
+#define DMFC_GENERAL1 0x0014
+#define DMFC_GENERAL2 0x0018
+#define DMFC_IC_CTRL 0x001c
+#define DMFC_STAT 0x0020
+
+#define DMFC_WR_CHAN_1_28 0
+#define DMFC_WR_CHAN_2_41 8
+#define DMFC_WR_CHAN_1C_42 16
+#define DMFC_WR_CHAN_2C_43 24
+
+#define DMFC_DP_CHAN_5B_23 0
+#define DMFC_DP_CHAN_5F_27 8
+#define DMFC_DP_CHAN_6B_24 16
+#define DMFC_DP_CHAN_6F_29 24
+
+#define DMFC_FIFO_SIZE_64 (3 << 3)
+#define DMFC_FIFO_SIZE_128 (2 << 3)
+#define DMFC_FIFO_SIZE_256 (1 << 3)
+#define DMFC_FIFO_SIZE_512 (0 << 3)
+
+#define DMFC_SEGMENT(x) ((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_128 (0 << 6)
+#define DMFC_BURSTSIZE_64 (1 << 6)
+#define DMFC_BURSTSIZE_32 (2 << 6)
+#define DMFC_BURSTSIZE_16 (3 << 6)
+
+struct dmfc_channel_data {
+ int ipu_channel;
+ unsigned long channel_reg;
+ unsigned long shift;
+ unsigned eot_shift;
+ unsigned max_fifo_lines;
+};
+
+static const struct dmfc_channel_data dmfcdata[] = {
+ {
+ .ipu_channel = 23,
+ .channel_reg = DMFC_DP_CHAN,
+ .shift = DMFC_DP_CHAN_5B_23,
+ .eot_shift = 20,
+ .max_fifo_lines = 3,
+ }, {
+ .ipu_channel = 24,
+ .channel_reg = DMFC_DP_CHAN,
+ .shift = DMFC_DP_CHAN_6B_24,
+ .eot_shift = 22,
+ .max_fifo_lines = 1,
+ }, {
+ .ipu_channel = 27,
+ .channel_reg = DMFC_DP_CHAN,
+ .shift = DMFC_DP_CHAN_5F_27,
+ .eot_shift = 21,
+ .max_fifo_lines = 2,
+ }, {
+ .ipu_channel = 28,
+ .channel_reg = DMFC_WR_CHAN,
+ .shift = DMFC_WR_CHAN_1_28,
+ .eot_shift = 16,
+ .max_fifo_lines = 2,
+ }, {
+ .ipu_channel = 29,
+ .channel_reg = DMFC_DP_CHAN,
+ .shift = DMFC_DP_CHAN_6F_29,
+ .eot_shift = 23,
+ .max_fifo_lines = 1,
+ },
+};
+
+#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
+
+struct ipu_dmfc_priv;
+
+struct dmfc_channel {
+ unsigned slots;
+ unsigned slotmask;
+ unsigned segment;
+ int burstsize;
+ struct ipu_soc *ipu;
+ struct ipu_dmfc_priv *priv;
+ const struct dmfc_channel_data *data;
+};
+
+struct ipu_dmfc_priv {
+ struct ipu_soc *ipu;
+ struct device *dev;
+ struct dmfc_channel channels[DMFC_NUM_CHANNELS];
+ struct mutex mutex;
+ unsigned long bandwidth_per_slot;
+ void __iomem *base;
+ int use_count;
+};
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+ mutex_lock(&priv->mutex);
+
+ if (!priv->use_count)
+ ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
+
+ priv->use_count++;
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+
+ mutex_lock(&priv->mutex);
+
+ priv->use_count--;
+
+ if (!priv->use_count)
+ ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
+
+ if (priv->use_count < 0)
+ priv->use_count = 0;
+
+ mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
+ int segment, int burstsize)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+ u32 val, field;
+
+ dev_dbg(priv->dev,
+ "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+ slots, segment, dmfc->data->ipu_channel);
+
+ if (!dmfc)
+ return -EINVAL;
+
+ switch (slots) {
+ case 1:
+ field = DMFC_FIFO_SIZE_64;
+ break;
+ case 2:
+ field = DMFC_FIFO_SIZE_128;
+ break;
+ case 4:
+ field = DMFC_FIFO_SIZE_256;
+ break;
+ case 8:
+ field = DMFC_FIFO_SIZE_512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (burstsize) {
+ case 16:
+ field |= DMFC_BURSTSIZE_16;
+ break;
+ case 32:
+ field |= DMFC_BURSTSIZE_32;
+ break;
+ case 64:
+ field |= DMFC_BURSTSIZE_64;
+ break;
+ case 128:
+ field |= DMFC_BURSTSIZE_128;
+ break;
+ }
+
+ field |= DMFC_SEGMENT(segment);
+
+ val = readl(priv->base + dmfc->data->channel_reg);
+
+ val &= ~(0xff << dmfc->data->shift);
+ val |= field << dmfc->data->shift;
+
+ writel(val, priv->base + dmfc->data->channel_reg);
+
+ dmfc->slots = slots;
+ dmfc->segment = segment;
+ dmfc->burstsize = burstsize;
+ dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+ return 0;
+}
+
+static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
+ unsigned long bandwidth)
+{
+ int slots = 1;
+
+ while (slots * priv->bandwidth_per_slot < bandwidth)
+ slots *= 2;
+
+ return slots;
+}
+
+static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
+{
+ unsigned slotmask_need, slotmask_used = 0;
+ int i, segment = 0;
+
+ slotmask_need = (1 << slots) - 1;
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+ slotmask_used |= priv->channels[i].slotmask;
+
+ while (slotmask_need <= 0xff) {
+ if (!(slotmask_used & slotmask_need))
+ return segment;
+
+ slotmask_need <<= 1;
+ segment++;
+ }
+
+ return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+ int i;
+
+ dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
+ dmfc->slots, dmfc->segment);
+
+ mutex_lock(&priv->mutex);
+
+ if (!dmfc->slots)
+ goto out;
+
+ dmfc->slotmask = 0;
+ dmfc->slots = 0;
+ dmfc->segment = 0;
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+ priv->channels[i].slotmask = 0;
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+ if (priv->channels[i].slots > 0) {
+ priv->channels[i].segment =
+ dmfc_find_slots(priv, priv->channels[i].slots);
+ priv->channels[i].slotmask =
+ ((1 << priv->channels[i].slots) - 1) <<
+ priv->channels[i].segment;
+ }
+ }
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+ if (priv->channels[i].slots > 0)
+ ipu_dmfc_setup_channel(&priv->channels[i],
+ priv->channels[i].slots,
+ priv->channels[i].segment,
+ priv->channels[i].burstsize);
+ }
+out:
+ mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+ unsigned long bandwidth_pixel_per_second, int burstsize)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+ int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
+ int segment = 0, ret = 0;
+
+ dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+ bandwidth_pixel_per_second / 1000000,
+ dmfc->data->ipu_channel);
+
+ ipu_dmfc_free_bandwidth(dmfc);
+
+ mutex_lock(&priv->mutex);
+
+ if (slots > 8) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ segment = dmfc_find_slots(priv, slots);
+ if (segment < 0) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
+
+out:
+ mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+ struct ipu_dmfc_priv *priv = dmfc->priv;
+ u32 dmfc_gen1;
+
+ dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
+
+ if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
+ dmfc_gen1 |= 1 << dmfc->data->eot_shift;
+ else
+ dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
+
+ writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+{
+ struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
+ int i;
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+ if (dmfcdata[i].ipu_channel == ipu_channel)
+ return &priv->channels[i];
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+ ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+ struct clk *ipu_clk)
+{
+ struct ipu_dmfc_priv *priv;
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->ipu = ipu;
+ mutex_init(&priv->mutex);
+
+ ipu->dmfc_priv = priv;
+
+ for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
+ priv->channels[i].priv = priv;
+ priv->channels[i].ipu = ipu;
+ priv->channels[i].data = &dmfcdata[i];
+ }
+
+ writel(0x0, priv->base + DMFC_WR_CHAN);
+ writel(0x0, priv->base + DMFC_DP_CHAN);
+
+ /*
+ * We have a total bandwidth of clkrate * 4pixel divided
+ * into 8 slots.
+ */
+ priv->bandwidth_per_slot = clk_get_rate(ipu_clk) / 8;
+
+ dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+ priv->bandwidth_per_slot / 1000000);
+
+ writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
+ writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
+ writel(0x00000003, priv->base + DMFC_GENERAL1);
+
+ return 0;
+}
+
+void ipu_dmfc_exit(struct ipu_soc *ipu)
+{
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "imx-ipu-v3.h"
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF 0x0
+#define DP_GRAPH_WIND_CTRL 0x0004
+#define DP_FG_POS 0x0008
+#define DP_CSC_A_0 0x0044
+#define DP_CSC_A_1 0x0048
+#define DP_CSC_A_2 0x004C
+#define DP_CSC_A_3 0x0050
+#define DP_CSC_0 0x0054
+#define DP_CSC_1 0x0058
+
+#define DP_COM_CONF_FG_EN (1 << 0)
+#define DP_COM_CONF_GWSEL (1 << 1)
+#define DP_COM_CONF_GWAM (1 << 2)
+#define DP_COM_CONF_GWCKE (1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET 8
+#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
+
+struct ipu_dp_priv;
+
+struct ipu_dp {
+ u32 flow;
+ bool in_use;
+ bool foreground;
+ enum ipu_color_space in_cs;
+};
+
+struct ipu_flow {
+ struct ipu_dp foreground;
+ struct ipu_dp background;
+ enum ipu_color_space out_cs;
+ void __iomem *base;
+ struct ipu_dp_priv *priv;
+};
+
+struct ipu_dp_priv {
+ struct ipu_soc *ipu;
+ struct device *dev;
+ void __iomem *base;
+ struct ipu_flow flow[3];
+ struct mutex mutex;
+ int use_count;
+};
+
+static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+
+static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
+{
+ if (dp->foreground)
+ return container_of(dp, struct ipu_flow, foreground);
+ else
+ return container_of(dp, struct ipu_flow, background);
+}
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
+ u8 alpha, bool bg_chan)
+{
+ struct ipu_flow *flow = to_flow(dp);
+ struct ipu_dp_priv *priv = flow->priv;
+ u32 reg;
+
+ mutex_lock(&priv->mutex);
+
+ reg = readl(flow->base + DP_COM_CONF);
+ if (bg_chan)
+ reg &= ~DP_COM_CONF_GWSEL;
+ else
+ reg |= DP_COM_CONF_GWSEL;
+ writel(reg, flow->base + DP_COM_CONF);
+
+ if (enable) {
+ reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
+ writel(reg | ((u32) alpha << 24),
+ flow->base + DP_GRAPH_WIND_CTRL);
+
+ reg = readl(flow->base + DP_COM_CONF);
+ writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+ } else {
+ reg = readl(flow->base + DP_COM_CONF);
+ writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
+ }
+
+ ipu_srm_dp_sync_update(priv->ipu);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+ struct ipu_flow *flow = to_flow(dp);
+ struct ipu_dp_priv *priv = flow->priv;
+
+ writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
+
+ ipu_srm_dp_sync_update(priv->ipu);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+
+static void ipu_dp_csc_init(struct ipu_flow *flow,
+ enum ipu_color_space in,
+ enum ipu_color_space out,
+ u32 place)
+{
+ u32 reg;
+
+ reg = readl(flow->base + DP_COM_CONF);
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+ if (in == out) {
+ writel(reg, flow->base + DP_COM_CONF);
+ return;
+ }
+
+ if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
+ writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
+ writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
+ writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
+ writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
+ writel(0x3d6 | (0x0000 << 16) | (2 << 30),
+ flow->base + DP_CSC_0);
+ writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
+ flow->base + DP_CSC_1);
+ } else {
+ writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
+ writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
+ writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
+ writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
+ writel(0x000 | (0x3e42 << 16) | (1 << 30),
+ flow->base + DP_CSC_0);
+ writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
+ flow->base + DP_CSC_1);
+ }
+
+ reg |= place;
+
+ writel(reg, flow->base + DP_COM_CONF);
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp,
+ enum ipu_color_space in,
+ enum ipu_color_space out)
+{
+ struct ipu_flow *flow = to_flow(dp);
+ struct ipu_dp_priv *priv = flow->priv;
+
+ mutex_lock(&priv->mutex);
+
+ dp->in_cs = in;
+
+ if (!dp->foreground)
+ flow->out_cs = out;
+
+ if (flow->foreground.in_cs == flow->background.in_cs) {
+ /*
+ * foreground and background are of same colorspace, put
+ * colorspace converter after combining unit.
+ */
+ ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
+ DP_COM_CONF_CSC_DEF_BOTH);
+ } else {
+ if (flow->foreground.in_cs == flow->out_cs)
+ /*
+ * foreground identical to output, apply color
+ * conversion on background
+ */
+ ipu_dp_csc_init(flow, flow->background.in_cs,
+ flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
+ else
+ ipu_dp_csc_init(flow, flow->foreground.in_cs,
+ flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
+ }
+
+ ipu_srm_dp_sync_update(priv->ipu);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+ struct ipu_flow *flow = to_flow(dp);
+ struct ipu_dp_priv *priv = flow->priv;
+
+ mutex_lock(&priv->mutex);
+
+ if (!priv->use_count)
+ ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
+
+ priv->use_count++;
+
+ if (dp->foreground) {
+ u32 reg;
+
+ reg = readl(flow->base + DP_COM_CONF);
+ reg |= DP_COM_CONF_FG_EN;
+ writel(reg, flow->base + DP_COM_CONF);
+
+ ipu_srm_dp_sync_update(priv->ipu);
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+ struct ipu_flow *flow = to_flow(dp);
+ struct ipu_dp_priv *priv = flow->priv;
+
+ mutex_lock(&priv->mutex);
+
+ priv->use_count--;
+
+ if (dp->foreground) {
+ u32 reg, csc;
+
+ reg = readl(flow->base + DP_COM_CONF);
+ csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+ if (csc == DP_COM_CONF_CSC_DEF_FG)
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+ reg &= ~DP_COM_CONF_FG_EN;
+ writel(reg, flow->base + DP_COM_CONF);
+
+ writel(0, flow->base + DP_FG_POS);
+ ipu_srm_dp_sync_update(priv->ipu);
+ }
+
+ if (!priv->use_count)
+ ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
+
+ if (priv->use_count < 0)
+ priv->use_count = 0;
+
+ mutex_unlock(&priv->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
+{
+ struct ipu_dp_priv *priv = ipu->dp_priv;
+ struct ipu_dp *dp;
+
+ if (flow > 5)
+ return ERR_PTR(-EINVAL);
+
+ if (flow & 1)
+ dp = &priv->flow[flow >> 1].foreground;
+ else
+ dp = &priv->flow[flow >> 1].background;
+
+ if (dp->in_use)
+ return ERR_PTR(-EBUSY);
+
+ dp->in_use = true;
+
+ return dp;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+ dp->in_use = false;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_put);
+
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+{
+ struct ipu_dp_priv *priv;
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ priv->dev = dev;
+ priv->ipu = ipu;
+
+ ipu->dp_priv = priv;
+
+ priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!priv->base) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ mutex_init(&priv->mutex);
+
+ for (i = 0; i < 3; i++) {
+ priv->flow[i].foreground.foreground = 1;
+ priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
+ priv->flow[i].priv = priv;
+ }
+
+ return 0;
+}
+
+void ipu_dp_exit(struct ipu_soc *ipu)
+{
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+struct ipu_soc;
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "imx-ipu-v3.h"
+
+#define IPUV3_CHANNEL_CSI0 0
+#define IPUV3_CHANNEL_CSI1 1
+#define IPUV3_CHANNEL_CSI2 2
+#define IPUV3_CHANNEL_CSI3 3
+#define IPUV3_CHANNEL_MEM_BG_SYNC 23
+#define IPUV3_CHANNEL_MEM_FG_SYNC 27
+#define IPUV3_CHANNEL_MEM_DC_SYNC 28
+#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
+#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
+#define IPUV3_CHANNEL_ROT_ENC_MEM 45
+#define IPUV3_CHANNEL_ROT_VF_MEM 46
+#define IPUV3_CHANNEL_ROT_PP_MEM 47
+#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48
+#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49
+#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50
+#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
+
+#define IPU_MCU_T_DEFAULT 8
+#define IPU_CM_IDMAC_REG_OFS 0x00008000
+#define IPU_CM_IC_REG_OFS 0x00020000
+#define IPU_CM_IRT_REG_OFS 0x00028000
+#define IPU_CM_CSI0_REG_OFS 0x00030000
+#define IPU_CM_CSI1_REG_OFS 0x00038000
+#define IPU_CM_SMFC_REG_OFS 0x00050000
+#define IPU_CM_DC_REG_OFS 0x00058000
+#define IPU_CM_DMFC_REG_OFS 0x00060000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset) (offset)
+
+#define IPU_CONF IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
+#define IPU_SKIP IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
+#define IPU_SNOOP IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST IPU_CM_REG(0x00dc)
+#define IPU_PM IPU_CM_REG(0x00e0)
+#define IPU_GPR IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
+#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
+
+#define IPU_DI0_COUNTER_RELEASE (1 << 24)
+#define IPU_DI1_COUNTER_RELEASE (1 << 25)
+
+#define IPU_IDMAC_REG(offset) (offset)
+
+#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+#define IPU_NUM_IRQS (32 * 5)
+
+enum ipu_modules {
+ IPU_CONF_CSI0_EN = (1 << 0),
+ IPU_CONF_CSI1_EN = (1 << 1),
+ IPU_CONF_IC_EN = (1 << 2),
+ IPU_CONF_ROT_EN = (1 << 3),
+ IPU_CONF_ISP_EN = (1 << 4),
+ IPU_CONF_DP_EN = (1 << 5),
+ IPU_CONF_DI0_EN = (1 << 6),
+ IPU_CONF_DI1_EN = (1 << 7),
+ IPU_CONF_SMFC_EN = (1 << 8),
+ IPU_CONF_DC_EN = (1 << 9),
+ IPU_CONF_DMFC_EN = (1 << 10),
+
+ IPU_CONF_VDI_EN = (1 << 12),
+
+ IPU_CONF_IDMAC_DIS = (1 << 22),
+
+ IPU_CONF_IC_DMFC_SEL = (1 << 25),
+ IPU_CONF_IC_DMFC_SYNC = (1 << 26),
+ IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
+
+ IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
+ IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
+ IPU_CONF_IC_INPUT = (1 << 30),
+ IPU_CONF_CSI_SEL = (1 << 31),
+};
+
+struct ipuv3_channel {
+ unsigned int num;
+
+ bool enabled;
+ bool busy;
+
+ struct ipu_soc *ipu;
+};
+
+struct ipu_dc_priv;
+struct ipu_dmfc_priv;
+struct ipu_di;
+struct ipu_devtype;
+
+struct ipu_soc {
+ struct device *dev;
+ const struct ipu_devtype *devtype;
+ enum ipuv3_type ipu_type;
+ spinlock_t lock;
+ struct mutex channel_lock;
+
+ void __iomem *cm_reg;
+ void __iomem *idmac_reg;
+ struct ipu_ch_param __iomem *cpmem_base;
+
+ int usecount;
+
+ struct clk *clk;
+
+ struct ipuv3_channel channel[64];
+
+ int irq_start;
+ int irq_sync;
+ int irq_err;
+
+ struct ipu_dc_priv *dc_priv;
+ struct ipu_dp_priv *dp_priv;
+ struct ipu_dmfc_priv *dmfc_priv;
+ struct ipu_di *di_priv[2];
+};
+
+void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+
+int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
+ unsigned long base, u32 module, struct clk *ipu_clk);
+void ipu_di_exit(struct ipu_soc *ipu, int id);
+
+int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+ struct clk *ipu_clk);
+void ipu_dmfc_exit(struct ipu_soc *ipu);
+
+int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+void ipu_dp_exit(struct ipu_soc *ipu);
+
+int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
+ unsigned long template_base);
+void ipu_dc_exit(struct ipu_soc *ipu);
+
+int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
+void ipu_cpmem_exit(struct ipu_soc *ipu);
+
+#endif /* __IPU_PRV_H__ */
--- /dev/null
+/*
+ * i.MX IPUv3 Graphics driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "ipu-v3/imx-ipu-v3.h"
+#include "imx-drm.h"
+
+#define DRIVER_DESC "i.MX IPUv3 Graphics"
+
+struct ipu_framebuffer {
+ struct drm_framebuffer base;
+ void *virt;
+ dma_addr_t phys;
+ size_t len;
+};
+
+struct ipu_crtc {
+ struct drm_fb_helper fb_helper;
+ struct ipu_framebuffer ifb;
+ int num_crtcs;
+ struct device *dev;
+ struct drm_crtc base;
+ struct imx_drm_crtc *imx_crtc;
+ struct ipuv3_channel *ipu_ch;
+ struct ipu_dc *dc;
+ struct ipu_dp *dp;
+ struct dmfc_channel *dmfc;
+ struct ipu_di *di;
+ int enabled;
+ struct ipu_priv *ipu_priv;
+ struct drm_pending_vblank_event *page_flip_event;
+ struct drm_framebuffer *newfb;
+ int irq;
+ u32 interface_pix_fmt;
+ unsigned long di_clkflags;
+};
+
+#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
+
+static int calc_vref(struct drm_display_mode *mode)
+{
+ unsigned long htotal, vtotal;
+
+ htotal = mode->htotal;
+ vtotal = mode->vtotal;
+
+ if (!htotal || !vtotal)
+ return 60;
+
+ return mode->clock * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref)
+{
+ return mode->hdisplay * mode->vdisplay * vref;
+}
+
+static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
+{
+ if (ipu_crtc->enabled)
+ return;
+
+ ipu_di_enable(ipu_crtc->di);
+ ipu_dmfc_enable_channel(ipu_crtc->dmfc);
+ ipu_idmac_enable_channel(ipu_crtc->ipu_ch);
+ ipu_dc_enable_channel(ipu_crtc->dc);
+ if (ipu_crtc->dp)
+ ipu_dp_enable_channel(ipu_crtc->dp);
+
+ ipu_crtc->enabled = 1;
+}
+
+static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
+{
+ if (!ipu_crtc->enabled)
+ return;
+
+ if (ipu_crtc->dp)
+ ipu_dp_disable_channel(ipu_crtc->dp);
+ ipu_dc_disable_channel(ipu_crtc->dc);
+ ipu_idmac_disable_channel(ipu_crtc->ipu_ch);
+ ipu_dmfc_disable_channel(ipu_crtc->dmfc);
+ ipu_di_disable(ipu_crtc->di);
+
+ ipu_crtc->enabled = 0;
+}
+
+static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ dev_info(ipu_crtc->dev, "%s mode: %d\n", __func__, mode);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ ipu_fb_enable(ipu_crtc);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ ipu_fb_disable(ipu_crtc);
+ break;
+ }
+}
+
+static int ipu_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+ int ret;
+
+ if (ipu_crtc->newfb)
+ return -EBUSY;
+
+ ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
+ if (ret) {
+ dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
+ list_del(&event->base.link);
+
+ return ret;
+ }
+
+ ipu_crtc->newfb = fb;
+ ipu_crtc->page_flip_event = event;
+
+ return 0;
+}
+
+static const struct drm_crtc_funcs ipu_crtc_funcs = {
+ .set_config = drm_crtc_helper_set_config,
+ .destroy = drm_crtc_cleanup,
+ .page_flip = ipu_page_flip,
+};
+
+static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_framebuffer *fb = crtc->fb;
+ unsigned long phys;
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ if (!cma_obj) {
+ DRM_LOG_KMS("entry is null.\n");
+ return -EFAULT;
+ }
+
+ phys = cma_obj->paddr;
+ phys += x * (fb->bits_per_pixel >> 3);
+ phys += y * fb->pitches[0];
+
+ dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys);
+ dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y);
+
+ ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]);
+ ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch),
+ 0, phys);
+
+ return 0;
+}
+
+static int ipu_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+ struct drm_framebuffer *fb = ipu_crtc->base.fb;
+ int ret;
+ struct ipu_di_signal_cfg sig_cfg = {};
+ u32 out_pixel_fmt;
+ struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch);
+ int bpp;
+ u32 v4l2_fmt;
+
+ dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
+ mode->hdisplay);
+ dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
+ mode->vdisplay);
+
+ ipu_ch_param_zero(cpmem);
+
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ v4l2_fmt = V4L2_PIX_FMT_RGB32;
+ bpp = 32;
+ break;
+ case DRM_FORMAT_RGB565:
+ v4l2_fmt = V4L2_PIX_FMT_RGB565;
+ bpp = 16;
+ break;
+ case DRM_FORMAT_RGB888:
+ v4l2_fmt = V4L2_PIX_FMT_RGB24;
+ bpp = 24;
+ break;
+ default:
+ dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n",
+ fb->pixel_format);
+ return -EINVAL;
+ }
+
+ out_pixel_fmt = ipu_crtc->interface_pix_fmt;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ sig_cfg.interlaced = 1;
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ sig_cfg.Hsync_pol = 1;
+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ sig_cfg.Vsync_pol = 1;
+
+ sig_cfg.enable_pol = 1;
+ sig_cfg.clk_pol = 0;
+ sig_cfg.width = mode->hdisplay;
+ sig_cfg.height = mode->vdisplay;
+ sig_cfg.pixel_fmt = out_pixel_fmt;
+ sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
+ sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
+ sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
+
+ sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
+ sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
+ sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
+ sig_cfg.pixelclock = mode->clock * 1000;
+ sig_cfg.clkflags = ipu_crtc->di_clkflags;
+
+ sig_cfg.v_to_h_sync = 0;
+
+ if (ipu_crtc->dp) {
+ ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
+ IPUV3_COLORSPACE_RGB);
+ if (ret) {
+ dev_err(ipu_crtc->dev,
+ "initializing display processor failed with %d\n",
+ ret);
+ return ret;
+ }
+ ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1);
+ }
+
+ ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
+ out_pixel_fmt, mode->hdisplay);
+ if (ret) {
+ dev_err(ipu_crtc->dev,
+ "initializing display controller failed with %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
+ if (ret) {
+ dev_err(ipu_crtc->dev,
+ "initializing panel failed with %d\n", ret);
+ return ret;
+ }
+
+ ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay);
+ ipu_cpmem_set_fmt(cpmem, v4l2_fmt);
+ ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch);
+
+ ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay);
+ if (ret) {
+ dev_err(ipu_crtc->dev,
+ "initializing dmfc channel failed with %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc,
+ calc_bandwidth(mode, calc_vref(mode)), 64);
+ if (ret) {
+ dev_err(ipu_crtc->dev,
+ "allocating dmfc bandwidth failed with %d\n",
+ ret);
+ return ret;
+ }
+
+ ipu_drm_set_base(crtc, x, y);
+
+ return 0;
+}
+
+static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
+{
+ struct drm_pending_vblank_event *e;
+ struct timeval now;
+ unsigned long flags;
+ struct drm_device *drm = ipu_crtc->base.dev;
+
+ spin_lock_irqsave(&drm->event_lock, flags);
+
+ e = ipu_crtc->page_flip_event;
+ if (!e) {
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+ return;
+ }
+
+ do_gettimeofday(&now);
+ e->event.sequence = 0;
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ ipu_crtc->page_flip_event = NULL;
+
+ imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
+
+ list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+
+ spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
+{
+ struct ipu_crtc *ipu_crtc = dev_id;
+
+ imx_drm_handle_vblank(ipu_crtc->imx_crtc);
+
+ if (ipu_crtc->newfb) {
+ ipu_crtc->base.fb = ipu_crtc->newfb;
+ ipu_crtc->newfb = NULL;
+ ipu_drm_set_base(&ipu_crtc->base, 0, 0);
+ ipu_crtc_handle_pageflip(ipu_crtc);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void ipu_crtc_prepare(struct drm_crtc *crtc)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ ipu_fb_disable(ipu_crtc);
+}
+
+static void ipu_crtc_commit(struct drm_crtc *crtc)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ ipu_fb_enable(ipu_crtc);
+}
+
+static void ipu_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static struct drm_crtc_helper_funcs ipu_helper_funcs = {
+ .dpms = ipu_crtc_dpms,
+ .mode_fixup = ipu_crtc_mode_fixup,
+ .mode_set = ipu_crtc_mode_set,
+ .prepare = ipu_crtc_prepare,
+ .commit = ipu_crtc_commit,
+ .load_lut = ipu_crtc_load_lut,
+};
+
+static int ipu_enable_vblank(struct drm_crtc *crtc)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ enable_irq(ipu_crtc->irq);
+
+ return 0;
+}
+
+static void ipu_disable_vblank(struct drm_crtc *crtc)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ disable_irq(ipu_crtc->irq);
+}
+
+static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
+ u32 pixfmt)
+{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+ ipu_crtc->interface_pix_fmt = pixfmt;
+
+ switch (encoder_type) {
+ case DRM_MODE_ENCODER_LVDS:
+ ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
+ IPU_DI_CLKMODE_EXT;
+ break;
+ case DRM_MODE_ENCODER_NONE:
+ ipu_crtc->di_clkflags = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
+ .enable_vblank = ipu_enable_vblank,
+ .disable_vblank = ipu_disable_vblank,
+ .set_interface_pix_fmt = ipu_set_interface_pix_fmt,
+ .crtc_funcs = &ipu_crtc_funcs,
+ .crtc_helper_funcs = &ipu_helper_funcs,
+};
+
+static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
+{
+ if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch))
+ ipu_idmac_put(ipu_crtc->ipu_ch);
+ if (!IS_ERR_OR_NULL(ipu_crtc->dmfc))
+ ipu_dmfc_put(ipu_crtc->dmfc);
+ if (!IS_ERR_OR_NULL(ipu_crtc->dp))
+ ipu_dp_put(ipu_crtc->dp);
+ if (!IS_ERR_OR_NULL(ipu_crtc->di))
+ ipu_di_put(ipu_crtc->di);
+}
+
+static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
+ struct ipu_client_platformdata *pdata)
+{
+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+ int ret;
+
+ ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]);
+ if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) {
+ ret = PTR_ERR(ipu_crtc->ipu_ch);
+ goto err_out;
+ }
+
+ ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
+ if (IS_ERR(ipu_crtc->dc)) {
+ ret = PTR_ERR(ipu_crtc->dc);
+ goto err_out;
+ }
+
+ ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]);
+ if (IS_ERR(ipu_crtc->dmfc)) {
+ ret = PTR_ERR(ipu_crtc->dmfc);
+ goto err_out;
+ }
+
+ if (pdata->dp >= 0) {
+ ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp);
+ if (IS_ERR(ipu_crtc->dp)) {
+ ret = PTR_ERR(ipu_crtc->ipu_ch);
+ goto err_out;
+ }
+ }
+
+ ipu_crtc->di = ipu_di_get(ipu, pdata->di);
+ if (IS_ERR(ipu_crtc->di)) {
+ ret = PTR_ERR(ipu_crtc->di);
+ goto err_out;
+ }
+
+ ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch,
+ IPU_IRQ_EOF);
+ ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
+ "imx_drm", ipu_crtc);
+ if (ret < 0) {
+ dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
+ goto err_out;
+ }
+
+ disable_irq(ipu_crtc->irq);
+
+ return 0;
+err_out:
+ ipu_put_resources(ipu_crtc);
+
+ return ret;
+}
+
+static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
+ struct ipu_client_platformdata *pdata)
+{
+ int ret;
+
+ ret = ipu_get_resources(ipu_crtc, pdata);
+ if (ret) {
+ dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = imx_drm_add_crtc(&ipu_crtc->base,
+ &ipu_crtc->imx_crtc,
+ &ipu_crtc_helper_funcs, THIS_MODULE,
+ ipu_crtc->dev->parent->of_node, pdata->di);
+ if (ret) {
+ dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
+ goto err_put_resources;
+ }
+
+ return 0;
+
+err_put_resources:
+ ipu_put_resources(ipu_crtc);
+
+ return ret;
+}
+
+static int __devinit ipu_drm_probe(struct platform_device *pdev)
+{
+ struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
+ struct ipu_crtc *ipu_crtc;
+ int ret;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+ if (!ipu_crtc)
+ return -ENOMEM;
+
+ ipu_crtc->dev = &pdev->dev;
+
+ ret = ipu_crtc_init(ipu_crtc, pdata);
+
+ platform_set_drvdata(pdev, ipu_crtc);
+
+ return 0;
+}
+
+static int __devexit ipu_drm_remove(struct platform_device *pdev)
+{
+ struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+
+ imx_drm_remove_crtc(ipu_crtc->imx_crtc);
+
+ ipu_put_resources(ipu_crtc);
+
+ return 0;
+}
+
+static struct platform_driver ipu_drm_driver = {
+ .driver = {
+ .name = "imx-ipuv3-crtc",
+ },
+ .probe = ipu_drm_probe,
+ .remove = __devexit_p(ipu_drm_remove),
+};
+module_platform_driver(ipu_drm_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * i.MX drm driver - parallel display implementation
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/videodev2.h>
+
+#include "imx-drm.h"
+
+#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
+#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
+
+struct imx_parallel_display {
+ struct drm_connector connector;
+ struct imx_drm_connector *imx_drm_connector;
+ struct drm_encoder encoder;
+ struct imx_drm_encoder *imx_drm_encoder;
+ struct device *dev;
+ void *edid;
+ int edid_len;
+ u32 interface_pix_fmt;
+ int mode_valid;
+ struct drm_display_mode mode;
+};
+
+static enum drm_connector_status imx_pd_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void imx_pd_connector_destroy(struct drm_connector *connector)
+{
+ /* do not free here */
+}
+
+static int imx_pd_connector_get_modes(struct drm_connector *connector)
+{
+ struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+ int num_modes = 0;
+
+ if (imxpd->edid) {
+ drm_mode_connector_update_edid_property(connector, imxpd->edid);
+ num_modes = drm_add_edid_modes(connector, imxpd->edid);
+ }
+
+ if (imxpd->mode_valid) {
+ struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ drm_mode_copy(mode, &imxpd->mode);
+ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ drm_mode_probed_add(connector, mode);
+ num_modes++;
+ }
+
+ return num_modes;
+}
+
+static int imx_pd_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return 0;
+}
+
+static struct drm_encoder *imx_pd_connector_best_encoder(
+ struct drm_connector *connector)
+{
+ struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+
+ return &imxpd->encoder;
+}
+
+static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
+{
+ struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+ imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
+ imxpd->interface_pix_fmt);
+}
+
+static void imx_pd_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void imx_pd_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
+{
+ /* do not free here */
+}
+
+static struct drm_connector_funcs imx_pd_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = imx_pd_connector_detect,
+ .destroy = imx_pd_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
+ .get_modes = imx_pd_connector_get_modes,
+ .best_encoder = imx_pd_connector_best_encoder,
+ .mode_valid = imx_pd_connector_mode_valid,
+};
+
+static struct drm_encoder_funcs imx_pd_encoder_funcs = {
+ .destroy = imx_pd_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
+ .dpms = imx_pd_encoder_dpms,
+ .mode_fixup = imx_pd_encoder_mode_fixup,
+ .prepare = imx_pd_encoder_prepare,
+ .commit = imx_pd_encoder_commit,
+ .mode_set = imx_pd_encoder_mode_set,
+ .disable = imx_pd_encoder_disable,
+};
+
+static int imx_pd_register(struct imx_parallel_display *imxpd)
+{
+ int ret;
+
+ drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
+
+ imxpd->connector.funcs = &imx_pd_connector_funcs;
+ imxpd->encoder.funcs = &imx_pd_encoder_funcs;
+
+ imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+ imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+
+ drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
+ ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
+ THIS_MODULE);
+ if (ret) {
+ dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
+ return ret;
+ }
+
+ drm_connector_helper_add(&imxpd->connector,
+ &imx_pd_connector_helper_funcs);
+
+ ret = imx_drm_add_connector(&imxpd->connector,
+ &imxpd->imx_drm_connector, THIS_MODULE);
+ if (ret) {
+ imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+ dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
+ return ret;
+ }
+
+ imxpd->connector.encoder = &imxpd->encoder;
+
+ return 0;
+}
+
+static int __devinit imx_pd_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const u8 *edidp;
+ struct imx_parallel_display *imxpd;
+ int ret;
+ const char *fmt;
+
+ imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+ if (!imxpd)
+ return -ENOMEM;
+
+ edidp = of_get_property(np, "edid", &imxpd->edid_len);
+ if (edidp)
+ imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
+
+ ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
+ if (!ret) {
+ if (!strcmp(fmt, "rgb24"))
+ imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+ else if (!strcmp(fmt, "rgb565"))
+ imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+ }
+
+ imxpd->dev = &pdev->dev;
+
+ ret = imx_pd_register(imxpd);
+ if (ret)
+ return ret;
+
+ ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
+
+ platform_set_drvdata(pdev, imxpd);
+
+ return 0;
+}
+
+static int __devexit imx_pd_remove(struct platform_device *pdev)
+{
+ struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
+ struct drm_connector *connector = &imxpd->connector;
+ struct drm_encoder *encoder = &imxpd->encoder;
+
+ drm_mode_connector_detach_encoder(connector, encoder);
+
+ imx_drm_remove_connector(imxpd->imx_drm_connector);
+ imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+
+ return 0;
+}
+
+static const struct of_device_id imx_pd_dt_ids[] = {
+ { .compatible = "fsl,imx-parallel-display", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver imx_pd_driver = {
+ .probe = imx_pd_probe,
+ .remove = __devexit_p(imx_pd_remove),
+ .driver = {
+ .of_match_table = imx_pd_dt_ids,
+ .name = "imx-parallel-display",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(imx_pd_driver);
+
+MODULE_DESCRIPTION("i.MX parallel display driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
high = ts_data->adc_end_val - ts_data->adc_start_val;
mid = (high + low) / 2;
- if (temp < bg_ptr->conv_table[high] || temp > bg_ptr->conv_table[high])
+ if (temp < bg_ptr->conv_table[low] || temp > bg_ptr->conv_table[high])
return -EINVAL;
while (low < high) {
if (pd)
oz_pd_get(pd);
spin_unlock_bh(&g_cdev.lock);
- if (pd == 0)
+ if (pd == NULL)
return -1;
ctx = oz_cdev_claim_ctx(pd);
- if (ctx == 0)
+ if (ctx == NULL)
goto out2;
n = ctx->rd_in - ctx->rd_out;
if (n < 0)
if (pd)
oz_pd_get(pd);
spin_unlock_bh(&g_cdev.lock);
- if (pd == 0)
+ if (pd == NULL)
return -1;
eb = &pd->elt_buff;
ei = oz_elt_info_alloc(eb);
- if (ei == 0) {
+ if (ei == NULL) {
count = 0;
goto out;
}
return 0;
}
ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
- if (ctx == 0)
+ if (ctx == NULL)
return -ENOMEM;
atomic_set(&ctx->ref_count, 1);
ctx->tx_seq_num = 1;
spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
}
spin_lock(&g_cdev.lock);
- if ((g_cdev.active_pd == 0) &&
+ if ((g_cdev.active_pd == NULL) &&
(memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) {
oz_pd_get(pd);
g_cdev.active_pd = pd;
int ix;
ctx = oz_cdev_claim_ctx(pd);
- if (ctx == 0) {
+ if (ctx == NULL) {
oz_trace("Cannot claim serial context.\n");
return;
}
break;
}
- /* Check wether one flag was changed */
+ /* Check whether one flag was changed */
if (oldflags != lcd_flags) {
/* check whether one of B,C,D flags were changed */
if ((oldflags ^ lcd_flags) &
lcd_write_cmd(0x30
| ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
| ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
- /* check wether L flag was changed */
+ /* check whether L flag was changed */
else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) {
if (lcd_flags & (LCD_FLAG_L))
lcd_backlight(1);
else
ieee->seq_ctrl[0]++;
- /* check wether the managed packet queued greater than 5 */
+ /* check whether the managed packet queued greater than 5 */
if (!ieee->check_nic_enough_desc(ieee->dev, tcb_desc->queue_index) ||
(skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0) ||
(ieee->queue_stop)) {
else
ieee->seq_ctrl[0]++;
- /* check wether the managed packet queued greater than 5 */
+ /* check whether the managed packet queued greater than 5 */
if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\
(skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\
(ieee->queue_stop) ) {
struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
struct rtsx_chip *chip;
- dev_info(&dev->pci->dev, "Ready to suspend\n");
-
- if (!dev) {
- dev_err(&dev->pci->dev, "Invalid memory\n");
+ if (!dev)
return 0;
- }
/* lock the device pointers */
mutex_lock(&(dev->dev_mutex));
struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
struct rtsx_chip *chip;
- dev_info(&dev->pci->dev, "Ready to resume\n");
-
- if (!dev) {
- dev_err(&dev->pci->dev, "Invalid memory\n");
+ if (!dev)
return 0;
- }
chip = dev->chip;
struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci);
struct rtsx_chip *chip;
- dev_info(&dev->pci->dev, "Ready to shutdown\n");
-
- if (!dev) {
- dev_err(&dev->pci->dev, "Invalid memory\n");
+ if (!dev)
return;
- }
chip = dev->chip;
void dc_receiver_onoff(struct channel *, u32);
void dc_transmitter_onoff(struct channel *, u32);
void dc_set_loopback(struct channel *, u32);
-u32 dc_init_descriptor_list(struct channel *);
void dc_clear_descriptor_list(struct channel *);
void dc_drop_descriptor_list(struct channel *);
void dc_set_output_port(struct channel *);
#include "2t3e3.h"
#include "ctrl.h"
+static int dc_init_descriptor_list(struct channel *sc);
+
void dc_init(struct channel *sc)
{
u32 val;
SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE);
}
-u32 dc_init_descriptor_list(struct channel *sc)
+static int dc_init_descriptor_list(struct channel *sc)
{
u32 i, j;
struct sk_buff *m;
sizeof(t3e3_rx_desc_t), GFP_KERNEL);
if (sc->ether.rx_ring == NULL) {
dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n");
- return ENOMEM;
+ return -ENOMEM;
}
if (sc->ether.tx_ring == NULL)
kfree(sc->ether.rx_ring);
sc->ether.rx_ring = NULL;
dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n");
- return ENOMEM;
+ return -ENOMEM;
}
sc->ether.tx_ring = NULL;
dev_err(&sc->pdev->dev, "SBE 2T3E3: token_alloc err:"
" no buffer space for RX ring\n");
- return ENOBUFS;
+ return -ENOBUFS;
}
sc->ether.rx_data[i] = m;
}
dev = alloc_hdlcdev(channel);
if (!dev) {
printk(KERN_ERR "SBE 2T3E3" ": Out of memory\n");
+ err = -ENOMEM;
goto free_regions;
}
else
channel->h.slot = 0;
- if (setup_device(dev, channel))
- goto free_regions;
+ err = setup_device(dev, channel);
+ if (err)
+ goto free_dev;
pci_read_config_dword(channel->pdev, 0x40, &val); /* mask sleep mode */
pci_write_config_dword(channel->pdev, 0x40, val & 0x3FFFFFFF);
pci_read_config_dword(channel->pdev, PCI_COMMAND, &channel->h.command);
t3e3_init(channel);
- if (request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev)) {
+ err = request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev);
+ if (err) {
printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
- goto free_regions;
+ goto unregister_dev;
}
pci_set_drvdata(pdev, channel);
return 0;
+unregister_dev:
+ unregister_hdlc_device(dev);
+free_dev:
+ free_netdev(dev);
free_regions:
pci_release_regions(pdev);
disable:
config SBYPASS
tristate "Silicom BypassCTL library support"
- depends on PCI
+ depends on PCI && NET
depends on m
---help---
If you have a network (Ethernet) controller of this type, say Y
config BPCTL
tristate "Silicom BypassCTL net support"
- depends on PCI
+ depends on PCI && NET
depends on m
select SBYPASS
select NET_CORE
int bp_10g9;
int bp_i80;
int bp_540;
-
-// selftest stanza
int (*hard_start_xmit_save) (struct sk_buff *skb,
struct net_device *dev);
const struct net_device_ops *old_ops;
struct net_device_ops new_ops;
int bp_self_test_flag;
char *bp_tx_data;
-// end selftest stanza
-//
struct bypass_pfs_sd bypass_pfs_set;
} bpctl_dev_t;
struct net_device *dev = ptr;
static bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
- //printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex );
- //return NOTIFY_DONE;
+ /* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
+ /* return NOTIFY_DONE; */
if (!dev)
return NOTIFY_DONE;
if (event == NETDEV_REGISTER) {
{
struct ethtool_drvinfo drvinfo;
- // char *str=NULL;
char cbuf[32];
char *buf = NULL;
char res[10];
memcpy(&cbuf, drvinfo.bus_info, 32);
buf = &cbuf[0];
- // while(*buf++){
-
- /*if(*buf==':'){
- buf++;
- break;
- } */
- //}
while (*buf++ != ':') ;
for (i = 0; i < 10; i++, buf++) {
if (*buf == ':')
}
if (event == NETDEV_UNREGISTER) {
int idx_dev = 0;
- //if_scan();
for (idx_dev = 0;
((bpctl_dev_arr[idx_dev].pdev != NULL)
&& (idx_dev < device_num)); idx_dev++) {
}
if (event == NETDEV_CHANGENAME) {
int idx_dev = 0;
- //if_scan();
for (idx_dev = 0;
((bpctl_dev_arr[idx_dev].pdev != NULL)
&& (idx_dev < device_num)); idx_dev++) {
return NOTIFY_DONE;
}
- //return NOTIFY_DONE;
switch (event) {
if (netif_carrier_ok(dev))
return NOTIFY_DONE;
- //if_scan();
if (((dev_num = get_dev_idx(dev->ifindex)) == -1) ||
(!(pbpctl_dev = &bpctl_dev_arr[dev_num])))
return NOTIFY_DONE;
BPCTLI_CTRL_EXT_MCLK_DATA));
else {
-/* To start management : MCLK 1, MDIO 1, output*/
- //writel((0x2|0x8), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
+ /* To start management : MCLK 1, MDIO 1, output*/
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT
| BP10G_MDIO_DATA_OUT));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl | BP10G_MDIO_DATA | BP10G_MDIO_DIR));
}
(BPCTLI_CTRL_EXT_MCLK_DATA)));
else {
- //writel((0x2), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext |
BP10G_MDIO_DATA_OUT) &
~(BP10G_MCLK_DATA_OUT)));
- // BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl |BP10G_MDIO_DIR|BP10G_MDIO_DATA));
}
usec_delay(PULSE_TIME);
(BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
- // writel((0x8), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext |
BP10G_MCLK_DATA_OUT) &
~BP10G_MDIO_DATA_OUT));
- // BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
usec_delay(PULSE_TIME);
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
- //writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
usec_delay(PULSE_TIME);
ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP);
}
- //ctrl_ext=BP10G_READ_REG(pbpctl_dev,EODSDP);
while (i--) {
if (pbpctl_dev->bp_10g9) {
BPCTLI_CTRL_EXT_MCLK_DATA)));
else {
- // writel(( 0/*0x1*/), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP, ((ctrl_ext | BP10G_MDIO_DATA_OUT) & ~BP10G_MCLK_DATA_OUT)); /* ? */
- // printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP););
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl &~BP10G_MDIO_DIR));
+ /* printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP);); */
}
(BPCTLI_CTRL_EXT_MDIO_DIR)));
else {
- // writel((0x8 /*|0x1*/ ), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl &~BP10G_MDIO_DIR));
}
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
else
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
- //ctrl_ext =readl((void *)((pbpctl_dev)->mem_map) + 0x28);
usec_delay(PULSE_TIME);
if (pbpctl_dev->bp_10g9) {
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
- //writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
}
usec_delay(CMND_INTERVAL);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- // BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
- // writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
}
usec_delay(CMND_INTERVAL * 4);
ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO);
- //printk("2reg=%x\n", ctrl_ext);
+ printk("2reg=%x\n", ctrl_ext);
#ifdef BP_SYNC_FLAG
spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags);
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
- // writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
- // writel((0x8), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext | BP10G_MCLK_DATA_OUT |
BP10G_MDIO_DATA_OUT));
- // BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl &~(BP10G_MDIO_DATA|BP10G_MDIO_DIR)));
}
usec_delay(PULSE_TIME);
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
- //writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
BPCTLI_CTRL_EXT_MCLK_DATA)));
} else {
- // writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP);
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
if (pbpctl_dev->bp_10g9) {
(BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
- //writel((0x8), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
((ctrl_ext | BP10G_MCLK_DATA_OUT) &
~BP10G_MDIO_DATA_OUT));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
BPCTLI_CTRL_EXT_MDIO_DATA)));
else {
- //writel((0x0), (void *)(((pbpctl_dev)->mem_map) + 0x28)) ;
BP10G_WRITE_REG(pbpctl_dev, EODSDP,
(ctrl_ext &
~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT)));
- //BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl |BP10G_MDIO_DIR)&~BP10G_MDIO_DATA));
}
if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) /*&&
(pbpctl_dev->bp_ext_ver<PXG4BPFI_VER) */ )
&& ((bpctl_dev_arr[idx_dev].func == 1)
&& (pbpctl_dev->func == 0))) {
- return (&(bpctl_dev_arr[idx_dev]));
+ return &(bpctl_dev_arr[idx_dev]);
}
if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) &&
(bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) &&
((bpctl_dev_arr[idx_dev].func == 3)
&& (pbpctl_dev->func == 2))) {
- return (&(bpctl_dev_arr[idx_dev]));
+ return &(bpctl_dev_arr[idx_dev]);
}
}
}
&& ((bpctl_dev_arr[idx_dev].func == 0)
&& (pbpctl_dev->func == 1))) {
- return (&(bpctl_dev_arr[idx_dev]));
+ return &(bpctl_dev_arr[idx_dev]);
}
if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) &&
(bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) &&
((bpctl_dev_arr[idx_dev].func == 2)
&& (pbpctl_dev->func == 3))) {
- return (&(bpctl_dev_arr[idx_dev]));
+ return &(bpctl_dev_arr[idx_dev]);
}
}
}
else if (!pbpctl_dev->bp_10g)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL);
else
- //ctrl =readl((void *)((pbpctl_dev)->mem_map) + 0x20);
ctrl = BP10G_READ_REG(pbpctl_dev, ESDP);
if (!tx_state)
BPCTLI_CTRL_SWDPIN0));
else
- //writel((ctrl|(0x1|0x100)), (void *)(((pbpctl_dev)->mem_map) + 0x20)) ;
BP10G_WRITE_REG(pbpctl_dev, ESDP,
(ctrl | BP10G_SDP0_DATA |
BP10G_SDP0_DIR));
BPCTLI_CTRL_SDP0_DIR)));
}
} else
- //writel(((ctrl|0x100)&~0x1), (void *)(((pbpctl_dev)->mem_map) + 0x20)) ;
BP10G_WRITE_REG(pbpctl_dev, ESDP,
((ctrl | BP10G_SDP0_DIR) &
~BP10G_SDP0_DATA));
int wdt_time_left(bpctl_dev_t *pbpctl_dev)
{
- //unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ;
+ /* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */
unsigned long curr_time = jiffies, delta_time = 0, wdt_on_time =
pbpctl_dev->bypass_wdt_on_time, delta_time_msec = 0;
int time_left = 0;
ret = wdt_pulse_int(pbpctl_dev);
else
ret = send_wdt_pulse(pbpctl_dev);
- //if (ret==-1)
- // mod_timer(&pbpctl_dev->bp_timer, jiffies+1);
+ /* if (ret==-1)
+ mod_timer(&pbpctl_dev->bp_timer, jiffies+1);*/
return 1;
}
return BP_NOT_CAP;
}
}
-//#ifdef PMC_FIX_FLAG
/*WAIT_AT_PWRUP 0x80 */
int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev)
{
return BP_NOT_CAP;
}
-//#endif /*PMC_FIX_FLAG*/
int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode)
{
int bypass_fw_ver(bpctl_dev_t *pbpctl_dev)
{
if (is_bypass_fn(pbpctl_dev))
- return ((read_reg(pbpctl_dev, VER_REG_ADDR)));
+ return read_reg(pbpctl_dev, VER_REG_ADDR);
else
return BP_NOT_CAP;
}
}
if (pbpctl_dev->bp_ext_ver >= 0x8) {
- //BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, (BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT))&~BPCTLI_CTRL_EXT_SDP7_DIR);
if (pbpctl_dev->bp_10g9) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL);
BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL,
(ctrl_ext | BP10G_I2C_CLK_OUT));
- //return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28))&0x4)!=0?0:1);
return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) &
BP10G_I2C_CLK_IN) != 0 ? 0 : 1);
BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
(ctrl_ext |
BP10G_SDP7_DATA_OUT));
- //return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28))&0x4)!=0?0:1);
return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) &
BP10G_SDP7_DATA_IN) != 0 ? 0 : 1);
}
BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0);
} else {
if ((bypass_status_clear(pbpctl_dev)) >= 0)
- return (bypass_from_last_read(pbpctl_dev));
+ return bypass_from_last_read(pbpctl_dev);
}
}
{
if ((pbpctl_dev->bp_caps & SW_CTL_CAP) &&
(pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER))
- return (read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR));
+ return read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR);
return BP_NOT_CAP;
}
BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
(ctrl_ext |
BP10G_SDP6_DATA_OUT));
- // return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28))&0x1)!=0?0:1);
return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) &
BP10G_SDP6_DATA_IN) != 0 ? 0 : 1);
}
BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0);
else {
if ((bypass_status_clear(pbpctl_dev)) >= 0)
- return (bypass_from_last_read(pbpctl_dev));
+ return bypass_from_last_read(pbpctl_dev);
}
}
DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0);
if (pbpctl_dev->bp_i80) {
- // return((((read_reg(pbpctl_dev,STATUS_DISC_REG_ADDR)) & DISC_OFF_MASK)==DISC_OFF_MASK)?1:0);
return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT)) &
BPCTLI_CTRL_EXT_SDP6_DATA) != 0 ? 1 : 0);
}
if (pbpctl_dev->bp_540) {
ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, ESDP);
- //return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28))&0x4)!=0?0:1);
return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) &
BP10G_SDP2_DATA) != 0 ? 1 : 0);
}
- //if (pbpctl_dev->device==SILICOM_PXG2TBI_SSID) {
if (pbpctl_dev->media_type == bp_copper) {
#if 0
return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) &
BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0);
else
- // return(((readl((void *)((pbpctl_dev)->mem_map) + 0x20)) & 0x2)!=0?1:0);
return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) &
BP10G_SDP1_DATA) != 0 ? 1 : 0);
BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL,
(ctrl_ext |
BP10G_I2C_DATA_OUT));
- //return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28))&0x4)!=0?0:1);
return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) &
BP10G_I2C_DATA_IN) != 0 ? 1 : 0);
BP10G_WRITE_REG(pbpctl_dev_b, EODSDP,
(ctrl_ext |
BP10G_SDP6_DATA_OUT));
- // temp= (((BP10G_READ_REG(pbpctl_dev_b,EODSDP))&BP10G_SDP6_DATA_IN)!=0?1:0);
- //return(((readl((void *)((pbpctl_dev)->mem_map) + 0x28)) & 0x1)!=0?1:0);
return (((BP10G_READ_REG(pbpctl_dev_b, EODSDP))
& BP10G_SDP6_DATA_IN) != 0 ? 1 : 0);
}
if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
if (is_bypass_fn(pbpctl_dev) == 1)
return ret;
- // return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0);
+ /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
else
return ret;
- // return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0);
+ /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
}
return ret;
return BP_NOT_CAP;
}
-//#ifdef PMC_FIX_FLAG
int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev)
{
return BP_NOT_CAP;
}
-//#endif /*PMC_FIX_FLAG*/
int std_nic_status(bpctl_dev_t *pbpctl_dev)
{
else
pbpctl_dev->media_type = bp_fiber;
- }
- //if (!pbpctl_dev->bp_10g)
- // pbpctl_dev->media_type=((BPCTL_READ_REG(pbpctl_dev, STATUS))&BPCTLI_STATUS_TBIMODE)?bp_fiber:bp_copper;
- else {
+ } else {
if (BP10G_CX4_SERIES(pbpctl_dev->subdevice))
pbpctl_dev->media_type = bp_cx4;
else
pbpctl_dev->media_type = bp_fiber;
}
- //pbpctl_dev->bp_fw_ver=0xa8;
if (is_bypass_fn(pbpctl_dev)) {
pbpctl_dev->bp_caps |= BP_PWOFF_ON_CAP;
if ((ret = cmnd_on(pbpctl_dev)) < 0)
return ret;
if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
- return (dis_bypass_cap(pbpctl_dev));
+ return dis_bypass_cap(pbpctl_dev);
wdt_off(pbpctl_dev);
if (pbpctl_dev->bp_caps & BP_CAP)
bypass_off(pbpctl_dev);
dev_kfree_skb_irq(skb);
return 0;
}
- return (pbpctl_dev->hard_start_xmit_save(skb, dev));
+ return pbpctl_dev->hard_start_xmit_save(skb, dev);
}
#endif
int get_bypass_fn(bpctl_dev_t *pbpctl_dev)
{
- return (bypass_status(pbpctl_dev));
+ return bypass_status(pbpctl_dev);
}
int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev)
if (!pbpctl_dev)
return -1;
- return (bypass_change_status(pbpctl_dev));
+ return bypass_change_status(pbpctl_dev);
}
int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
if (!pbpctl_dev)
return -1;
- return (dis_bypass_cap_status(pbpctl_dev));
+ return dis_bypass_cap_status(pbpctl_dev);
}
int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
if (!pbpctl_dev)
return -1;
- return (default_pwroff_status(pbpctl_dev));
+ return default_pwroff_status(pbpctl_dev);
}
int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
if (!pbpctl_dev)
return -1;
- return (default_pwron_status(pbpctl_dev));
+ return default_pwron_status(pbpctl_dev);
}
int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout)
if (!pbpctl_dev)
return -1;
- return (wdt_timer(pbpctl_dev, time_left));
+ return wdt_timer(pbpctl_dev, time_left);
}
int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev)
if (!pbpctl_dev)
return -1;
- return (wdt_timer_reload(pbpctl_dev));
+ return wdt_timer_reload(pbpctl_dev);
}
int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev)
if (!pbpctl_dev)
return -1;
- return (std_nic_status(pbpctl_dev));
+ return std_nic_status(pbpctl_dev);
}
int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
if (!pbpctl_dev)
return -1;
- return (tap_status(pbpctl_dev));
+ return tap_status(pbpctl_dev);
}
int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
if (!pbpctl_dev)
return -1;
- return (tap_change_status(pbpctl_dev));
+ return tap_change_status(pbpctl_dev);
}
int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
if (!pbpctl_dev)
return -1;
- return (dis_tap_cap_status(pbpctl_dev));
+ return dis_tap_cap_status(pbpctl_dev);
}
int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
if (!pbpctl_dev)
return -1;
- return (disc_port_status(pbpctl_dev));
+ return disc_port_status(pbpctl_dev);
}
int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
if (!pbpctl_dev)
return -1;
- return (wdt_exp_mode_status(pbpctl_dev));
+ return wdt_exp_mode_status(pbpctl_dev);
}
int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param)
if (!pbpctl_dev)
return -1;
- return (wdt_exp_mode(pbpctl_dev, param));
+ return wdt_exp_mode(pbpctl_dev, param);
}
int reset_cont_fn(bpctl_dev_t *pbpctl_dev)
if ((ret = cmnd_on(pbpctl_dev)) < 0)
return ret;
- return (reset_cont(pbpctl_dev));
+ return reset_cont(pbpctl_dev);
}
int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state)
(pbpctl_dev_b->bp_tpl_flag))
return BP_NOT_CAP;
}
- return (set_tx(pbpctl_dev, tx_state));
+ return set_tx(pbpctl_dev, tx_state);
}
int set_bp_force_link_fn(int dev_num, int tx_state)
return -1;
bpctl_dev_curr = &bpctl_dev_arr[dev_num];
- return (set_bp_force_link(bpctl_dev_curr, tx_state));
+ return set_bp_force_link(bpctl_dev_curr, tx_state);
}
int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param)
if (!pbpctl_dev)
return -1;
- return (set_bypass_wd_auto(pbpctl_dev, param));
+ return set_bypass_wd_auto(pbpctl_dev, param);
}
int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev)
if (!pbpctl_dev)
return -1;
- return (get_bypass_wd_auto(pbpctl_dev));
+ return get_bypass_wd_auto(pbpctl_dev);
}
#ifdef BP_SELF_TEST
if (!pbpctl_dev)
return -1;
- return (set_bp_self_test(pbpctl_dev, param));
+ return set_bp_self_test(pbpctl_dev, param);
}
int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev)
if (!pbpctl_dev)
return -1;
- return (get_bp_self_test(pbpctl_dev));
+ return get_bp_self_test(pbpctl_dev);
}
#endif
if (!pbpctl_dev)
return -1;
- return (pbpctl_dev->bp_caps);
+ return pbpctl_dev->bp_caps;
}
(pbpctl_dev_b->bp_tpl_flag))
return BP_NOT_CAP;
}
- return (tx_status(pbpctl_dev));
+ return tx_status(pbpctl_dev);
}
int get_bp_force_link_fn(int dev_num)
return -1;
bpctl_dev_curr = &bpctl_dev_arr[dev_num];
- return (bp_force_link_status(bpctl_dev_curr));
+ return bp_force_link_status(bpctl_dev_curr);
}
static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev)
if (pbpctl_dev->bp_caps & TPL_CAP) {
if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX)
- return (tpl2_flag_status(pbpctl_dev));
+ return tpl2_flag_status(pbpctl_dev);
ret = pbpctl_dev->bp_tpl_flag;
}
return ret;
}
-//#ifdef PMC_FIX_FLAG
int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
- //bp_lock(pbp_device_block);
+ /* bp_lock(pbp_device_block); */
cmnd_on(pbpctl_dev);
if (!tap_mode)
bp_wait_at_pwup_dis(pbpctl_dev);
bp_wait_at_pwup_en(pbpctl_dev);
cmnd_off(pbpctl_dev);
- // bp_unlock(pbp_device_block);
+ /* bp_unlock(pbp_device_block); */
return BP_OK;
}
return BP_NOT_CAP;
if (!pbpctl_dev)
return -1;
- // bp_lock(pbp_device_block);
+ /* bp_lock(pbp_device_block); */
ret = bp_wait_at_pwup_status(pbpctl_dev);
- // bp_unlock(pbp_device_block);
+ /* bp_unlock(pbp_device_block); */
return ret;
}
return -1;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
- // bp_lock(pbp_device_block);
+ /* bp_lock(pbp_device_block); */
cmnd_on(pbpctl_dev);
if (!tap_mode)
else
bp_hw_reset_en(pbpctl_dev);
cmnd_off(pbpctl_dev);
- // bp_unlock(pbp_device_block);
+ /* bp_unlock(pbp_device_block); */
return BP_OK;
}
return BP_NOT_CAP;
if (!pbpctl_dev)
return -1;
- //bp_lock(pbp_device_block);
+ /* bp_lock(pbp_device_block); */
ret = bp_hw_reset_status(pbpctl_dev);
- //bp_unlock(pbp_device_block);
+ /* bp_unlock(pbp_device_block); */
return ret;
}
-//#endif /*PMC_FIX_FLAG*/
int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name,
char *add_param)
int get_dev_idx_bsf(int bus, int slot, int func)
{
int idx_dev = 0;
- //if_scan();
for (idx_dev = 0;
((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num));
idx_dev++) {
int idx_dev = 0;
struct net_device *dev;
int ifindex;
- //rcu_read_lock();
- //rtnl_lock();
- //rcu_read_lock();
+ /* rcu_read_lock(); */
+ /* rtnl_lock(); */
+ /* rcu_read_lock(); */
#if 1
#if (LINUX_VERSION_CODE >= 0x020618)
for_each_netdev(&init_net, dev)
{
struct ethtool_drvinfo drvinfo;
- // char *str=NULL;
char cbuf[32];
char *buf = NULL;
char res[10];
memcpy(&cbuf, drvinfo.bus_info, 32);
buf = &cbuf[0];
- // while(*buf++){
-
- /*if(*buf==':'){
- buf++;
- break;
- } */
- //}
while (*buf++ != ':') ;
for (i = 0; i < 10; i++, buf++) {
if (*buf == ':')
}
#endif
- //rtnl_unlock();
- //rcu_read_unlock();
+ /* rtnl_unlock(); */
+ /* rcu_read_unlock(); */
}
static bpctl_dev_t *pbpctl_dev;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
- //lock_kernel();
+ /* lock_kernel(); */
#endif
lock_bpctl();
- //local_irq_save(flags);
- /*if(!spin_trylock_irqsave(&bpvm_lock)){
+ /* local_irq_save(flags); */
+ /* if(!spin_trylock_irqsave(&bpvm_lock)){
local_irq_restore(flags);
- //unlock_bpctl();
- //unlock_kernel();
+ unlock_bpctl();
+ unlock_kernel();
return -1;
} */
- //spin_lock_irqsave(&bpvm_lock, flags);
+ /* spin_lock_irqsave(&bpvm_lock, flags); */
/*
* Switch according to the ioctl called
goto bp_exit;
}
- //lock_bpctl();
- //preempt_disable();
+ /* lock_bpctl(); */
+ /* preempt_disable(); */
local_irq_save(flags);
if (!spin_trylock(&bpvm_lock)) {
local_irq_restore(flags);
unlock_bpctl();
- //unlock_kernel();
return -1;
}
-// preempt_disable();
- //rcu_read_lock();
-// spin_lock_irqsave(&bpvm_lock, flags);
+
+/* preempt_disable();
+ rcu_read_lock();
+ spin_lock_irqsave(&bpvm_lock, flags);
+*/
if ((bpctl_cmd.in_param[5]) ||
(bpctl_cmd.in_param[6]) || (bpctl_cmd.in_param[7]))
dev_idx = get_dev_idx_bsf(bpctl_cmd.in_param[5],
dev_idx = get_dev_idx(bpctl_cmd.in_param[1]);
if (dev_idx < 0 || dev_idx > device_num) {
- //unlock_bpctl();
- //preempt_enable();
+ /* unlock_bpctl();
+ preempt_enable(); */
ret = -EOPNOTSUPP;
- //preempt_enable();
- //rcu_read_unlock();
+ /* preempt_enable();
+ rcu_read_unlock(); */
spin_unlock_irqrestore(&bpvm_lock, flags);
goto bp_exit;
}
bpctl_dev_arr[dev_idx].name);
bpctl_cmd.status = -1;
ret = SUCCESS;
- /*preempt_enable(); */
- //rcu_read_unlock();
+ /* preempt_enable(); */
+ /* rcu_read_unlock(); */
spin_unlock_irqrestore(&bpvm_lock, flags);
goto bp_exit;
bpctl_dev_arr[dev_idx].name);
bpctl_cmd.status = -1;
ret = SUCCESS;
- /*preempt_enable(); */
- //rcu_read_unlock();
+ /* preempt_enable(); */
+ /* rcu_read_unlock(); */
spin_unlock_irqrestore(&bpvm_lock, flags);
goto bp_exit;
}
case IOCTL_TX_MSG(GET_BYPASS_CAPS):
bpctl_cmd.status = get_bypass_caps_fn(pbpctl_dev);
/*preempt_enable(); */
- //rcu_read_unlock();
+ /*rcu_read_unlock();*/
spin_unlock_irqrestore(&bpvm_lock, flags);
if (copy_to_user
(argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) {
- //unlock_bpctl();
- //preempt_enable();
+ /*unlock_bpctl(); */
+ /*preempt_enable(); */
ret = -EFAULT;
goto bp_exit;
}
case IOCTL_TX_MSG(GET_TPL):
bpctl_cmd.status = get_tpl_fn(pbpctl_dev);
break;
-//#ifdef PMC_FIX_FLAG
case IOCTL_TX_MSG(SET_BP_WAIT_AT_PWUP):
bpctl_cmd.status =
set_bp_wait_at_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]);
case IOCTL_TX_MSG(GET_BP_HW_RESET):
bpctl_cmd.status = get_bp_hw_reset_fn(pbpctl_dev);
break;
-//#endif
#ifdef BP_SELF_TEST
case IOCTL_TX_MSG(SET_BP_SELF_TEST):
bpctl_cmd.status =
break;
default:
- // unlock_bpctl();
+ /* unlock_bpctl(); */
ret = -EOPNOTSUPP;
- /*preempt_enable(); */
- //rcu_read_unlock();
+ /* preempt_enable(); */
+ /* rcu_read_unlock();*/
spin_unlock_irqrestore(&bpvm_lock, flags);
goto bp_exit;
}
- //unlock_bpctl();
- /*preempt_enable(); */
+ /* unlock_bpctl(); */
+ /* preempt_enable(); */
bpcmd_exit:
- //rcu_read_unlock();
+ /* rcu_read_unlock(); */
spin_unlock_irqrestore(&bpvm_lock, flags);
if (copy_to_user(argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd)))
ret = -EFAULT;
ret = SUCCESS;
bp_exit:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
- //unlock_kernel();
+ /* unlock_kernel(); */
#endif
- //spin_unlock_irqrestore(&bpvm_lock, flags);
+ /* spin_unlock_irqrestore(&bpvm_lock, flags); */
unlock_bpctl();
- //unlock_kernel();
+ /* unlock_kernel(); */
return ret;
}
{BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID,
SILICOM_PE10G2BPTT_SSID, PE10G2BPTT, "PE10G2BPTT"},
- //{BROADCOM_VID, BROADCOM_PE10G2_PID, PCI_ANY_ID, PCI_ANY_ID, PE10G2BPTCX4, "PE10G2BPTCX4"},
+ /* {BROADCOM_VID, BROADCOM_PE10G2_PID, PCI_ANY_ID, PCI_ANY_ID, PE10G2BPTCX4, "PE10G2BPTCX4"}, */
{0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ ,
SILICOM_PEG4BPI6_SSID /*PCI_ANY_ID */ , PEG4BPI6, "PEG4BPI6"},
{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
SILICOM_PE210G2DBi9SR_SSID, PE210G2DBi9SR, "PE210G2DBi9SR"},
- //{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID*/, SILICOM_PE210G2DBi9SRRB_SSID , PE210G2DBi9SRRB, "PE210G2DBi9SRRB"},
{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
SILICOM_PE210G2DBi9LR_SSID, PE210G2DBi9LR, "PE210G2DBi9LR"},
- // {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID*/, SILICOM_PE210G2DBi9LRRB_SSID , PE210G2DBi9LRRB, "PE210G2DBi9LRRB"},
{0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ ,
SILICOM_PE310G4DBi940SR_SSID, PE310G4DBi940SR, "PE310G4DBi9SR"},
{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ ,
SILICOM_PE2G6BPi35_SSID /*PCI_ANY_ID */ , PE2G6BPi35, "PE2G6BPi35"},
- // {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID*/,0xaa0,PE2G6BPi35CX,"PE2G6BPi35CX"},
- // {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID*/,0xaa1,PE2G6BPi35CX,"PE2G6BPi35CX"},
- // {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID*/,0xaa2,PE2G6BPi35CX,"PE2G6BPi35CX"},
{0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa0, PE2G6BPi35CX,
"PE2G6BPi35CX"},
tx_ctl_pci_tbl[idx].subdevice;
bpctl_dev_arr[idx_dev].subvendor =
tx_ctl_pci_tbl[idx].subvendor;
- //bpctl_dev_arr[idx_dev].pdev=pdev1;
+ /* bpctl_dev_arr[idx_dev].pdev=pdev1; */
bpctl_dev_arr[idx_dev].func = PCI_FUNC(pdev1->devfn);
bpctl_dev_arr[idx_dev].slot = PCI_SLOT(pdev1->devfn);
bpctl_dev_arr[idx_dev].bus = pdev1->bus->number;
}
}
- //bpctl_dev_arr[idx_dev].bp_fw_ver=0xa8;
+ /* bpctl_dev_arr[idx_dev].bp_fw_ver=0xa8; */
printk("firmware version: 0x%x\n",
bpctl_dev_arr[idx_dev].
bp_fw_ver);
#ifdef BP_PROC_SUPPORT
{
int i = 0;
- //unsigned long flags;
- //rcu_read_lock();
+ /* unsigned long flags; */
+ /* rcu_read_lock(); */
bp_proc_create();
for (i = 0; i < device_num; i++) {
if (bpctl_dev_arr[i].ifindex) {
- //spin_lock_irqsave(&bpvm_lock, flags);
+ /* spin_lock_irqsave(&bpvm_lock, flags); */
bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]);
bypass_proc_create_dev_sd(&bpctl_dev_arr[i]);
- //spin_unlock_irqrestore(&bpvm_lock, flags);
+ /* spin_unlock_irqrestore(&bpvm_lock, flags); */
}
}
- //rcu_read_unlock();
+ /* rcu_read_unlock(); */
}
#endif
- //register_netdevice_notifier(&bp_notifier_block);
return 0;
}
#endif
for (i = 0; i < device_num; i++) {
- //unsigned long flags;
+ /* unsigned long flags; */
#ifdef BP_PROC_SUPPORT
-//spin_lock_irqsave(&bpvm_lock, flags);
-//rcu_read_lock();
+/* spin_lock_irqsave(&bpvm_lock, flags);
+ rcu_read_lock(); */
bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]);
-//spin_unlock_irqrestore(&bpvm_lock, flags);
-//rcu_read_unlock();
+/* spin_unlock_irqrestore(&bpvm_lock, flags);
+ rcu_read_unlock(); */
#endif
remove_bypass_wd_auto(&bpctl_dev_arr[i]);
bpctl_dev_arr[i].reset_time = 0;
int is_bypass_sd(int ifindex)
{
- return (is_bypass(get_dev_idx_p(ifindex)));
+ return is_bypass(get_dev_idx_p(ifindex));
}
int set_bypass_sd(int ifindex, int bypass_mode)
{
- return (set_bypass_fn(get_dev_idx_p(ifindex), bypass_mode));
+ return set_bypass_fn(get_dev_idx_p(ifindex), bypass_mode);
}
int get_bypass_sd(int ifindex)
{
- return (get_bypass_fn(get_dev_idx_p(ifindex)));
+ return get_bypass_fn(get_dev_idx_p(ifindex));
}
int get_bypass_change_sd(int ifindex)
{
- return (get_bypass_change_fn(get_dev_idx_p(ifindex)));
+ return get_bypass_change_fn(get_dev_idx_p(ifindex));
}
int set_dis_bypass_sd(int ifindex, int dis_param)
{
- return (set_dis_bypass_fn(get_dev_idx_p(ifindex), dis_param));
+ return set_dis_bypass_fn(get_dev_idx_p(ifindex), dis_param);
}
int get_dis_bypass_sd(int ifindex)
{
- return (get_dis_bypass_fn(get_dev_idx_p(ifindex)));
+ return get_dis_bypass_fn(get_dev_idx_p(ifindex));
}
int set_bypass_pwoff_sd(int ifindex, int bypass_mode)
{
- return (set_bypass_pwoff_fn(get_dev_idx_p(ifindex), bypass_mode));
+ return set_bypass_pwoff_fn(get_dev_idx_p(ifindex), bypass_mode);
}
int get_bypass_pwoff_sd(int ifindex)
{
- return (get_bypass_pwoff_fn(get_dev_idx_p(ifindex)));
+ return get_bypass_pwoff_fn(get_dev_idx_p(ifindex));
}
int set_bypass_pwup_sd(int ifindex, int bypass_mode)
{
- return (set_bypass_pwup_fn(get_dev_idx_p(ifindex), bypass_mode));
+ return set_bypass_pwup_fn(get_dev_idx_p(ifindex), bypass_mode);
}
int get_bypass_pwup_sd(int ifindex)
{
- return (get_bypass_pwup_fn(get_dev_idx_p(ifindex)));
+ return get_bypass_pwup_fn(get_dev_idx_p(ifindex));
}
int get_bypass_wd_sd(int ifindex, int *timeout)
{
- return (get_bypass_wd_fn(get_dev_idx_p(ifindex), timeout));
+ return get_bypass_wd_fn(get_dev_idx_p(ifindex), timeout);
}
int get_wd_expire_time_sd(int ifindex, int *time_left)
{
- return (get_wd_expire_time_fn(get_dev_idx_p(ifindex), time_left));
+ return get_wd_expire_time_fn(get_dev_idx_p(ifindex), time_left);
}
int reset_bypass_wd_timer_sd(int ifindex)
{
- return (reset_bypass_wd_timer_fn(get_dev_idx_p(ifindex)));
+ return reset_bypass_wd_timer_fn(get_dev_idx_p(ifindex));
}
int get_wd_set_caps_sd(int ifindex)
{
- return (get_wd_set_caps_fn(get_dev_idx_p(ifindex)));
+ return get_wd_set_caps_fn(get_dev_idx_p(ifindex));
}
int set_std_nic_sd(int ifindex, int nic_mode)
{
- return (set_std_nic_fn(get_dev_idx_p(ifindex), nic_mode));
+ return set_std_nic_fn(get_dev_idx_p(ifindex), nic_mode);
}
int get_std_nic_sd(int ifindex)
{
- return (get_std_nic_fn(get_dev_idx_p(ifindex)));
+ return get_std_nic_fn(get_dev_idx_p(ifindex));
}
int set_tap_sd(int ifindex, int tap_mode)
{
- return (set_tap_fn(get_dev_idx_p(ifindex), tap_mode));
+ return set_tap_fn(get_dev_idx_p(ifindex), tap_mode);
}
int get_tap_sd(int ifindex)
{
- return (get_tap_fn(get_dev_idx_p(ifindex)));
+ return get_tap_fn(get_dev_idx_p(ifindex));
}
int set_tap_pwup_sd(int ifindex, int tap_mode)
{
- return (set_tap_pwup_fn(get_dev_idx_p(ifindex), tap_mode));
+ return set_tap_pwup_fn(get_dev_idx_p(ifindex), tap_mode);
}
int get_tap_pwup_sd(int ifindex)
{
- return (get_tap_pwup_fn(get_dev_idx_p(ifindex)));
+ return get_tap_pwup_fn(get_dev_idx_p(ifindex));
}
int get_tap_change_sd(int ifindex)
{
- return (get_tap_change_fn(get_dev_idx_p(ifindex)));
+ return get_tap_change_fn(get_dev_idx_p(ifindex));
}
int set_dis_tap_sd(int ifindex, int dis_param)
{
- return (set_dis_tap_fn(get_dev_idx_p(ifindex), dis_param));
+ return set_dis_tap_fn(get_dev_idx_p(ifindex), dis_param);
}
int get_dis_tap_sd(int ifindex)
{
- return (get_dis_tap_fn(get_dev_idx_p(ifindex)));
+ return get_dis_tap_fn(get_dev_idx_p(ifindex));
}
int set_bp_disc_sd(int ifindex, int disc_mode)
{
- return (set_disc_fn(get_dev_idx_p(ifindex), disc_mode));
+ return set_disc_fn(get_dev_idx_p(ifindex), disc_mode);
}
int get_bp_disc_sd(int ifindex)
{
- return (get_disc_fn(get_dev_idx_p(ifindex)));
+ return get_disc_fn(get_dev_idx_p(ifindex));
}
int set_bp_disc_pwup_sd(int ifindex, int disc_mode)
{
- return (set_disc_pwup_fn(get_dev_idx_p(ifindex), disc_mode));
+ return set_disc_pwup_fn(get_dev_idx_p(ifindex), disc_mode);
}
int get_bp_disc_pwup_sd(int ifindex)
{
- return (get_disc_pwup_fn(get_dev_idx_p(ifindex)));
+ return get_disc_pwup_fn(get_dev_idx_p(ifindex));
}
int get_bp_disc_change_sd(int ifindex)
{
- return (get_disc_change_fn(get_dev_idx_p(ifindex)));
+ return get_disc_change_fn(get_dev_idx_p(ifindex));
}
int set_bp_dis_disc_sd(int ifindex, int dis_param)
{
- return (set_dis_disc_fn(get_dev_idx_p(ifindex), dis_param));
+ return set_dis_disc_fn(get_dev_idx_p(ifindex), dis_param);
}
int get_bp_dis_disc_sd(int ifindex)
{
- return (get_dis_disc_fn(get_dev_idx_p(ifindex)));
+ return get_dis_disc_fn(get_dev_idx_p(ifindex));
}
int get_wd_exp_mode_sd(int ifindex)
{
- return (get_wd_exp_mode_fn(get_dev_idx_p(ifindex)));
+ return get_wd_exp_mode_fn(get_dev_idx_p(ifindex));
}
int set_wd_exp_mode_sd(int ifindex, int param)
{
- return (set_wd_exp_mode_fn(get_dev_idx_p(ifindex), param));
+ return set_wd_exp_mode_fn(get_dev_idx_p(ifindex), param);
}
int reset_cont_sd(int ifindex)
{
- return (reset_cont_fn(get_dev_idx_p(ifindex)));
+ return reset_cont_fn(get_dev_idx_p(ifindex));
}
int set_tx_sd(int ifindex, int tx_state)
{
- return (set_tx_fn(get_dev_idx_p(ifindex), tx_state));
+ return set_tx_fn(get_dev_idx_p(ifindex), tx_state);
}
int set_tpl_sd(int ifindex, int tpl_state)
{
- return (set_tpl_fn(get_dev_idx_p(ifindex), tpl_state));
+ return set_tpl_fn(get_dev_idx_p(ifindex), tpl_state);
}
int set_bp_hw_reset_sd(int ifindex, int status)
{
- return (set_bp_hw_reset_fn(get_dev_idx_p(ifindex), status));
+ return set_bp_hw_reset_fn(get_dev_idx_p(ifindex), status);
}
int set_wd_autoreset_sd(int ifindex, int param)
{
- return (set_wd_autoreset_fn(get_dev_idx_p(ifindex), param));
+ return set_wd_autoreset_fn(get_dev_idx_p(ifindex), param);
}
int get_wd_autoreset_sd(int ifindex)
{
- return (get_wd_autoreset_fn(get_dev_idx_p(ifindex)));
+ return get_wd_autoreset_fn(get_dev_idx_p(ifindex));
}
int get_bypass_caps_sd(int ifindex)
{
- return (get_bypass_caps_fn(get_dev_idx_p(ifindex)));
+ return get_bypass_caps_fn(get_dev_idx_p(ifindex));
}
int get_bypass_slave_sd(int ifindex)
bpctl_dev_t *pbpctl_dev_out;
int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out);
if (ret == 1)
- return (pbpctl_dev_out->ifindex);
+ return pbpctl_dev_out->ifindex;
return -1;
}
int get_tx_sd(int ifindex)
{
- return (get_tx_fn(get_dev_idx_p(ifindex)));
+ return get_tx_fn(get_dev_idx_p(ifindex));
}
int get_tpl_sd(int ifindex)
{
- return (get_tpl_fn(get_dev_idx_p(ifindex)));
+ return get_tpl_fn(get_dev_idx_p(ifindex));
}
int get_bp_hw_reset_sd(int ifindex)
{
- return (get_bp_hw_reset_fn(get_dev_idx_p(ifindex)));
+ return get_bp_hw_reset_fn(get_dev_idx_p(ifindex));
}
int get_bypass_info_sd(int ifindex, struct bp_info *bp_info)
{
- return (get_bypass_info_fn
- (get_dev_idx_p(ifindex), bp_info->prod_name, &bp_info->fw_ver));
+ return get_bypass_info_fn(get_dev_idx_p(ifindex), bp_info->prod_name, &bp_info->fw_ver);
}
int bp_if_scan_sd(void)
#endif
if (pde == (struct proc_dir_entry *)0) {
- return (pde);
+ return pde;
}
}
- return (pde);
+ return pde;
}
int bp_proc_create(void)
printk(KERN_INFO "Enable Line Monitor\n");
if (ixjdebug & 0x0002)
- printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n");
+ printk(KERN_INFO "Set Line Monitor to Asynchronous Mode\n");
if (ixj_WriteDSPCommand(0x7E01, j)) /* Asynchronous Line Monitor */
return -1;
if (ixj_WriteDSPCommand(0x5151, j)) /* Enable DTMF detection */
return -1;
- if (ixj_WriteDSPCommand(0x6E01, j)) /* Set Asyncronous Tone Generation */
+ if (ixj_WriteDSPCommand(0x6E01, j)) /* Set Asynchronous Tone Generation */
return -1;
set_rec_depth(j, 2); /* Set Record Channel Limit to 2 frames */
dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
- if (dsp_wdt.fclk) {
+ if (!IS_ERR(dsp_wdt.fclk)) {
dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
- if (!dsp_wdt.iclk) {
+ if (IS_ERR(dsp_wdt.iclk)) {
clk_put(dsp_wdt.fclk);
dsp_wdt.fclk = NULL;
ret = -EFAULT;
}
/* 1. stop threads */
- if (ud->tcp_rx)
+ if (ud->tcp_rx) {
kthread_stop_put(ud->tcp_rx);
- if (ud->tcp_tx)
+ ud->tcp_rx = NULL;
+ }
+ if (ud->tcp_tx) {
kthread_stop_put(ud->tcp_tx);
+ ud->tcp_tx = NULL;
+ }
/*
* 2. close the socket
}
/* kill threads related to this sdev, if v.c. exists */
- if (vdev->ud.tcp_rx)
+ if (vdev->ud.tcp_rx) {
kthread_stop_put(vdev->ud.tcp_rx);
- if (vdev->ud.tcp_tx)
+ vdev->ud.tcp_rx = NULL;
+ }
+ if (vdev->ud.tcp_tx) {
kthread_stop_put(vdev->ud.tcp_tx);
-
+ vdev->ud.tcp_tx = NULL;
+ }
pr_info("stop threads\n");
/* active connection is closed */
#include "localpara.h"
/****************** CONSTANT AND MACRO SECTION ******************************/
-#define _INLINE __inline
#define MEDIA_STATE_DISCONNECTED 0
#define MEDIA_STATE_CONNECTED 1
/* OID_802_11_BSSID */
s8 sme_get_bssid(void *pcore_data, u8 *pbssid);
-s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Not use */
+s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Unused */
s8 sme_set_desired_bssid(void *pcore_data, u8 *pbssid);
/* OID_802_11_SSID */
s8 sme_get_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);
-s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Not use */
+s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Unused */
s8 sme_set_desired_ssid(void *pcore_data, u8 *pssid, u8 ssid_len);
/* OID_802_11_INFRASTRUCTURE_MODE */
s8 sme_get_bss_type(void *pcore_data, u8 *pbss_type);
-s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Not use */
+s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Unused */
s8 sme_set_desired_bss_type(void *pcore_data, u8 bss_type);
/* OID_802_11_FRAGMENTATION_THRESHOLD */
s8 sme_get_txrate_policy(void *pcore_data, u8 *policy);
s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin);
s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax);
-s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff);
+s8 sme_get_ms_radio_mode(void *pcore_data, u8 *pMsRadioOff);
s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff);
void sme_get_tx_power_level(void *pcore_data, u32 *TxPower);
int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
- struct net_device *dev = request->wdev->netdev;
+ struct net_device *dev;
struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
- wlandevice_t *wlandev = dev->ml_priv;
+ wlandevice_t *wlandev;
struct p80211msg_dot11req_scan msg1;
struct p80211msg_dot11req_scan_results msg2;
struct cfg80211_bss *bss;
if (!request)
return -EINVAL;
+ dev = request->wdev->netdev;
+ wlandev = dev->ml_priv;
+
if (priv->scan_request && priv->scan_request != request)
return -EBUSY;