diff options
Diffstat (limited to 'drivers/net/phy/mdio-gpio.c')
-rw-r--r-- | drivers/net/phy/mdio-gpio.c | 72 |
1 files changed, 51 insertions, 21 deletions
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index e701433bf52f..5f1a2250018f 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c | |||
@@ -32,29 +32,39 @@ | |||
32 | 32 | ||
33 | struct mdio_gpio_info { | 33 | struct mdio_gpio_info { |
34 | struct mdiobb_ctrl ctrl; | 34 | struct mdiobb_ctrl ctrl; |
35 | int mdc, mdio; | 35 | int mdc, mdio, mdo; |
36 | int mdc_active_low, mdio_active_low, mdo_active_low; | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | static void *mdio_gpio_of_get_data(struct platform_device *pdev) | 39 | static void *mdio_gpio_of_get_data(struct platform_device *pdev) |
39 | { | 40 | { |
40 | struct device_node *np = pdev->dev.of_node; | 41 | struct device_node *np = pdev->dev.of_node; |
41 | struct mdio_gpio_platform_data *pdata; | 42 | struct mdio_gpio_platform_data *pdata; |
43 | enum of_gpio_flags flags; | ||
42 | int ret; | 44 | int ret; |
43 | 45 | ||
44 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 46 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
45 | if (!pdata) | 47 | if (!pdata) |
46 | return NULL; | 48 | return NULL; |
47 | 49 | ||
48 | ret = of_get_gpio(np, 0); | 50 | ret = of_get_gpio_flags(np, 0, &flags); |
49 | if (ret < 0) | 51 | if (ret < 0) |
50 | return NULL; | 52 | return NULL; |
51 | 53 | ||
52 | pdata->mdc = ret; | 54 | pdata->mdc = ret; |
55 | pdata->mdc_active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
53 | 56 | ||
54 | ret = of_get_gpio(np, 1); | 57 | ret = of_get_gpio_flags(np, 1, &flags); |
55 | if (ret < 0) | 58 | if (ret < 0) |
56 | return NULL; | 59 | return NULL; |
57 | pdata->mdio = ret; | 60 | pdata->mdio = ret; |
61 | pdata->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
62 | |||
63 | ret = of_get_gpio_flags(np, 2, &flags); | ||
64 | if (ret > 0) { | ||
65 | pdata->mdo = ret; | ||
66 | pdata->mdo_active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
67 | } | ||
58 | 68 | ||
59 | return pdata; | 69 | return pdata; |
60 | } | 70 | } |
@@ -64,8 +74,19 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) | |||
64 | struct mdio_gpio_info *bitbang = | 74 | struct mdio_gpio_info *bitbang = |
65 | container_of(ctrl, struct mdio_gpio_info, ctrl); | 75 | container_of(ctrl, struct mdio_gpio_info, ctrl); |
66 | 76 | ||
77 | if (bitbang->mdo) { | ||
78 | /* Separate output pin. Always set its value to high | ||
79 | * when changing direction. If direction is input, | ||
80 | * assume the pin serves as pull-up. If direction is | ||
81 | * output, the default value is high. | ||
82 | */ | ||
83 | gpio_set_value(bitbang->mdo, 1 ^ bitbang->mdo_active_low); | ||
84 | return; | ||
85 | } | ||
86 | |||
67 | if (dir) | 87 | if (dir) |
68 | gpio_direction_output(bitbang->mdio, 1); | 88 | gpio_direction_output(bitbang->mdio, |
89 | 1 ^ bitbang->mdio_active_low); | ||
69 | else | 90 | else |
70 | gpio_direction_input(bitbang->mdio); | 91 | gpio_direction_input(bitbang->mdio); |
71 | } | 92 | } |
@@ -75,7 +96,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl) | |||
75 | struct mdio_gpio_info *bitbang = | 96 | struct mdio_gpio_info *bitbang = |
76 | container_of(ctrl, struct mdio_gpio_info, ctrl); | 97 | container_of(ctrl, struct mdio_gpio_info, ctrl); |
77 | 98 | ||
78 | return gpio_get_value(bitbang->mdio); | 99 | return gpio_get_value(bitbang->mdio) ^ bitbang->mdio_active_low; |
79 | } | 100 | } |
80 | 101 | ||
81 | static void mdio_set(struct mdiobb_ctrl *ctrl, int what) | 102 | static void mdio_set(struct mdiobb_ctrl *ctrl, int what) |
@@ -83,7 +104,10 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what) | |||
83 | struct mdio_gpio_info *bitbang = | 104 | struct mdio_gpio_info *bitbang = |
84 | container_of(ctrl, struct mdio_gpio_info, ctrl); | 105 | container_of(ctrl, struct mdio_gpio_info, ctrl); |
85 | 106 | ||
86 | gpio_set_value(bitbang->mdio, what); | 107 | if (bitbang->mdo) |
108 | gpio_set_value(bitbang->mdo, what ^ bitbang->mdo_active_low); | ||
109 | else | ||
110 | gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low); | ||
87 | } | 111 | } |
88 | 112 | ||
89 | static void mdc_set(struct mdiobb_ctrl *ctrl, int what) | 113 | static void mdc_set(struct mdiobb_ctrl *ctrl, int what) |
@@ -91,7 +115,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what) | |||
91 | struct mdio_gpio_info *bitbang = | 115 | struct mdio_gpio_info *bitbang = |
92 | container_of(ctrl, struct mdio_gpio_info, ctrl); | 116 | container_of(ctrl, struct mdio_gpio_info, ctrl); |
93 | 117 | ||
94 | gpio_set_value(bitbang->mdc, what); | 118 | gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low); |
95 | } | 119 | } |
96 | 120 | ||
97 | static struct mdiobb_ops mdio_gpio_ops = { | 121 | static struct mdiobb_ops mdio_gpio_ops = { |
@@ -110,18 +134,22 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, | |||
110 | struct mdio_gpio_info *bitbang; | 134 | struct mdio_gpio_info *bitbang; |
111 | int i; | 135 | int i; |
112 | 136 | ||
113 | bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); | 137 | bitbang = devm_kzalloc(dev, sizeof(*bitbang), GFP_KERNEL); |
114 | if (!bitbang) | 138 | if (!bitbang) |
115 | goto out; | 139 | goto out; |
116 | 140 | ||
117 | bitbang->ctrl.ops = &mdio_gpio_ops; | 141 | bitbang->ctrl.ops = &mdio_gpio_ops; |
118 | bitbang->ctrl.reset = pdata->reset; | 142 | bitbang->ctrl.reset = pdata->reset; |
119 | bitbang->mdc = pdata->mdc; | 143 | bitbang->mdc = pdata->mdc; |
144 | bitbang->mdc_active_low = pdata->mdc_active_low; | ||
120 | bitbang->mdio = pdata->mdio; | 145 | bitbang->mdio = pdata->mdio; |
146 | bitbang->mdio_active_low = pdata->mdio_active_low; | ||
147 | bitbang->mdo = pdata->mdo; | ||
148 | bitbang->mdo_active_low = pdata->mdo_active_low; | ||
121 | 149 | ||
122 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); | 150 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); |
123 | if (!new_bus) | 151 | if (!new_bus) |
124 | goto out_free_bitbang; | 152 | goto out; |
125 | 153 | ||
126 | new_bus->name = "GPIO Bitbanged MDIO", | 154 | new_bus->name = "GPIO Bitbanged MDIO", |
127 | 155 | ||
@@ -138,11 +166,18 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, | |||
138 | 166 | ||
139 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); | 167 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); |
140 | 168 | ||
141 | if (gpio_request(bitbang->mdc, "mdc")) | 169 | if (devm_gpio_request(dev, bitbang->mdc, "mdc")) |
170 | goto out_free_bus; | ||
171 | |||
172 | if (devm_gpio_request(dev, bitbang->mdio, "mdio")) | ||
142 | goto out_free_bus; | 173 | goto out_free_bus; |
143 | 174 | ||
144 | if (gpio_request(bitbang->mdio, "mdio")) | 175 | if (bitbang->mdo) { |
145 | goto out_free_mdc; | 176 | if (devm_gpio_request(dev, bitbang->mdo, "mdo")) |
177 | goto out_free_bus; | ||
178 | gpio_direction_output(bitbang->mdo, 1); | ||
179 | gpio_direction_input(bitbang->mdio); | ||
180 | } | ||
146 | 181 | ||
147 | gpio_direction_output(bitbang->mdc, 0); | 182 | gpio_direction_output(bitbang->mdc, 0); |
148 | 183 | ||
@@ -150,12 +185,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, | |||
150 | 185 | ||
151 | return new_bus; | 186 | return new_bus; |
152 | 187 | ||
153 | out_free_mdc: | ||
154 | gpio_free(bitbang->mdc); | ||
155 | out_free_bus: | 188 | out_free_bus: |
156 | free_mdio_bitbang(new_bus); | 189 | free_mdio_bitbang(new_bus); |
157 | out_free_bitbang: | ||
158 | kfree(bitbang); | ||
159 | out: | 190 | out: |
160 | return NULL; | 191 | return NULL; |
161 | } | 192 | } |
@@ -163,13 +194,8 @@ out: | |||
163 | static void mdio_gpio_bus_deinit(struct device *dev) | 194 | static void mdio_gpio_bus_deinit(struct device *dev) |
164 | { | 195 | { |
165 | struct mii_bus *bus = dev_get_drvdata(dev); | 196 | struct mii_bus *bus = dev_get_drvdata(dev); |
166 | struct mdio_gpio_info *bitbang = bus->priv; | ||
167 | 197 | ||
168 | dev_set_drvdata(dev, NULL); | ||
169 | gpio_free(bitbang->mdio); | ||
170 | gpio_free(bitbang->mdc); | ||
171 | free_mdio_bitbang(bus); | 198 | free_mdio_bitbang(bus); |
172 | kfree(bitbang); | ||
173 | } | 199 | } |
174 | 200 | ||
175 | static void mdio_gpio_bus_destroy(struct device *dev) | 201 | static void mdio_gpio_bus_destroy(struct device *dev) |
@@ -189,6 +215,10 @@ static int mdio_gpio_probe(struct platform_device *pdev) | |||
189 | if (pdev->dev.of_node) { | 215 | if (pdev->dev.of_node) { |
190 | pdata = mdio_gpio_of_get_data(pdev); | 216 | pdata = mdio_gpio_of_get_data(pdev); |
191 | bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); | 217 | bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); |
218 | if (bus_id < 0) { | ||
219 | dev_warn(&pdev->dev, "failed to get alias id\n"); | ||
220 | bus_id = 0; | ||
221 | } | ||
192 | } else { | 222 | } else { |
193 | pdata = dev_get_platdata(&pdev->dev); | 223 | pdata = dev_get_platdata(&pdev->dev); |
194 | bus_id = pdev->id; | 224 | bus_id = pdev->id; |