18b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge/*
28b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * NXP ISP1301 USB transceiver driver
38b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge *
48b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * Copyright (C) 2012 Roland Stigge
58b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge *
68b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * Author: Roland Stigge <stigge@antcom.de>
78b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge *
88b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * This program is free software; you can redistribute it and/or modify
98b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * it under the terms of the GNU General Public License version 2 as
108b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge * published by the Free Software Foundation.
118b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge */
128b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
138b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge#include <linux/module.h>
14790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi#include <linux/mutex.h>
158b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge#include <linux/i2c.h>
16790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi#include <linux/usb/phy.h>
17c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi#include <linux/usb/isp1301.h>
188b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
198b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge#define DRV_NAME		"isp1301"
208b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
21790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbistruct isp1301 {
22790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct usb_phy		phy;
23790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct mutex		mutex;
24790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
25790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct i2c_client	*client;
26790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi};
27790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
28c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi#define phy_to_isp(p)		(container_of((p), struct isp1301, phy))
29c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
308b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic const struct i2c_device_id isp1301_id[] = {
318b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	{ "isp1301", 0 },
328b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	{ }
338b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge};
348b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
358b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic struct i2c_client *isp1301_i2c_client;
368b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
37c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbistatic int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear)
38c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi{
39c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	return i2c_smbus_write_byte_data(isp->client, reg | clear, value);
40c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi}
41c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
42c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbistatic int isp1301_write(struct isp1301 *isp, u8 reg, u8 value)
43c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi{
44c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	return __isp1301_write(isp, reg, value, 0);
45c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi}
46c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
47c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbistatic int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value)
48c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi{
49c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR);
50c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi}
51c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
52c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbistatic int isp1301_phy_init(struct usb_phy *phy)
53c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi{
54c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	struct isp1301 *isp = phy_to_isp(phy);
55c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
56c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	/* Disable transparent UART mode first */
57c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN);
58c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, ~MC1_SPEED_REG);
59c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
60c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, ~0);
61c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_PSW_EN
62c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi				| MC2_SPD_SUSP_CTRL));
63c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
64c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, ~0);
65c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
66c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLDOWN
67c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi				| OTG1_DP_PULLDOWN));
68c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLUP
69c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi				| OTG1_DP_PULLUP));
70c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
71c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	/* mask all interrupts */
72c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, ~0);
73c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, ~0);
74c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, ~0);
75c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
76c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	return 0;
77c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi}
78c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
79c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbistatic int isp1301_phy_set_vbus(struct usb_phy *phy, int on)
80c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi{
81c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	struct isp1301 *isp = phy_to_isp(phy);
82c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
83c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	if (on)
84c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi		isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
85c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	else
86c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi		isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
87c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
88c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	return 0;
89c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi}
90c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi
918b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int isp1301_probe(struct i2c_client *client,
928b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge			 const struct i2c_device_id *i2c_id)
938b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
94790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct isp1301 *isp;
95790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct usb_phy *phy;
96790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
97790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL);
98790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	if (!isp)
99790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi		return -ENOMEM;
100790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
101790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp->client = client;
102790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	mutex_init(&isp->mutex);
103790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
104790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy = &isp->phy;
1051abd8b3172b701ed626df4ebf09b7fe7f329888aRobert Jarzmik	phy->dev = &client->dev;
106790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy->label = DRV_NAME;
107c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	phy->init = isp1301_phy_init;
108c38a4f3f508d47e51c3f28e8946b1482ebf47feeFelipe Balbi	phy->set_vbus = isp1301_phy_set_vbus;
109790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy->type = USB_PHY_TYPE_USB2;
110790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
111790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	i2c_set_clientdata(client, isp);
112790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	usb_add_phy_dev(phy);
113790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
1148b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	isp1301_i2c_client = client;
115790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
1168b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return 0;
1178b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
1188b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1198b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int isp1301_remove(struct i2c_client *client)
1208b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
121790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct isp1301 *isp = i2c_get_clientdata(client);
122790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
123790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	usb_remove_phy(&isp->phy);
124790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp1301_i2c_client = NULL;
125790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
1268b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return 0;
1278b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
1288b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1298b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic struct i2c_driver isp1301_driver = {
1308b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.driver = {
1318b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		.name = DRV_NAME,
1328b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	},
1338b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.probe = isp1301_probe,
1348b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.remove = isp1301_remove,
1358b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.id_table = isp1301_id,
1368b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge};
1378b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1388b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggemodule_i2c_driver(isp1301_driver);
1398b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1408b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int match(struct device *dev, void *data)
1418b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
1428b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	struct device_node *node = (struct device_node *)data;
1438b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return (dev->of_node == node) &&
1448b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		(dev->driver == &isp1301_driver.driver);
1458b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
1468b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1478b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestruct i2c_client *isp1301_get_client(struct device_node *node)
1488b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
1498b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	if (node) { /* reference of ISP1301 I2C node via DT */
1508b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		struct device *dev = bus_find_device(&i2c_bus_type, NULL,
1518b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge						     node, match);
1528b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		if (!dev)
1538b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge			return NULL;
1548b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		return to_i2c_client(dev);
1558b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	} else { /* non-DT: only one ISP1301 chip supported */
1568b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		return isp1301_i2c_client;
1578b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	}
1588b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
1598b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeEXPORT_SYMBOL_GPL(isp1301_get_client);
1608b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1618b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
1628b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
1638b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_LICENSE("GPL");
164