linux/drivers/usb/chipidea/udc.c

// SPDX-License-Identifier: GPL-2.0
/*
 * udc.c - ChipIdea UDC driver
 *
 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
 *
 * Author: David Lopo
 */

#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg-fsm.h>
#include <linux/usb/chipidea.h>

#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "otg.h"
#include "otg_fsm.h"
#include "trace.h"

/* control endpoint description */
static const struct usb_endpoint_descriptor
ctrl_endpt_out_desc =;

static const struct usb_endpoint_descriptor
ctrl_endpt_in_desc =;

static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
		       struct td_node *node);
/**
 * hw_ep_bit: calculates the bit number
 * @num: endpoint number
 * @dir: endpoint direction
 *
 * This function returns bit number
 */
static inline int hw_ep_bit(int num, int dir)
{}

static inline int ep_to_bit(struct ci_hdrc *ci, int n)
{}

/**
 * hw_device_state: enables/disables interrupts (execute without interruption)
 * @ci: the controller
 * @dma: 0 => disable, !0 => enable and set dma engine
 *
 * This function returns an error code
 */
static int hw_device_state(struct ci_hdrc *ci, u32 dma)
{}

/**
 * hw_ep_flush: flush endpoint fifo (execute without interruption)
 * @ci: the controller
 * @num: endpoint number
 * @dir: endpoint direction
 *
 * This function returns an error code
 */
static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
{}

/**
 * hw_ep_disable: disables endpoint (execute without interruption)
 * @ci: the controller
 * @num: endpoint number
 * @dir: endpoint direction
 *
 * This function returns an error code
 */
static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir)
{}

/**
 * hw_ep_enable: enables endpoint (execute without interruption)
 * @ci: the controller
 * @num:  endpoint number
 * @dir:  endpoint direction
 * @type: endpoint type
 *
 * This function returns an error code
 */
static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type)
{}

/**
 * hw_ep_get_halt: return endpoint halt status
 * @ci: the controller
 * @num: endpoint number
 * @dir: endpoint direction
 *
 * This function returns 1 if endpoint halted
 */
static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)
{}

/**
 * hw_ep_prime: primes endpoint (execute without interruption)
 * @ci: the controller
 * @num:     endpoint number
 * @dir:     endpoint direction
 * @is_ctrl: true if control endpoint
 *
 * This function returns an error code
 */
static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
{}

/**
 * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
 *                 without interruption)
 * @ci: the controller
 * @num:   endpoint number
 * @dir:   endpoint direction
 * @value: true => stall, false => unstall
 *
 * This function returns an error code
 */
static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
{}

/**
 * hw_port_is_high_speed: test if port is high speed
 * @ci: the controller
 *
 * This function returns true if high speed port
 */
static int hw_port_is_high_speed(struct ci_hdrc *ci)
{}

/**
 * hw_test_and_clear_complete: test & clear complete status (execute without
 *                             interruption)
 * @ci: the controller
 * @n: endpoint number
 *
 * This function returns complete status
 */
static int hw_test_and_clear_complete(struct ci_hdrc *ci, int n)
{}

/**
 * hw_test_and_clear_intr_active: test & clear active interrupts (execute
 *                                without interruption)
 * @ci: the controller
 *
 * This function returns active interrutps
 */
static u32 hw_test_and_clear_intr_active(struct ci_hdrc *ci)
{}

/**
 * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
 *                                interruption)
 * @ci: the controller
 *
 * This function returns guard value
 */
static int hw_test_and_clear_setup_guard(struct ci_hdrc *ci)
{}

/**
 * hw_test_and_set_setup_guard: test & set setup guard (execute without
 *                              interruption)
 * @ci: the controller
 *
 * This function returns guard value
 */
static int hw_test_and_set_setup_guard(struct ci_hdrc *ci)
{}

/**
 * hw_usb_set_address: configures USB address (execute without interruption)
 * @ci: the controller
 * @value: new USB address
 *
 * This function explicitly sets the address, without the "USBADRA" (advance)
 * feature, which is not supported by older versions of the controller.
 */
static void hw_usb_set_address(struct ci_hdrc *ci, u8 value)
{}

/**
 * hw_usb_reset: restart device after a bus reset (execute without
 *               interruption)
 * @ci: the controller
 *
 * This function returns an error code
 */
static int hw_usb_reset(struct ci_hdrc *ci)
{}

