// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * Ben Dooks <[email protected]> * http://armlinux.simtec.co.uk/ * * S3C USB2.0 High-speed / OtG driver */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/mutex.h> #include <linux/seq_file.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/phy.h> #include <linux/usb/composite.h> #include "core.h" #include "hw.h" /* conversion functions */ static inline struct dwc2_hsotg_req *our_req(struct usb_request *req) { … } static inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) { … } static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) { … } static inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) { … } static inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) { … } static inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, u32 ep_index, u32 dir_in) { … } /* forward declaration of functions */ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); /** * using_dma - return the DMA status of the driver. * @hsotg: The driver state. * * Return true if we're using DMA. * * Currently, we have the DMA support code worked into everywhere * that needs it, but the AMBA DMA implementation in the hardware can * only DMA from 32bit aligned addresses. This means that gadgets such * as the CDC Ethernet cannot work as they often pass packets which are * not 32bit aligned. * * Unfortunately the choice to use DMA or not is global to the controller * and seems to be only settable when the controller is being put through * a core reset. This means we either need to fix the gadgets to take * account of DMA alignment, or add bounce buffers (yuerk). * * g_using_dma is set depending on dts flag. */ static inline bool using_dma(struct dwc2_hsotg *hsotg) { … } /* * using_desc_dma - return the descriptor DMA status of the driver. * @hsotg: The driver state. * * Return true if we're using descriptor DMA. */ static inline bool using_desc_dma(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_incr_frame_num - Increments the targeted frame number. * @hs_ep: The endpoint * * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. * If an overrun occurs it will wrap the value and set the frame_overrun flag. */ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number * by one. * @hs_ep: The endpoint. * * This function used in service interval based scheduling flow to calculate * descriptor frame number filed value. For service interval mode frame * number in descriptor should point to last (u)frame in the interval. * */ static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_en_gsint - enable one or more of the general interrupt * @hsotg: The device state * @ints: A bitmask of the interrupts to enable */ static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) { … } /** * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt * @hsotg: The device state * @ints: A bitmask of the interrupts to enable */ static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) { … } /** * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq * @hsotg: The device state * @ep: The endpoint index * @dir_in: True if direction is in. * @en: The enable value, true to enable * * Set or clear the mask for an individual endpoint's interrupt * request. */ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, unsigned int ep, unsigned int dir_in, unsigned int en) { … } /** * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode * * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for * device mode TX FIFOs * * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt * * @hsotg: Programming view of the DWC_otg controller * */ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode * TX FIFOs * * @hsotg: Programming view of the DWC_otg controller */ int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs * @hsotg: The device instance. */ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure * @ep: USB endpoint to allocate request for. * @flags: Allocation flags * * Allocate a new USB request structure appropriate for the specified endpoint */ static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags) { … } /** * is_ep_periodic - return true if the endpoint is in periodic mode. * @hs_ep: The endpoint to query. * * Returns true if the endpoint is in periodic mode, meaning it is being * used for an Interrupt or ISO transfer. */ static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request * @hsotg: The device state. * @hs_ep: The endpoint for the request * @hs_req: The request being processed. * * This is the reverse of dwc2_hsotg_map_dma(), called for the completion * of a request to ensure the buffer is ready for access by the caller. */ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { … } /* * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains * for Control endpoint * @hsotg: The device state. * * This function will allocate 4 descriptor chains for EP 0: 2 for * Setup stage, per one for IN and OUT data/status transactions. */ static int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO * @hsotg: The controller state. * @hs_ep: The endpoint we're going to write for. * @hs_req: The request to write data for. * * This is called when the TxFIFO has some space in it to hold a new * transmission and we have something to give it. The actual setup of * the data size is done elsewhere, so all we have to do is to actually * write the data. * * The return value is zero if there is more space (or nothing was done) * otherwise -ENOSPC is returned if the FIFO space was used up. * * This routine is only needed for PIO */ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { … } /** * get_ep_limit - get the maximum data legnth for this endpoint * @hs_ep: The endpoint * * Return the maximum data that can be queued in one go on a given endpoint * so that transfers that are too long can be split. */ static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_read_frameno - read current frame number * @hsotg: The device instance * * Return the current frame number */ static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_get_chain_limit - get the maximum data payload value of the * DMA descriptor chain prepared for specific endpoint * @hs_ep: The endpoint * * Return the maximum data that can be queued in one go on a given endpoint * depending on its descriptor chain capacity so that transfers that * are too long can be split. */ static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) { … } /* * dwc2_gadget_get_desc_params - get DMA descriptor parameters. * @hs_ep: The endpoint * @mask: RX/TX bytes mask to be defined * * Returns maximum data payload for one descriptor after analyzing endpoint * characteristics. * DMA descriptor transfer bytes limit depends on EP type: * Control out - MPS, * Isochronous - descriptor rx/tx bytes bitfield limit, * Control In/Bulk/Interrupt - multiple of mps. This will allow to not * have concatenations from various descriptors within one packet. * Interrupt OUT - if mps not multiple of 4 then a single packet corresponds * to a single descriptor. * * Selects corresponding mask for RX/TX bytes as well. */ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) { … } static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, struct dwc2_dma_desc **desc, dma_addr_t dma_buff, unsigned int len, bool true_last) { … } /* * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. * @hs_ep: The endpoint * @ureq: Request to transfer * @offset: offset in bytes * @len: Length of the transfer * * This function will iterate over descriptor chain and fill its entries * with corresponding information based on transfer data. */ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, dma_addr_t dma_buff, unsigned int len) { … } /* * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. * @hs_ep: The isochronous endpoint. * @dma_buff: usb requests dma buffer. * @len: usb request transfer length. * * Fills next free descriptor with the data of the arrived usb request, * frame info, sets Last and IOC bits increments next_desc. If filled * descriptor is not the first one, removes L bit from the previous descriptor * status. */ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, dma_addr_t dma_buff, unsigned int len) { … } /* * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA * @hs_ep: The isochronous endpoint. * * Prepare descriptor chain for isochronous endpoints. Afterwards * write DMA address to HW and enable the endpoint. */ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) { … } static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep); static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, int result); /** * dwc2_hsotg_start_req - start a USB request from an endpoint's queue * @hsotg: The controller state. * @hs_ep: The endpoint to process a request for * @hs_req: The request to start. * @continuing: True if we are doing more for the current request. * * Start the given request running by setting the endpoint registers * appropriately, and writing any data to the FIFOs. */ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, bool continuing) { … } /** * dwc2_hsotg_map_dma - map the DMA memory being used for the request * @hsotg: The device state. * @hs_ep: The endpoint the request is on. * @req: The request being processed. * * We've been asked to queue a request, so ensure that the memory buffer * is correctly setup for DMA. If we've been passed an extant DMA address * then ensure the buffer has been synced to memory. If our buffer has no * DMA memory, then we map the memory and mark our request to allow us to * cleanup on completion. */ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct usb_request *req) { … } static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { … } static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { … } /** * dwc2_gadget_target_frame_elapsed - Checks target frame * @hs_ep: The driver endpoint to check * * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop * corresponding transfer. */ static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) { … } /* * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers * @hsotg: The driver state * @hs_ep: the ep descriptor chain is for * * Called to update EP0 structure's pointers depend on stage of * control transfer. */ static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep) { … } static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { … } static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { … } static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, struct usb_request *req) { … } /** * dwc2_hsotg_complete_oursetup - setup completion callback * @ep: The endpoint the request was on. * @req: The request completed. * * Called on completion of any requests the driver itself * submitted that need cleaning up. */ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, struct usb_request *req) { … } /** * ep_from_windex - convert control wIndex value to endpoint * @hsotg: The driver state. * @windex: The control request wIndex field (in host order). * * Convert the given wIndex into a pointer to an driver endpoint * structure, or return NULL if it is not a valid endpoint. */ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, u32 windex) { … } /** * dwc2_hsotg_set_test_mode - Enable usb Test Modes * @hsotg: The driver state. * @testmode: requested usb test mode * Enable usb Test Mode requested by the Host. */ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) { … } /** * dwc2_hsotg_send_reply - send reply to control request * @hsotg: The device state * @ep: Endpoint 0 * @buff: Buffer for request * @length: Length of reply. * * Create a request and queue it on the given endpoint. This is useful as * an internal method of sending replies to certain control requests, etc. */ static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *ep, void *buff, int length) { … } /** * dwc2_hsotg_process_req_status - process request GET_STATUS * @hsotg: The device state * @ctrl: USB control request */ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { … } static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); /** * get_ep_head - return the first request on the endpoint * @hs_ep: The controller endpoint to get * * Get the first request on the endpoint. */ static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_gadget_start_next_request - Starts next request from ep queue * @hs_ep: Endpoint structure * * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked * in its handler. Hence we need to unmask it here to be able to do * resynchronization. */ static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE * @hsotg: The device state * @ctrl: USB control request */ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { … } static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); /** * dwc2_hsotg_stall_ep0 - stall ep0 * @hsotg: The device state * * Set stall for ep0 as response for setup request. */ static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_process_control - process a control request * @hsotg: The device state * @ctrl: The control request received * * The controller has received the SETUP phase of a control request, and * needs to work out what to do next (and whether to pass it on to the * gadget driver). */ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, struct usb_ctrlrequest *ctrl) { … } /** * dwc2_hsotg_complete_setup - completion of a setup transfer * @ep: The endpoint the request was on. * @req: The request completed. * * Called on completion of any requests the driver itself submitted for * EP0 setup packets */ static void dwc2_hsotg_complete_setup(struct usb_ep *ep, struct usb_request *req) { … } /** * dwc2_hsotg_enqueue_setup - start a request for EP0 packets * @hsotg: The device state. * * Enqueue a request on EP0 if necessary to received any SETUP packets * received from the host. */ static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) { … } static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_complete_request - complete a request given to us * @hsotg: The device state. * @hs_ep: The endpoint the request was on. * @hs_req: The request to complete. * @result: The result code (0 => Ok, otherwise errno) * * The given request has finished, so call the necessary completion * if it has one and then look to see if we can start a new request * on the endpoint. * * Note, expects the ep to already be locked as appropriate. */ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, int result) { … } /* * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA * @hs_ep: The endpoint the request was on. * * Get first request from the ep queue, determine descriptor on which complete * happened. SW discovers which descriptor currently in use by HW, adjusts * dma_address and calculates index of completed descriptor based on the value * of DEPDMA register. Update actual length of request, giveback to gadget. */ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) { … } /* * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. * @hs_ep: The isochronous endpoint. * * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA * interrupt. Reset target frame and next_desc to allow to start * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS * interrupt for OUT direction. */ static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint * @hsotg: The device state. * @ep_idx: The endpoint index for the data * @size: The size of data in the fifo, in bytes * * The FIFO status shows there is data to read from the FIFO for a given * endpoint, so sort out whether we need to read the data into a request * that has been made for that endpoint. */ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) { … } /** * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint * @hsotg: The device instance * @dir_in: If IN zlp * * Generate a zero-length IN packet request for terminating a SETUP * transaction. * * Note, since we don't write any data to the TxFIFO, then it is * currently believed that we do not need to wait for any space in * the TxFIFO. */ static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) { … } /* * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc * @hs_ep - The endpoint on which transfer went * * Iterate over endpoints descriptor chain and get info on bytes remained * in DMA descriptors after transfer has completed. Used for non isoc EPs. */ static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO * @hsotg: The device instance * @epnum: The endpoint received from * * The RXFIFO has delivered an OutDone event, which means that the data * transfer for an OUT endpoint has been completed, either by a short * packet or by the finish of a transfer. */ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) { … } /** * dwc2_hsotg_handle_rx - RX FIFO has data * @hsotg: The device instance * * The IRQ handler has detected that the RX FIFO has some data in it * that requires processing, so find out what is in there and do the * appropriate read. * * The RXFIFO is a true FIFO, the packets coming out are still in packet * chunks, so if you have x packets received on an endpoint you'll get x * FIFO events delivered, each with a packet's worth of data in it. * * When using DMA, we should not be processing events from the RXFIFO * as the actual data should be sent to the memory directly and we turn * on the completion interrupts to get notifications of transfer completion. */ static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_ep0_mps - turn max packet size into register setting * @mps: The maximum packet size in bytes. */ static u32 dwc2_hsotg_ep0_mps(unsigned int mps) { … } /** * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field * @hsotg: The driver state. * @ep: The index number of the endpoint * @mps: The maximum packet size in bytes * @mc: The multicount value * @dir_in: True if direction is in. * * Configure the maximum packet size for the given endpoint, updating * the hardware control registers to reflect this. */ static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, unsigned int ep, unsigned int mps, unsigned int mc, unsigned int dir_in) { … } /** * dwc2_hsotg_txfifo_flush - flush Tx FIFO * @hsotg: The driver state * @idx: The index for the endpoint (0..15) */ static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) { … } /** * dwc2_hsotg_trytx - check to see if anything needs transmitting * @hsotg: The driver state * @hs_ep: The driver endpoint to check. * * Check to see if there is a request that has data to send, and if so * make an attempt to write data into the FIFO. */ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_complete_in - complete IN transfer * @hsotg: The device state. * @hs_ep: The endpoint that has just completed. * * An IN transfer has been completed, update the transfer's state and then * call the relevant completion routines. */ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep * @hsotg: The device state. * @idx: Index of ep. * @dir_in: Endpoint direction 1-in 0-out. * * Reads for endpoint with given index and direction, by masking * epint_reg with coresponding mask. */ static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, unsigned int idx, int dir_in) { … } /** * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD * @hs_ep: The endpoint on which interrupt is asserted. * * This interrupt indicates that the endpoint has been disabled per the * application's request. * * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, * in case of ISOC completes current request. * * For ISOC-OUT endpoints completes expired requests. If there is remaining * request starts it. */ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS * @ep: The endpoint on which interrupt is asserted. * * This is starting point for ISOC-OUT transfer, synchronization done with * first out token received from host while corresponding EP is disabled. * * Device does not know initial frame in which out token will come. For this * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon * getting this interrupt SW starts calculation for next transfer frame. */ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) { … } static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep); /** * dwc2_gadget_handle_nak - handle NAK interrupt * @hs_ep: The endpoint on which interrupt is asserted. * * This is starting point for ISOC-IN transfer, synchronization done with * first IN token received from host while corresponding EP is disabled. * * Device does not know when first one token will arrive from host. On first * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was * sent in response to that as there was no data in FIFO. SW is basing on this * interrupt to obtain frame in which token has come and then based on the * interval calculates next frame for transfer. */ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_epint - handle an in/out endpoint interrupt * @hsotg: The driver state * @idx: The index for the endpoint (0..15) * @dir_in: Set if this is an IN endpoint * * Process and clear any interrupt pending for an individual endpoint */ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, int dir_in) { … } /** * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) * @hsotg: The device state. * * Handle updating the device settings after the enumeration phase has * been completed. */ static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) { … } /** * kill_all_requests - remove all requests from the endpoint's queue * @hsotg: The device state. * @ep: The endpoint the requests may be on. * @result: The result code to use. * * Go through the requests on the given endpoint and mark them * completed with the given result code. */ static void kill_all_requests(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *ep, int result) { … } /** * dwc2_hsotg_disconnect - disconnect service * @hsotg: The device state. * * The device has been disconnected. Remove all current * transactions and signal the gadget driver that this * has happened. */ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler * @hsotg: The device state: * @periodic: True if this is a periodic FIFO interrupt */ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) { … } /* IRQ flags which will trigger a retry around the IRQ loop */ #define IRQ_RETRY_MASK … static int dwc2_hsotg_ep_disable(struct usb_ep *ep); /** * dwc2_hsotg_core_init_disconnected - issue softreset to the core * @hsotg: The device state * @is_usb_reset: Usb resetting flag * * Issue a soft reset to the core, and await the core finishing it. */ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, bool is_usb_reset) { … } void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) { … } void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. * @hsotg: The device state: * * This interrupt indicates one of the following conditions occurred while * transmitting an ISOC transaction. * - Corrupted IN Token for ISOC EP. * - Packet not complete in FIFO. * * The following actions will be taken: * - Determine the EP * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO */ static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt * @hsotg: The device state: * * This interrupt indicates one of the following conditions occurred while * transmitting an ISOC transaction. * - Corrupted OUT Token for ISOC EP. * - Packet not complete in FIFO. * * The following actions will be taken: * - Determine the EP * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. */ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_irq - handle device interrupt * @irq: The IRQ number triggered * @pw: The pw value when registered the handler. */ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) { … } static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep) { … } /** * dwc2_hsotg_ep_enable - enable the given endpoint * @ep: The USB endpint to configure * @desc: The USB endpoint descriptor to configure with. * * This is called from the USB gadget code's usb_ep_enable(). */ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { … } /** * dwc2_hsotg_ep_disable - disable given endpoint * @ep: The endpoint to disable. */ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) { … } static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) { … } /** * on_list - check request is on the given endpoint * @ep: The endpoint to check. * @test: The request to test if it is on the endpoint. */ static bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) { … } /** * dwc2_hsotg_ep_dequeue - dequeue given endpoint * @ep: The endpoint to dequeue. * @req: The request to be removed from a queue. */ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { … } /** * dwc2_gadget_ep_set_wedge - set wedge on a given endpoint * @ep: The endpoint to be wedged. * */ static int dwc2_gadget_ep_set_wedge(struct usb_ep *ep) { … } /** * dwc2_hsotg_ep_sethalt - set halt on a given endpoint * @ep: The endpoint to set halt. * @value: Set or unset the halt. * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if * the endpoint is busy processing requests. * * We need to stall the endpoint immediately if request comes from set_feature * protocol command handler. */ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) { … } /** * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held * @ep: The endpoint to set halt. * @value: Set or unset the halt. */ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) { … } static const struct usb_ep_ops dwc2_hsotg_ep_ops = …; /** * dwc2_hsotg_init - initialize the usb core * @hsotg: The driver state */ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_udc_start - prepare the udc for work * @gadget: The usb gadget state * @driver: The usb gadget driver * * Perform initialization to prepare udc device and driver * to work. */ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { … } /** * dwc2_hsotg_udc_stop - stop the udc * @gadget: The usb gadget state * * Stop udc hw block and stay tunned for future transmissions */ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) { … } /** * dwc2_hsotg_gadget_getframe - read the frame number * @gadget: The usb gadget state * * Read the {micro} frame number */ static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) { … } /** * dwc2_hsotg_set_selfpowered - set if device is self/bus powered * @gadget: The usb gadget state * @is_selfpowered: Whether the device is self-powered * * Set if the device is self or bus powered. */ static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) { … } /** * dwc2_hsotg_pullup - connect/disconnect the USB PHY * @gadget: The usb gadget state * @is_on: Current state of the USB PHY * * Connect/Disconnect the USB PHY pullup */ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) { … } static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) { … } /** * dwc2_hsotg_vbus_draw - report bMaxPower field * @gadget: The usb gadget state * @mA: Amount of current * * Report how much power the device may consume to the phy. */ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) { … } static void dwc2_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) { … } static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = …; /** * dwc2_hsotg_initep - initialise a single endpoint * @hsotg: The device state. * @hs_ep: The endpoint to be initialised. * @epnum: The endpoint number * @dir_in: True if direction is in. * * Initialise the given endpoint (as part of the probe and device state * creation) to give to the gadget driver. Setup the endpoint name, any * direction information and other state that may be required. */ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_ep *hs_ep, int epnum, bool dir_in) { … } /** * dwc2_hsotg_hw_cfg - read HW configuration registers * @hsotg: Programming view of the DWC_otg controller * * Read the USB core HW configuration registers */ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_dump - dump state of the udc * @hsotg: Programming view of the DWC_otg controller * */ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_init - init function for gadget * @hsotg: Programming view of the DWC_otg controller * */ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) { … } /** * dwc2_hsotg_remove - remove function for hsotg driver * @hsotg: Programming view of the DWC_otg controller * */ int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) { … } int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) { … } int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) { … } /** * dwc2_backup_device_registers() - Backup controller device registers. * When suspending usb bus, registers needs to be backuped * if controller power is disabled once suspended. * * @hsotg: Programming view of the DWC_otg controller */ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) { … } /** * dwc2_restore_device_registers() - Restore controller device registers. * When resuming usb bus, device registers needs to be restored * if controller power were disabled. * * @hsotg: Programming view of the DWC_otg controller * @remote_wakeup: Indicates whether resume is initiated by Device or Host. * * Return: 0 if successful, negative error code otherwise */ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) { … } /** * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode * * @hsotg: Programming view of DWC_otg controller * */ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode * * @hsotg: Programming view of DWC_otg controller * */ void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. * * @hsotg: Programming view of the DWC_otg controller * * Return non-zero if failed to enter to hibernation. */ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) { … } /** * dwc2_gadget_exit_hibernation() * This function is for exiting from Device mode hibernation by host initiated * resume/reset and device initiated remote-wakeup. * * @hsotg: Programming view of the DWC_otg controller * @rem_wakeup: indicates whether resume is initiated by Device or Host. * @reset: indicates whether resume is initiated by Reset. * * Return non-zero if failed to exit from hibernation. */ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, int reset) { … } /** * dwc2_gadget_enter_partial_power_down() - Put controller in partial * power down. * * @hsotg: Programming view of the DWC_otg controller * * Return: non-zero if failed to enter device partial power down. * * This function is for entering device mode partial power down. */ int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) { … } /* * dwc2_gadget_exit_partial_power_down() - Exit controller from device partial * power down. * * @hsotg: Programming view of the DWC_otg controller * @restore: indicates whether need to restore the registers or not. * * Return: non-zero if failed to exit device partial power down. * * This function is for exiting from device mode partial power down. */ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) { … } /** * dwc2_gadget_enter_clock_gating() - Put controller in clock gating. * * @hsotg: Programming view of the DWC_otg controller * * Return: non-zero if failed to enter device partial power down. * * This function is for entering device mode clock gating. */ void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) { … } /* * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating. * * @hsotg: Programming view of the DWC_otg controller * @rem_wakeup: indicates whether remote wake up is enabled. * * This function is for exiting from device mode clock gating. */ void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) { … }