phy-isp1301.c revision 790d3a5ab6e36fb06e99339afe35ecdec4d3b2cb
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>
178b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
188b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge#define DRV_NAME		"isp1301"
198b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
20790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbistruct isp1301 {
21790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct usb_phy		phy;
22790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct mutex		mutex;
23790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
24790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct i2c_client	*client;
25790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi};
26790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
278b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic const struct i2c_device_id isp1301_id[] = {
288b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	{ "isp1301", 0 },
298b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	{ }
308b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge};
318b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
328b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic struct i2c_client *isp1301_i2c_client;
338b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
348b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int isp1301_probe(struct i2c_client *client,
358b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge			 const struct i2c_device_id *i2c_id)
368b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
37790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct isp1301 *isp;
38790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct usb_phy *phy;
39790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
40790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL);
41790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	if (!isp)
42790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi		return -ENOMEM;
43790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
44790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp->client = client;
45790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	mutex_init(&isp->mutex);
46790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
47790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy = &isp->phy;
48790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy->label = DRV_NAME;
49790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	phy->type = USB_PHY_TYPE_USB2;
50790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
51790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	i2c_set_clientdata(client, isp);
52790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	usb_add_phy_dev(phy);
53790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
548b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	isp1301_i2c_client = client;
55790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
568b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return 0;
578b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
588b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
598b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int isp1301_remove(struct i2c_client *client)
608b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
61790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	struct isp1301 *isp = i2c_get_clientdata(client);
62790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
63790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	usb_remove_phy(&isp->phy);
64790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi	isp1301_i2c_client = NULL;
65790d3a5ab6e36fb06e99339afe35ecdec4d3b2cbFelipe Balbi
668b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return 0;
678b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
688b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
698b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic struct i2c_driver isp1301_driver = {
708b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.driver = {
718b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		.name = DRV_NAME,
728b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	},
738b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.probe = isp1301_probe,
748b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.remove = isp1301_remove,
758b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	.id_table = isp1301_id,
768b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge};
778b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
788b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggemodule_i2c_driver(isp1301_driver);
798b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
808b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestatic int match(struct device *dev, void *data)
818b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
828b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	struct device_node *node = (struct device_node *)data;
838b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	return (dev->of_node == node) &&
848b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		(dev->driver == &isp1301_driver.driver);
858b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
868b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
878b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stiggestruct i2c_client *isp1301_get_client(struct device_node *node)
888b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge{
898b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	if (node) { /* reference of ISP1301 I2C node via DT */
908b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		struct device *dev = bus_find_device(&i2c_bus_type, NULL,
918b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge						     node, match);
928b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		if (!dev)
938b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge			return NULL;
948b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		return to_i2c_client(dev);
958b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	} else { /* non-DT: only one ISP1301 chip supported */
968b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge		return isp1301_i2c_client;
978b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge	}
988b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge}
998b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeEXPORT_SYMBOL_GPL(isp1301_get_client);
1008b7c3b68104d687a16dbcc803a18c72148fdfdacRoland Stigge
1018b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
1028b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
1038b7c3b68104d687a16dbcc803a18c72148fdfdacRoland StiggeMODULE_LICENSE("GPL");
104