/******************************************************************************
 * UTIL block
 *****************************************************************************/

static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
			unsigned int length, struct scatterlist *s)
{}

/**
 * _usb_addr: calculates endpoint address from direction & number
 * @ep:  endpoint
 */
static inline u8 _usb_addr(struct ci_hw_ep *ep)
{}

static int prepare_td_for_non_sg(struct ci_hw_ep *hwep,
		struct ci_hw_req *hwreq)
{}

static int prepare_td_per_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
		struct scatterlist *s)
{}

static void ci_add_buffer_entry(struct td_node *node, struct scatterlist *s)
{}

static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{}

/**
 * _hardware_enqueue: configures a request at hardware level
 * @hwep:   endpoint
 * @hwreq:  request
 *
 * This function returns an error code
 */
static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{}

/**
 * free_pending_td: remove a pending request for the endpoint
 * @hwep: endpoint
 */
static void free_pending_td(struct ci_hw_ep *hwep)
{}

static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
					   struct td_node *node)
{}

/**
 * _hardware_dequeue: handles a request at hardware level
 * @hwep: endpoint
 * @hwreq:  request
 *
 * This function returns an error code
 */
static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
{}

/**
 * _ep_nuke: dequeues all endpoint requests
 * @hwep: endpoint
 *
 * This function returns an error code
 * Caller must hold lock
 */
static int _ep_nuke(struct ci_hw_ep *hwep)
__releases(hwep->lock)
__acquires(hwep->lock)
{}

static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer)
{}


/**
 * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
 * @gadget: gadget
 *
 * This function returns an error code
 */
static int _gadget_stop_activity(struct usb_gadget *gadget)
{}

/******************************************************************************
 * ISR block
 *****************************************************************************/
/**
 * isr_reset_handler: USB reset interrupt handler
 * @ci: UDC device
 *
 * This function resets USB engine after a bus reset occurred
 */
static void isr_reset_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{}

/**
 * isr_get_status_complete: get_status request complete function
 * @ep:  endpoint
 * @req: request handled
 *
 * Caller must release lock
 */
static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
{}

/**
 * _ep_queue: queues (submits) an I/O request to an endpoint
 * @ep:        endpoint
 * @req:       request
 * @gfp_flags: GFP flags (not used)
 *
 * Caller must hold lock
 * This function returns an error code
 */
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
		    gfp_t __maybe_unused gfp_flags)
{}

/**
 * isr_get_status_response: get_status request response
 * @ci: ci struct
 * @setup: setup request packet
 *
 * This function returns an error code
 */
static int isr_get_status_response(struct ci_hdrc *ci,
				   struct usb_ctrlrequest *setup)
__releases(hwep->lock)
__acquires(hwep->lock)
{}

/**
 * isr_setup_status_complete: setup_status request complete function
 * @ep:  endpoint
 * @req: request handled
 *
 * Caller must release lock. Put the port in test mode if test mode
 * feature is selected.
 */
static void
isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
{}

/**
 * isr_setup_status_phase: queues the status phase of a setup transation
 * @ci: ci struct
 *
 * This function returns an error code
 */
static int isr_setup_status_phase(struct ci_hdrc *ci)
{}

/**
 * isr_tr_complete_low: transaction complete low level handler
 * @hwep: endpoint
 *
 * This function returns an error code
 * Caller must hold lock
 */
static int isr_tr_complete_low(struct ci_hw_ep *hwep)
__releases(hwep->lock)
__acquires(hwep->lock)
{}

static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
{}

/**
 * isr_setup_packet_handler: setup packet handler
 * @ci: UDC descriptor
 *
 * This function handles setup packet 
 */
static void isr_setup_packet_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{}

/**
 * isr_tr_complete_handler: transaction complete interrupt handler
 * @ci: UDC descriptor
 *
 * This function handles traffic events
 */
static void isr_tr_complete_handler(struct ci_hdrc *ci)
__releases(ci->lock)
__acquires(ci->lock)
{}

/******************************************************************************
 * ENDPT block
 *****************************************************************************/
/*
 * ep_enable: configure endpoint, making it usable
 *
 * Check usb_ep_enable() at "usb_gadget.h" for details
 */
static int ep_enable(struct usb_ep *ep,
		     const struct usb_endpoint_descriptor *desc)
{}

