// SPDX-License-Identifier: GPL-2.0+
/*
* isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller
*
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2004 David Brownell
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <linux/soc/ti/omap1-mux.h>
#include <linux/soc/ti/omap1-usb.h>
#include <linux/soc/ti/omap1-io.h>
#undef VERBOSE
#define DRIVER_VERSION "24 August 2004"
#define DRIVER_NAME (isp1301_driver.driver.name)
MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
MODULE_LICENSE("GPL");
struct isp1301 {
struct usb_phy phy;
struct i2c_client *client;
void (*i2c_release)(struct device *dev);
int irq_type;
u32 last_otg_ctrl;
unsigned working:1;
struct timer_list timer;
/* use keventd context to change the state for us */
struct work_struct work;
unsigned long todo;
# define WORK_UPDATE_ISP 0 /* update ISP from OTG */
# define WORK_UPDATE_OTG 1 /* update OTG from ISP */
# define WORK_HOST_RESUME 4 /* resume host */
# define WORK_TIMER 6 /* timer fired */
# define WORK_STOP 7 /* don't resubmit */
};
/* bits in OTG_CTRL */
#define OTG_XCEIV_OUTPUTS \
(OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
#define OTG_XCEIV_INPUTS \
(OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
#define OTG_CTRL_BITS \
(OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
/* and OTG_PULLUP is sometimes written */
#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \
OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
OTG_CTRL_BITS)
/*-------------------------------------------------------------------------*/
/* board-specific PM hooks */
#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
#if IS_REACHABLE(CONFIG_TPS65010)
#include <linux/mfd/tps65010.h>
#else
static inline int tps65010_set_vbus_draw(unsigned mA)
{
pr_debug("tps65010: draw %d mA (STUB)\n", mA);
return 0;
}
#endif
static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
{
int status = tps65010_set_vbus_draw(mA);
if (status < 0)
pr_debug(" VBUS %d mA error %d\n", mA, status);
}
#else
static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
{
/* H4 controls this by DIP switch S2.4; no soft control.
* ON means the charger is always enabled. Leave it OFF
* unless the OTG port is used only in B-peripheral mode.
*/
}
#endif
static void enable_vbus_source(struct isp1301 *isp)
{
/* this board won't supply more than 8mA vbus power.
* some boards can switch a 100ma "unit load" (or more).
*/
}
/* products will deliver OTG messages with LEDs, GUI, etc */
static inline void notresponding(struct isp1301 *isp)
{
printk(KERN_NOTICE "OTG device not responding.\n");
}
/*-------------------------------------------------------------------------*/
static struct i2c_driver isp1301_driver;
/* smbus apis are used for portability */
static inline u8
isp1301_get_u8(struct isp1301 *isp, u8 reg)
{
return i2c_smbus_read_byte_data(isp->client, reg + 0);
}
static inline int
isp1301_get_u16(struct isp1301 *isp, u8 reg)
{
return i2c_smbus_read_word_data(isp->client, reg);
}
static inline int
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
}
static inline int
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
return i2c_smbus_wr
|