21
21
* If both the fiber and copper ports are connected, the first to gain
22
22
* link takes priority and the other port is completely locked out.
23
23
*/
24
- #include <linux/phy.h>
24
+ #include <linux/ctype.h>
25
+ #include <linux/hwmon.h>
25
26
#include <linux/marvell_phy.h>
27
+ #include <linux/phy.h>
26
28
27
29
enum {
28
30
MV_PCS_BASE_T = 0x0000 ,
@@ -40,6 +42,19 @@ enum {
40
42
*/
41
43
MV_AN_CTRL1000 = 0x8000 , /* 1000base-T control register */
42
44
MV_AN_STAT1000 = 0x8001 , /* 1000base-T status register */
45
+
46
+ /* Vendor2 MMD registers */
47
+ MV_V2_TEMP_CTRL = 0xf08a ,
48
+ MV_V2_TEMP_CTRL_MASK = 0xc000 ,
49
+ MV_V2_TEMP_CTRL_SAMPLE = 0x0000 ,
50
+ MV_V2_TEMP_CTRL_DISABLE = 0xc000 ,
51
+ MV_V2_TEMP = 0xf08c ,
52
+ MV_V2_TEMP_UNKNOWN = 0x9600 , /* unknown function */
53
+ };
54
+
55
+ struct mv3310_priv {
56
+ struct device * hwmon_dev ;
57
+ char * hwmon_name ;
43
58
};
44
59
45
60
static int mv3310_modify (struct phy_device * phydev , int devad , u16 reg ,
@@ -60,17 +75,180 @@ static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
60
75
return ret < 0 ? ret : 1 ;
61
76
}
62
77
78
+ #ifdef CONFIG_HWMON
79
+ static umode_t mv3310_hwmon_is_visible (const void * data ,
80
+ enum hwmon_sensor_types type ,
81
+ u32 attr , int channel )
82
+ {
83
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval )
84
+ return 0444 ;
85
+ if (type == hwmon_temp && attr == hwmon_temp_input )
86
+ return 0444 ;
87
+ return 0 ;
88
+ }
89
+
90
+ static int mv3310_hwmon_read (struct device * dev , enum hwmon_sensor_types type ,
91
+ u32 attr , int channel , long * value )
92
+ {
93
+ struct phy_device * phydev = dev_get_drvdata (dev );
94
+ int temp ;
95
+
96
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval ) {
97
+ * value = MSEC_PER_SEC ;
98
+ return 0 ;
99
+ }
100
+
101
+ if (type == hwmon_temp && attr == hwmon_temp_input ) {
102
+ temp = phy_read_mmd (phydev , MDIO_MMD_VEND2 , MV_V2_TEMP );
103
+ if (temp < 0 )
104
+ return temp ;
105
+
106
+ * value = ((temp & 0xff ) - 75 ) * 1000 ;
107
+
108
+ return 0 ;
109
+ }
110
+
111
+ return - EOPNOTSUPP ;
112
+ }
113
+
114
+ static const struct hwmon_ops mv3310_hwmon_ops = {
115
+ .is_visible = mv3310_hwmon_is_visible ,
116
+ .read = mv3310_hwmon_read ,
117
+ };
118
+
119
+ static u32 mv3310_hwmon_chip_config [] = {
120
+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL ,
121
+ 0 ,
122
+ };
123
+
124
+ static const struct hwmon_channel_info mv3310_hwmon_chip = {
125
+ .type = hwmon_chip ,
126
+ .config = mv3310_hwmon_chip_config ,
127
+ };
128
+
129
+ static u32 mv3310_hwmon_temp_config [] = {
130
+ HWMON_T_INPUT ,
131
+ 0 ,
132
+ };
133
+
134
+ static const struct hwmon_channel_info mv3310_hwmon_temp = {
135
+ .type = hwmon_temp ,
136
+ .config = mv3310_hwmon_temp_config ,
137
+ };
138
+
139
+ static const struct hwmon_channel_info * mv3310_hwmon_info [] = {
140
+ & mv3310_hwmon_chip ,
141
+ & mv3310_hwmon_temp ,
142
+ NULL ,
143
+ };
144
+
145
+ static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
146
+ .ops = & mv3310_hwmon_ops ,
147
+ .info = mv3310_hwmon_info ,
148
+ };
149
+
150
+ static int mv3310_hwmon_config (struct phy_device * phydev , bool enable )
151
+ {
152
+ u16 val ;
153
+ int ret ;
154
+
155
+ ret = phy_write_mmd (phydev , MDIO_MMD_VEND2 , MV_V2_TEMP ,
156
+ MV_V2_TEMP_UNKNOWN );
157
+ if (ret < 0 )
158
+ return ret ;
159
+
160
+ val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE ;
161
+ ret = mv3310_modify (phydev , MDIO_MMD_VEND2 , MV_V2_TEMP_CTRL ,
162
+ MV_V2_TEMP_CTRL_MASK , val );
163
+
164
+ return ret < 0 ? ret : 0 ;
165
+ }
166
+
167
+ static void mv3310_hwmon_disable (void * data )
168
+ {
169
+ struct phy_device * phydev = data ;
170
+
171
+ mv3310_hwmon_config (phydev , false);
172
+ }
173
+
174
+ static int mv3310_hwmon_probe (struct phy_device * phydev )
175
+ {
176
+ struct device * dev = & phydev -> mdio .dev ;
177
+ struct mv3310_priv * priv = dev_get_drvdata (& phydev -> mdio .dev );
178
+ int i , j , ret ;
179
+
180
+ priv -> hwmon_name = devm_kstrdup (dev , dev_name (dev ), GFP_KERNEL );
181
+ if (!priv -> hwmon_name )
182
+ return - ENODEV ;
183
+
184
+ for (i = j = 0 ; priv -> hwmon_name [i ]; i ++ ) {
185
+ if (isalnum (priv -> hwmon_name [i ])) {
186
+ if (i != j )
187
+ priv -> hwmon_name [j ] = priv -> hwmon_name [i ];
188
+ j ++ ;
189
+ }
190
+ }
191
+ priv -> hwmon_name [j ] = '\0' ;
192
+
193
+ ret = mv3310_hwmon_config (phydev , true);
194
+ if (ret )
195
+ return ret ;
196
+
197
+ ret = devm_add_action_or_reset (dev , mv3310_hwmon_disable , phydev );
198
+ if (ret )
199
+ return ret ;
200
+
201
+ priv -> hwmon_dev = devm_hwmon_device_register_with_info (dev ,
202
+ priv -> hwmon_name , phydev ,
203
+ & mv3310_hwmon_chip_info , NULL );
204
+
205
+ return PTR_ERR_OR_ZERO (priv -> hwmon_dev );
206
+ }
207
+ #else
208
+ static inline int mv3310_hwmon_config (struct phy_device * phydev , bool enable )
209
+ {
210
+ return 0 ;
211
+ }
212
+
213
+ static int mv3310_hwmon_probe (struct phy_device * phydev )
214
+ {
215
+ return 0 ;
216
+ }
217
+ #endif
218
+
63
219
static int mv3310_probe (struct phy_device * phydev )
64
220
{
221
+ struct mv3310_priv * priv ;
65
222
u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN ;
223
+ int ret ;
66
224
67
225
if (!phydev -> is_c45 ||
68
226
(phydev -> c45_ids .devices_in_package & mmd_mask ) != mmd_mask )
69
227
return - ENODEV ;
70
228
229
+ priv = devm_kzalloc (& phydev -> mdio .dev , sizeof (* priv ), GFP_KERNEL );
230
+ if (!priv )
231
+ return - ENOMEM ;
232
+
233
+ dev_set_drvdata (& phydev -> mdio .dev , priv );
234
+
235
+ ret = mv3310_hwmon_probe (phydev );
236
+ if (ret )
237
+ return ret ;
238
+
239
+ return 0 ;
240
+ }
241
+
242
+ static int mv3310_suspend (struct phy_device * phydev )
243
+ {
71
244
return 0 ;
72
245
}
73
246
247
+ static int mv3310_resume (struct phy_device * phydev )
248
+ {
249
+ return mv3310_hwmon_config (phydev , true);
250
+ }
251
+
74
252
static int mv3310_config_init (struct phy_device * phydev )
75
253
{
76
254
__ETHTOOL_DECLARE_LINK_MODE_MASK (supported ) = { 0 , };
@@ -367,9 +545,11 @@ static struct phy_driver mv3310_drivers[] = {
367
545
SUPPORTED_FIBRE |
368
546
SUPPORTED_10000baseT_Full |
369
547
SUPPORTED_Backplane ,
370
- .probe = mv3310_probe ,
371
548
.soft_reset = gen10g_no_soft_reset ,
372
549
.config_init = mv3310_config_init ,
550
+ .probe = mv3310_probe ,
551
+ .suspend = mv3310_suspend ,
552
+ .resume = mv3310_resume ,
373
553
.config_aneg = mv3310_config_aneg ,
374
554
.aneg_done = mv3310_aneg_done ,
375
555
.read_status = mv3310_read_status ,
0 commit comments