1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * NXP ISP1301 USB transceiver driver |
4 | * |
5 | * Copyright (C) 2012 Roland Stigge |
6 | * |
7 | * Author: Roland Stigge <stigge@antcom.de> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/mutex.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/usb/phy.h> |
14 | #include <linux/usb/isp1301.h> |
15 | |
16 | #define DRV_NAME "isp1301" |
17 | |
18 | struct isp1301 { |
19 | struct usb_phy phy; |
20 | struct mutex mutex; |
21 | |
22 | struct i2c_client *client; |
23 | }; |
24 | |
25 | #define phy_to_isp(p) (container_of((p), struct isp1301, phy)) |
26 | |
27 | static const struct i2c_device_id isp1301_id[] = { |
28 | { "isp1301" , 0 }, |
29 | { } |
30 | }; |
31 | MODULE_DEVICE_TABLE(i2c, isp1301_id); |
32 | |
33 | static const struct of_device_id isp1301_of_match[] = { |
34 | {.compatible = "nxp,isp1301" }, |
35 | { }, |
36 | }; |
37 | MODULE_DEVICE_TABLE(of, isp1301_of_match); |
38 | |
39 | static struct i2c_client *isp1301_i2c_client; |
40 | |
41 | static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear) |
42 | { |
43 | return i2c_smbus_write_byte_data(client: isp->client, command: reg | clear, value); |
44 | } |
45 | |
46 | static int isp1301_write(struct isp1301 *isp, u8 reg, u8 value) |
47 | { |
48 | return __isp1301_write(isp, reg, value, clear: 0); |
49 | } |
50 | |
51 | static int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value) |
52 | { |
53 | return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR); |
54 | } |
55 | |
56 | static int isp1301_phy_init(struct usb_phy *phy) |
57 | { |
58 | struct isp1301 *isp = phy_to_isp(phy); |
59 | |
60 | /* Disable transparent UART mode first */ |
61 | isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN); |
62 | isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, value: ~MC1_SPEED_REG); |
63 | isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG); |
64 | isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, value: ~0); |
65 | isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, value: (MC2_BI_DI | MC2_PSW_EN |
66 | | MC2_SPD_SUSP_CTRL)); |
67 | |
68 | isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, value: ~0); |
69 | isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0); |
70 | isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, value: (OTG1_DM_PULLDOWN |
71 | | OTG1_DP_PULLDOWN)); |
72 | isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, value: (OTG1_DM_PULLUP |
73 | | OTG1_DP_PULLUP)); |
74 | |
75 | /* mask all interrupts */ |
76 | isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, value: ~0); |
77 | isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, value: ~0); |
78 | isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, value: ~0); |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static int isp1301_phy_set_vbus(struct usb_phy *phy, int on) |
84 | { |
85 | struct isp1301 *isp = phy_to_isp(phy); |
86 | |
87 | if (on) |
88 | isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); |
89 | else |
90 | isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | static int isp1301_probe(struct i2c_client *client) |
96 | { |
97 | struct isp1301 *isp; |
98 | struct usb_phy *phy; |
99 | |
100 | isp = devm_kzalloc(dev: &client->dev, size: sizeof(*isp), GFP_KERNEL); |
101 | if (!isp) |
102 | return -ENOMEM; |
103 | |
104 | isp->client = client; |
105 | mutex_init(&isp->mutex); |
106 | |
107 | phy = &isp->phy; |
108 | phy->dev = &client->dev; |
109 | phy->label = DRV_NAME; |
110 | phy->init = isp1301_phy_init; |
111 | phy->set_vbus = isp1301_phy_set_vbus; |
112 | phy->type = USB_PHY_TYPE_USB2; |
113 | |
114 | i2c_set_clientdata(client, data: isp); |
115 | usb_add_phy_dev(phy); |
116 | |
117 | isp1301_i2c_client = client; |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | static void isp1301_remove(struct i2c_client *client) |
123 | { |
124 | struct isp1301 *isp = i2c_get_clientdata(client); |
125 | |
126 | usb_remove_phy(&isp->phy); |
127 | isp1301_i2c_client = NULL; |
128 | } |
129 | |
130 | static struct i2c_driver isp1301_driver = { |
131 | .driver = { |
132 | .name = DRV_NAME, |
133 | .of_match_table = isp1301_of_match, |
134 | }, |
135 | .probe = isp1301_probe, |
136 | .remove = isp1301_remove, |
137 | .id_table = isp1301_id, |
138 | }; |
139 | |
140 | module_i2c_driver(isp1301_driver); |
141 | |
142 | struct i2c_client *isp1301_get_client(struct device_node *node) |
143 | { |
144 | struct i2c_client *client; |
145 | |
146 | /* reference of ISP1301 I2C node via DT */ |
147 | client = of_find_i2c_device_by_node(node); |
148 | if (client) |
149 | return client; |
150 | |
151 | /* non-DT: only one ISP1301 chip supported */ |
152 | return isp1301_i2c_client; |
153 | } |
154 | EXPORT_SYMBOL_GPL(isp1301_get_client); |
155 | |
156 | MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>" ); |
157 | MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver" ); |
158 | MODULE_LICENSE("GPL" ); |
159 | |