/*
 * ep_disable: endpoint is no longer usable
 *
 * Check usb_ep_disable() at "usb_gadget.h" for details
 */
static int ep_disable(struct usb_ep *ep)
{}

/*
 * ep_alloc_request: allocate a request object to use with this endpoint
 *
 * Check usb_ep_alloc_request() at "usb_gadget.h" for details
 */
static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{}

/*
 * ep_free_request: frees a request object
 *
 * Check usb_ep_free_request() at "usb_gadget.h" for details
 */
static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
{}

/*
 * ep_queue: queues (submits) an I/O request to an endpoint
 *
 * Check usb_ep_queue()* at usb_gadget.h" for details
 */
static int ep_queue(struct usb_ep *ep, struct usb_request *req,
		    gfp_t __maybe_unused gfp_flags)
{}

/*
 * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
 *
 * Check usb_ep_dequeue() at "usb_gadget.h" for details
 */
static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{}

/*
 * ep_set_halt: sets the endpoint halt feature
 *
 * Check usb_ep_set_halt() at "usb_gadget.h" for details
 */
static int ep_set_halt(struct usb_ep *ep, int value)
{}

/*
 * ep_set_wedge: sets the halt feature and ignores clear requests
 *
 * Check usb_ep_set_wedge() at "usb_gadget.h" for details
 */
static int ep_set_wedge(struct usb_ep *ep)
{}

/*
 * ep_fifo_flush: flushes contents of a fifo
 *
 * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
 */
static void ep_fifo_flush(struct usb_ep *ep)
{}

/*
 * Endpoint-specific part of the API to the USB controller hardware
 * Check "usb_gadget.h" for details
 */
static const struct usb_ep_ops usb_ep_ops =;

/******************************************************************************
 * GADGET block
 *****************************************************************************/

static int ci_udc_get_frame(struct usb_gadget *_gadget)
{}

/*
 * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded
 */
static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
{}

static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{}

static int ci_udc_wakeup(struct usb_gadget *_gadget)
{}

static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{}

static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
{}

/* Change Data+ pullup status
 * this func is used by usb_gadget_connect/disconnect
 */
static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
{}

static int ci_udc_start(struct usb_gadget *gadget,
			 struct usb_gadget_driver *driver);
static int ci_udc_stop(struct usb_gadget *gadget);

/* Match ISOC IN from the highest endpoint */
static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
			      struct usb_endpoint_descriptor *desc,
			      struct usb_ss_ep_comp_descriptor *comp_desc)
{}

/*
 * Device operations part of the API to the USB controller hardware,
 * which don't involve endpoints (or i/o)
 * Check  "usb_gadget.h" for details
 */
static const struct usb_gadget_ops usb_gadget_ops =;

static int init_eps(struct ci_hdrc *ci)
{}

static void destroy_eps(struct ci_hdrc *ci)
{}

/**
 * ci_udc_start: register a gadget driver
 * @gadget: our gadget
 * @driver: the driver being registered
 *
 * Interrupts are enabled here.
 */
static int ci_udc_start(struct usb_gadget *gadget,
			 struct usb_gadget_driver *driver)
{}

static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
{}

/*
 * ci_udc_stop: unregister a gadget driver
 */
static int ci_udc_stop(struct usb_gadget *gadget)
{}

/******************************************************************************
 * BUS block
 *****************************************************************************/
/*
 * udc_irq: ci interrupt handler
 *
 * This function returns IRQ_HANDLED if the IRQ has been handled
 * It locks access to registers
 */
static irqreturn_t udc_irq(struct ci_hdrc *ci)
{}

/**
 * udc_start: initialize gadget role
 * @ci: chipidea controller
 */
static int udc_start(struct ci_hdrc *ci)
{}

/*
 * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
 *
 * No interrupts active, the IRQ has been released
 */
void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
{}

static int udc_id_switch_for_device(struct ci_hdrc *ci)
{}

static void udc_id_switch_for_host(struct ci_hdrc *ci)
{}

#ifdef CONFIG_PM_SLEEP
static void udc_suspend(struct ci_hdrc *ci)
{}

static void udc_resume(struct ci_hdrc *ci, bool power_lost)
{}
#endif

/**
 * ci_hdrc_gadget_init - initialize device related bits
 * @ci: the controller
 *
 * This function initializes the gadget, if the device is "device capable".
 */
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{}