Commit 2a60f5ea authored by Alexandre Belloni's avatar Alexandre Belloni Committed by Felipe Balbi

usb: gadget: udc: lpc32xx: add support for stotg04 phy

The STOTG04 phy is used as a drop-in replacement of the ISP1301 but some
bits doesn't have exactly the same meaning and this can lead to issues.
Detect the phy dynamically and avoid writing to reserved bits.
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent f584fa8c
...@@ -115,6 +115,11 @@ struct lpc32xx_ep { ...@@ -115,6 +115,11 @@ struct lpc32xx_ep {
bool wedge; bool wedge;
}; };
enum atx_type {
ISP1301,
STOTG04,
};
/* /*
* Common UDC structure * Common UDC structure
*/ */
...@@ -149,6 +154,7 @@ struct lpc32xx_udc { ...@@ -149,6 +154,7 @@ struct lpc32xx_udc {
u8 last_vbus; u8 last_vbus;
int pullup; int pullup;
int poweron; int poweron;
enum atx_type atx;
/* Work queues related to I2C support */ /* Work queues related to I2C support */
struct work_struct pullup_job; struct work_struct pullup_job;
...@@ -550,6 +556,15 @@ static inline void remove_debug_file(struct lpc32xx_udc *udc) {} ...@@ -550,6 +556,15 @@ static inline void remove_debug_file(struct lpc32xx_udc *udc) {}
/* Primary initialization sequence for the ISP1301 transceiver */ /* Primary initialization sequence for the ISP1301 transceiver */
static void isp1301_udc_configure(struct lpc32xx_udc *udc) static void isp1301_udc_configure(struct lpc32xx_udc *udc)
{ {
u8 value;
s32 vendor, product;
vendor = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00);
product = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02);
if (vendor == 0x0483 && product == 0xa0c4)
udc->atx = STOTG04;
/* LPC32XX only supports DAT_SE0 USB mode */ /* LPC32XX only supports DAT_SE0 USB mode */
/* This sequence is important */ /* This sequence is important */
...@@ -569,8 +584,12 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc) ...@@ -569,8 +584,12 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
*/ */
i2c_smbus_write_byte_data(udc->isp1301_i2c_client, i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
(ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
value = MC2_BI_DI;
if (udc->atx != STOTG04)
value |= MC2_SPD_SUSP_CTRL;
i2c_smbus_write_byte_data(udc->isp1301_i2c_client, i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL)); ISP1301_I2C_MODE_CONTROL_2, value);
/* Driver VBUS_DRV high or low depending on board setup */ /* Driver VBUS_DRV high or low depending on board setup */
if (udc->board->vbus_drv_pol != 0) if (udc->board->vbus_drv_pol != 0)
...@@ -610,12 +629,11 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc) ...@@ -610,12 +629,11 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
i2c_smbus_write_byte_data(udc->isp1301_i2c_client, i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
ISP1301_I2C_INTERRUPT_RISING, INT_SESS_VLD | INT_VBUS_VLD); ISP1301_I2C_INTERRUPT_RISING, INT_SESS_VLD | INT_VBUS_VLD);
dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", vendor);
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00)); dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", product);
dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02));
dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n",
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14));
} }
/* Enables or disables the USB device pullup via the ISP1301 transceiver */ /* Enables or disables the USB device pullup via the ISP1301 transceiver */
...@@ -658,6 +676,10 @@ static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, ...@@ -658,6 +676,10 @@ static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup,
/* Powers up or down the ISP1301 transceiver */ /* Powers up or down the ISP1301 transceiver */
static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable)
{ {
/* There is no "global power down" register for stotg04 */
if (udc->atx == STOTG04)
return;
if (enable != 0) if (enable != 0)
/* Power up ISP1301 - this ISP1301 will automatically wakeup /* Power up ISP1301 - this ISP1301 will automatically wakeup
when VBUS is detected */ when VBUS is detected */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment