Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'add-si3474-pse-controller-driver'

Piotr Kubik says:

====================
Add Si3474 PSE controller driver

From: Piotr Kubik <piotr.kubik@adtran.com>

These patch series provide support for Skyworks Si3474 I2C Power
Sourcing Equipment controller.

Based on the TPS23881 driver code.

Supported features of Si3474:
- get port status,
- get port power,
- get port voltage,
- enable/disable port power

Signed-off-by: Piotr Kubik <piotr.kubik@adtran.com>
====================

Link: https://patch.msgid.link/6af537dc-8a52-4710-8a18-dcfbb911cf23@adtran.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+734
+144
Documentation/devicetree/bindings/net/pse-pd/skyworks,si3474.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/pse-pd/skyworks,si3474.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Skyworks Si3474 Power Sourcing Equipment controller 8 + 9 + maintainers: 10 + - Piotr Kubik <piotr.kubik@adtran.com> 11 + 12 + allOf: 13 + - $ref: pse-controller.yaml# 14 + 15 + properties: 16 + compatible: 17 + enum: 18 + - skyworks,si3474 19 + 20 + reg: 21 + maxItems: 2 22 + 23 + reg-names: 24 + items: 25 + - const: main 26 + - const: secondary 27 + 28 + channels: 29 + description: The Si3474 is a single-chip PoE PSE controller managing 30 + 8 physical power delivery channels. Internally, it's structured 31 + into two logical "Quads". 32 + Quad 0 Manages physical channels ('ports' in datasheet) 0, 1, 2, 3 33 + Quad 1 Manages physical channels ('ports' in datasheet) 4, 5, 6, 7. 34 + 35 + type: object 36 + additionalProperties: false 37 + 38 + properties: 39 + "#address-cells": 40 + const: 1 41 + 42 + "#size-cells": 43 + const: 0 44 + 45 + patternProperties: 46 + '^channel@[0-7]$': 47 + type: object 48 + additionalProperties: false 49 + 50 + properties: 51 + reg: 52 + maxItems: 1 53 + 54 + required: 55 + - reg 56 + 57 + required: 58 + - "#address-cells" 59 + - "#size-cells" 60 + 61 + required: 62 + - compatible 63 + - reg 64 + - pse-pis 65 + 66 + unevaluatedProperties: false 67 + 68 + examples: 69 + - | 70 + i2c { 71 + #address-cells = <1>; 72 + #size-cells = <0>; 73 + 74 + ethernet-pse@26 { 75 + compatible = "skyworks,si3474"; 76 + reg-names = "main", "secondary"; 77 + reg = <0x26>, <0x27>; 78 + 79 + channels { 80 + #address-cells = <1>; 81 + #size-cells = <0>; 82 + phys0_0: channel@0 { 83 + reg = <0>; 84 + }; 85 + phys0_1: channel@1 { 86 + reg = <1>; 87 + }; 88 + phys0_2: channel@2 { 89 + reg = <2>; 90 + }; 91 + phys0_3: channel@3 { 92 + reg = <3>; 93 + }; 94 + phys0_4: channel@4 { 95 + reg = <4>; 96 + }; 97 + phys0_5: channel@5 { 98 + reg = <5>; 99 + }; 100 + phys0_6: channel@6 { 101 + reg = <6>; 102 + }; 103 + phys0_7: channel@7 { 104 + reg = <7>; 105 + }; 106 + }; 107 + pse-pis { 108 + #address-cells = <1>; 109 + #size-cells = <0>; 110 + pse_pi0: pse-pi@0 { 111 + reg = <0>; 112 + #pse-cells = <0>; 113 + pairset-names = "alternative-a", "alternative-b"; 114 + pairsets = <&phys0_0>, <&phys0_1>; 115 + polarity-supported = "MDI-X", "S"; 116 + vpwr-supply = <&reg_pse>; 117 + }; 118 + pse_pi1: pse-pi@1 { 119 + reg = <1>; 120 + #pse-cells = <0>; 121 + pairset-names = "alternative-a", "alternative-b"; 122 + pairsets = <&phys0_2>, <&phys0_3>; 123 + polarity-supported = "MDI-X", "S"; 124 + vpwr-supply = <&reg_pse>; 125 + }; 126 + pse_pi2: pse-pi@2 { 127 + reg = <2>; 128 + #pse-cells = <0>; 129 + pairset-names = "alternative-a", "alternative-b"; 130 + pairsets = <&phys0_4>, <&phys0_5>; 131 + polarity-supported = "MDI-X", "S"; 132 + vpwr-supply = <&reg_pse>; 133 + }; 134 + pse_pi3: pse-pi@3 { 135 + reg = <3>; 136 + #pse-cells = <0>; 137 + pairset-names = "alternative-a", "alternative-b"; 138 + pairsets = <&phys0_6>, <&phys0_7>; 139 + polarity-supported = "MDI-X", "S"; 140 + vpwr-supply = <&reg_pse>; 141 + }; 142 + }; 143 + }; 144 + };
+11
drivers/net/pse-pd/Kconfig
··· 32 32 To compile this driver as a module, choose M here: the 33 33 module will be called pd692x0. 34 34 35 + config PSE_SI3474 36 + tristate "Si3474 PSE controller" 37 + depends on I2C 38 + help 39 + This module provides support for Si3474 regulator based Ethernet 40 + Power Sourcing Equipment. 41 + Only 4-pair PSE configurations are supported. 42 + 43 + To compile this driver as a module, choose M here: the 44 + module will be called si3474. 45 + 35 46 config PSE_TPS23881 36 47 tristate "TPS23881 PSE controller" 37 48 depends on I2C
+1
drivers/net/pse-pd/Makefile
··· 5 5 6 6 obj-$(CONFIG_PSE_REGULATOR) += pse_regulator.o 7 7 obj-$(CONFIG_PSE_PD692X0) += pd692x0.o 8 + obj-$(CONFIG_PSE_SI3474) += si3474.o 8 9 obj-$(CONFIG_PSE_TPS23881) += tps23881.o
+578
drivers/net/pse-pd/si3474.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for the Skyworks Si3474 PoE PSE Controller 4 + * 5 + * Chip Architecture & Terminology: 6 + * 7 + * The Si3474 is a single-chip PoE PSE controller managing 8 physical power 8 + * delivery channels. Internally, it's structured into two logical "Quads". 9 + * 10 + * Quad 0: Manages physical channels ('ports' in datasheet) 0, 1, 2, 3 11 + * Quad 1: Manages physical channels ('ports' in datasheet) 4, 5, 6, 7 12 + * 13 + * Each Quad is accessed via a separate I2C address. The base address range is 14 + * set by hardware pins A1-A4, and the specific address selects Quad 0 (usually 15 + * the lower/even address) or Quad 1 (usually the higher/odd address). 16 + * See datasheet Table 2.2 for the address mapping. 17 + * 18 + * While the Quads manage channel-specific operations, the Si3474 package has 19 + * several resources shared across the entire chip: 20 + * - Single RESETb input pin. 21 + * - Single INTb output pin (signals interrupts from *either* Quad). 22 + * - Single OSS input pin (Emergency Shutdown). 23 + * - Global I2C Address (0x7F) used for firmware updates. 24 + * - Global status monitoring (Temperature, VDD/VPWR Undervoltage Lockout). 25 + * 26 + * Driver Architecture: 27 + * 28 + * To handle the mix of per-Quad access and shared resources correctly, this 29 + * driver treats the entire Si3474 package as one logical device. The driver 30 + * instance associated with the primary I2C address (Quad 0) takes ownership. 31 + * It discovers and manages the I2C client for the secondary address (Quad 1). 32 + * This primary instance handles shared resources like IRQ management and 33 + * registers a single PSE controller device representing all logical PIs. 34 + * Internal functions route I2C commands to the appropriate Quad's i2c_client 35 + * based on the target channel or PI. 36 + * 37 + * Terminology Mapping: 38 + * 39 + * - "PI" (Power Interface): Refers to the logical PSE port as defined by 40 + * IEEE 802.3 (typically corresponds to an RJ45 connector). This is the 41 + * `id` (0-7) used in the pse_controller_ops. 42 + * - "Channel": Refers to one of the 8 physical power control paths within 43 + * the Si3474 chip itself (hardware channels 0-7). This terminology is 44 + * used internally within the driver to avoid confusion with 'ports'. 45 + * - "Quad": One of the two internal 4-channel management units within the 46 + * Si3474, each accessed via its own I2C address. 47 + * 48 + * Relationship: 49 + * - A 2-Pair PoE PI uses 1 Channel. 50 + * - A 4-Pair PoE PI uses 2 Channels. 51 + * 52 + * ASCII Schematic: 53 + * 54 + * +-----------------------------------------------------+ 55 + * | Si3474 Chip | 56 + * | | 57 + * | +---------------------+ +---------------------+ | 58 + * | | Quad 0 | | Quad 1 | | 59 + * | | Channels 0, 1, 2, 3 | | Channels 4, 5, 6, 7 | | 60 + * | +----------^----------+ +-------^-------------+ | 61 + * | I2C Addr 0 | | I2C Addr 1 | 62 + * | +------------------------+ | 63 + * | (Primary Driver Instance) (Managed by Primary) | 64 + * | | 65 + * | Shared Resources (affect whole chip): | 66 + * | - Single INTb Output -> Handled by Primary | 67 + * | - Single RESETb Input | 68 + * | - Single OSS Input -> Handled by Primary | 69 + * | - Global I2C Addr (0x7F) for Firmware Update | 70 + * | - Global Status (Temp, VDD/VPWR UVLO) | 71 + * +-----------------------------------------------------+ 72 + * | | | | | | | | 73 + * Ch0 Ch1 Ch2 Ch3 Ch4 Ch5 Ch6 Ch7 (Physical Channels) 74 + * 75 + * Example Mapping (Logical PI to Physical Channel(s)): 76 + * * 2-Pair Mode (8 PIs): 77 + * PI 0 -> Ch 0 78 + * PI 1 -> Ch 1 79 + * ... 80 + * PI 7 -> Ch 7 81 + * * 4-Pair Mode (4 PIs): 82 + * PI 0 -> Ch 0 + Ch 1 (Managed via Quad 0 Addr) 83 + * PI 1 -> Ch 2 + Ch 3 (Managed via Quad 0 Addr) 84 + * PI 2 -> Ch 4 + Ch 5 (Managed via Quad 1 Addr) 85 + * PI 3 -> Ch 6 + Ch 7 (Managed via Quad 1 Addr) 86 + * (Note: Actual mapping depends on Device Tree and PORT_REMAP config) 87 + */ 88 + 89 + #include <linux/i2c.h> 90 + #include <linux/module.h> 91 + #include <linux/of.h> 92 + #include <linux/platform_device.h> 93 + #include <linux/pse-pd/pse.h> 94 + 95 + #define SI3474_MAX_CHANS 8 96 + 97 + #define MANUFACTURER_ID 0x08 98 + #define IC_ID 0x05 99 + #define SI3474_DEVICE_ID (MANUFACTURER_ID << 3 | IC_ID) 100 + 101 + /* Misc registers */ 102 + #define VENDOR_IC_ID_REG 0x1B 103 + #define TEMPERATURE_REG 0x2C 104 + #define FIRMWARE_REVISION_REG 0x41 105 + #define CHIP_REVISION_REG 0x43 106 + 107 + /* Main status registers */ 108 + #define POWER_STATUS_REG 0x10 109 + #define PORT_MODE_REG 0x12 110 + #define DETECT_CLASS_ENABLE_REG 0x14 111 + 112 + /* PORTn Current */ 113 + #define PORT1_CURRENT_LSB_REG 0x30 114 + 115 + /* PORTn Current [mA], return in [nA] */ 116 + /* 1000 * ((PORTn_CURRENT_MSB << 8) + PORTn_CURRENT_LSB) / 16384 */ 117 + #define SI3474_NA_STEP (1000 * 1000 * 1000 / 16384) 118 + 119 + /* VPWR Voltage */ 120 + #define VPWR_LSB_REG 0x2E 121 + #define VPWR_MSB_REG 0x2F 122 + 123 + /* PORTn Voltage */ 124 + #define PORT1_VOLTAGE_LSB_REG 0x32 125 + 126 + /* VPWR Voltage [V], return in [uV] */ 127 + /* 60 * (( VPWR_MSB << 8) + VPWR_LSB) / 16384 */ 128 + #define SI3474_UV_STEP (1000 * 1000 * 60 / 16384) 129 + 130 + /* Helper macros */ 131 + #define CHAN_IDX(chan) ((chan) % 4) 132 + #define CHAN_BIT(chan) BIT(CHAN_IDX(chan)) 133 + #define CHAN_UPPER_BIT(chan) BIT(CHAN_IDX(chan) + 4) 134 + 135 + #define CHAN_MASK(chan) (0x03U << (2 * CHAN_IDX(chan))) 136 + #define CHAN_REG(base, chan) ((base) + (CHAN_IDX(chan) * 4)) 137 + 138 + struct si3474_pi_desc { 139 + u8 chan[2]; 140 + bool is_4p; 141 + }; 142 + 143 + struct si3474_priv { 144 + struct i2c_client *client[2]; 145 + struct pse_controller_dev pcdev; 146 + struct device_node *np; 147 + struct si3474_pi_desc pi[SI3474_MAX_CHANS]; 148 + }; 149 + 150 + static struct si3474_priv *to_si3474_priv(struct pse_controller_dev *pcdev) 151 + { 152 + return container_of(pcdev, struct si3474_priv, pcdev); 153 + } 154 + 155 + static void si3474_get_channels(struct si3474_priv *priv, int id, 156 + u8 *chan0, u8 *chan1) 157 + { 158 + *chan0 = priv->pi[id].chan[0]; 159 + *chan1 = priv->pi[id].chan[1]; 160 + } 161 + 162 + static struct i2c_client *si3474_get_chan_client(struct si3474_priv *priv, 163 + u8 chan) 164 + { 165 + return (chan < 4) ? priv->client[0] : priv->client[1]; 166 + } 167 + 168 + static int si3474_pi_get_admin_state(struct pse_controller_dev *pcdev, int id, 169 + struct pse_admin_state *admin_state) 170 + { 171 + struct si3474_priv *priv = to_si3474_priv(pcdev); 172 + struct i2c_client *client; 173 + bool is_enabled; 174 + u8 chan0, chan1; 175 + s32 ret; 176 + 177 + si3474_get_channels(priv, id, &chan0, &chan1); 178 + client = si3474_get_chan_client(priv, chan0); 179 + 180 + ret = i2c_smbus_read_byte_data(client, PORT_MODE_REG); 181 + if (ret < 0) { 182 + admin_state->c33_admin_state = 183 + ETHTOOL_C33_PSE_ADMIN_STATE_UNKNOWN; 184 + return ret; 185 + } 186 + 187 + is_enabled = ret & (CHAN_MASK(chan0) | CHAN_MASK(chan1)); 188 + 189 + if (is_enabled) 190 + admin_state->c33_admin_state = 191 + ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED; 192 + else 193 + admin_state->c33_admin_state = 194 + ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED; 195 + 196 + return 0; 197 + } 198 + 199 + static int si3474_pi_get_pw_status(struct pse_controller_dev *pcdev, int id, 200 + struct pse_pw_status *pw_status) 201 + { 202 + struct si3474_priv *priv = to_si3474_priv(pcdev); 203 + struct i2c_client *client; 204 + bool delivering; 205 + u8 chan0, chan1; 206 + s32 ret; 207 + 208 + si3474_get_channels(priv, id, &chan0, &chan1); 209 + client = si3474_get_chan_client(priv, chan0); 210 + 211 + ret = i2c_smbus_read_byte_data(client, POWER_STATUS_REG); 212 + if (ret < 0) { 213 + pw_status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_UNKNOWN; 214 + return ret; 215 + } 216 + 217 + delivering = ret & (CHAN_UPPER_BIT(chan0) | CHAN_UPPER_BIT(chan1)); 218 + 219 + if (delivering) 220 + pw_status->c33_pw_status = 221 + ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING; 222 + else 223 + pw_status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED; 224 + 225 + return 0; 226 + } 227 + 228 + static int si3474_get_of_channels(struct si3474_priv *priv) 229 + { 230 + struct pse_pi *pi; 231 + u32 chan_id; 232 + u8 pi_no; 233 + s32 ret; 234 + 235 + for (pi_no = 0; pi_no < SI3474_MAX_CHANS; pi_no++) { 236 + pi = &priv->pcdev.pi[pi_no]; 237 + bool pairset_found = false; 238 + u8 pairset_no; 239 + 240 + for (pairset_no = 0; pairset_no < 2; pairset_no++) { 241 + if (!pi->pairset[pairset_no].np) 242 + continue; 243 + 244 + pairset_found = true; 245 + 246 + ret = of_property_read_u32(pi->pairset[pairset_no].np, 247 + "reg", &chan_id); 248 + if (ret) { 249 + dev_err(&priv->client[0]->dev, 250 + "Failed to read channel reg property\n"); 251 + return ret; 252 + } 253 + if (chan_id > SI3474_MAX_CHANS) { 254 + dev_err(&priv->client[0]->dev, 255 + "Incorrect channel number: %d\n", chan_id); 256 + return -EINVAL; 257 + } 258 + 259 + priv->pi[pi_no].chan[pairset_no] = chan_id; 260 + /* Mark as 4-pair if second pairset is present */ 261 + priv->pi[pi_no].is_4p = (pairset_no == 1); 262 + } 263 + 264 + if (pairset_found && !priv->pi[pi_no].is_4p) { 265 + dev_err(&priv->client[0]->dev, 266 + "Second pairset is missing for PI %pOF, only 4p configs are supported\n", 267 + pi->np); 268 + return -EINVAL; 269 + } 270 + } 271 + 272 + return 0; 273 + } 274 + 275 + static int si3474_setup_pi_matrix(struct pse_controller_dev *pcdev) 276 + { 277 + struct si3474_priv *priv = to_si3474_priv(pcdev); 278 + s32 ret; 279 + 280 + ret = si3474_get_of_channels(priv); 281 + if (ret < 0) 282 + dev_warn(&priv->client[0]->dev, 283 + "Unable to parse DT PSE power interface matrix\n"); 284 + 285 + return ret; 286 + } 287 + 288 + static int si3474_pi_enable(struct pse_controller_dev *pcdev, int id) 289 + { 290 + struct si3474_priv *priv = to_si3474_priv(pcdev); 291 + struct i2c_client *client; 292 + u8 chan0, chan1; 293 + s32 ret; 294 + u8 val; 295 + 296 + si3474_get_channels(priv, id, &chan0, &chan1); 297 + client = si3474_get_chan_client(priv, chan0); 298 + 299 + /* Release PI from shutdown */ 300 + ret = i2c_smbus_read_byte_data(client, PORT_MODE_REG); 301 + if (ret < 0) 302 + return ret; 303 + 304 + val = (u8)ret; 305 + val |= CHAN_MASK(chan0); 306 + val |= CHAN_MASK(chan1); 307 + 308 + ret = i2c_smbus_write_byte_data(client, PORT_MODE_REG, val); 309 + if (ret) 310 + return ret; 311 + 312 + /* DETECT_CLASS_ENABLE must be set when using AUTO mode, 313 + * otherwise PI does not power up - datasheet section 2.10.2 314 + */ 315 + val = CHAN_BIT(chan0) | CHAN_UPPER_BIT(chan0) | 316 + CHAN_BIT(chan1) | CHAN_UPPER_BIT(chan1); 317 + 318 + ret = i2c_smbus_write_byte_data(client, DETECT_CLASS_ENABLE_REG, val); 319 + if (ret) 320 + return ret; 321 + 322 + return 0; 323 + } 324 + 325 + static int si3474_pi_disable(struct pse_controller_dev *pcdev, int id) 326 + { 327 + struct si3474_priv *priv = to_si3474_priv(pcdev); 328 + struct i2c_client *client; 329 + u8 chan0, chan1; 330 + s32 ret; 331 + u8 val; 332 + 333 + si3474_get_channels(priv, id, &chan0, &chan1); 334 + client = si3474_get_chan_client(priv, chan0); 335 + 336 + /* Set PI in shutdown mode */ 337 + ret = i2c_smbus_read_byte_data(client, PORT_MODE_REG); 338 + if (ret < 0) 339 + return ret; 340 + 341 + val = (u8)ret; 342 + val &= ~CHAN_MASK(chan0); 343 + val &= ~CHAN_MASK(chan1); 344 + 345 + ret = i2c_smbus_write_byte_data(client, PORT_MODE_REG, val); 346 + if (ret) 347 + return ret; 348 + 349 + return 0; 350 + } 351 + 352 + static int si3474_pi_get_chan_current(struct si3474_priv *priv, u8 chan) 353 + { 354 + struct i2c_client *client; 355 + u64 tmp_64; 356 + s32 ret; 357 + u8 reg; 358 + 359 + client = si3474_get_chan_client(priv, chan); 360 + 361 + /* Registers 0x30 to 0x3d */ 362 + reg = CHAN_REG(PORT1_CURRENT_LSB_REG, chan); 363 + 364 + ret = i2c_smbus_read_word_data(client, reg); 365 + if (ret < 0) 366 + return ret; 367 + 368 + tmp_64 = ret * SI3474_NA_STEP; 369 + 370 + /* uA = nA / 1000 */ 371 + tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000); 372 + return (int)tmp_64; 373 + } 374 + 375 + static int si3474_pi_get_chan_voltage(struct si3474_priv *priv, u8 chan) 376 + { 377 + struct i2c_client *client; 378 + s32 ret; 379 + u32 val; 380 + u8 reg; 381 + 382 + client = si3474_get_chan_client(priv, chan); 383 + 384 + /* Registers 0x32 to 0x3f */ 385 + reg = CHAN_REG(PORT1_VOLTAGE_LSB_REG, chan); 386 + 387 + ret = i2c_smbus_read_word_data(client, reg); 388 + if (ret < 0) 389 + return ret; 390 + 391 + val = ret * SI3474_UV_STEP; 392 + 393 + return (int)val; 394 + } 395 + 396 + static int si3474_pi_get_voltage(struct pse_controller_dev *pcdev, int id) 397 + { 398 + struct si3474_priv *priv = to_si3474_priv(pcdev); 399 + struct i2c_client *client; 400 + u8 chan0, chan1; 401 + s32 ret; 402 + 403 + si3474_get_channels(priv, id, &chan0, &chan1); 404 + client = si3474_get_chan_client(priv, chan0); 405 + 406 + /* Check which channels are enabled*/ 407 + ret = i2c_smbus_read_byte_data(client, POWER_STATUS_REG); 408 + if (ret < 0) 409 + return ret; 410 + 411 + /* Take voltage from the first enabled channel */ 412 + if (ret & CHAN_BIT(chan0)) 413 + ret = si3474_pi_get_chan_voltage(priv, chan0); 414 + else if (ret & CHAN_BIT(chan1)) 415 + ret = si3474_pi_get_chan_voltage(priv, chan1); 416 + else 417 + /* 'should' be no voltage in this case */ 418 + return 0; 419 + 420 + return ret; 421 + } 422 + 423 + static int si3474_pi_get_actual_pw(struct pse_controller_dev *pcdev, int id) 424 + { 425 + struct si3474_priv *priv = to_si3474_priv(pcdev); 426 + u8 chan0, chan1; 427 + u32 uV, uA; 428 + u64 tmp_64; 429 + s32 ret; 430 + 431 + ret = si3474_pi_get_voltage(&priv->pcdev, id); 432 + 433 + /* Do not read currents if voltage is 0 */ 434 + if (ret <= 0) 435 + return ret; 436 + uV = ret; 437 + 438 + si3474_get_channels(priv, id, &chan0, &chan1); 439 + 440 + ret = si3474_pi_get_chan_current(priv, chan0); 441 + if (ret < 0) 442 + return ret; 443 + uA = ret; 444 + 445 + ret = si3474_pi_get_chan_current(priv, chan1); 446 + if (ret < 0) 447 + return ret; 448 + uA += ret; 449 + 450 + tmp_64 = uV; 451 + tmp_64 *= uA; 452 + /* mW = uV * uA / 1000000000 */ 453 + return DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000); 454 + } 455 + 456 + static const struct pse_controller_ops si3474_ops = { 457 + .setup_pi_matrix = si3474_setup_pi_matrix, 458 + .pi_enable = si3474_pi_enable, 459 + .pi_disable = si3474_pi_disable, 460 + .pi_get_actual_pw = si3474_pi_get_actual_pw, 461 + .pi_get_voltage = si3474_pi_get_voltage, 462 + .pi_get_admin_state = si3474_pi_get_admin_state, 463 + .pi_get_pw_status = si3474_pi_get_pw_status, 464 + }; 465 + 466 + static void si3474_ancillary_i2c_remove(void *data) 467 + { 468 + struct i2c_client *client = data; 469 + 470 + i2c_unregister_device(client); 471 + } 472 + 473 + static int si3474_i2c_probe(struct i2c_client *client) 474 + { 475 + struct device *dev = &client->dev; 476 + struct si3474_priv *priv; 477 + u8 fw_version; 478 + s32 ret; 479 + 480 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 481 + dev_err(dev, "i2c check functionality failed\n"); 482 + return -ENXIO; 483 + } 484 + 485 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 486 + if (!priv) 487 + return -ENOMEM; 488 + 489 + ret = i2c_smbus_read_byte_data(client, VENDOR_IC_ID_REG); 490 + if (ret < 0) 491 + return ret; 492 + 493 + if (ret != SI3474_DEVICE_ID) { 494 + dev_err(dev, "Wrong device ID: 0x%x\n", ret); 495 + return -ENXIO; 496 + } 497 + 498 + ret = i2c_smbus_read_byte_data(client, FIRMWARE_REVISION_REG); 499 + if (ret < 0) 500 + return ret; 501 + fw_version = ret; 502 + 503 + ret = i2c_smbus_read_byte_data(client, CHIP_REVISION_REG); 504 + if (ret < 0) 505 + return ret; 506 + 507 + dev_dbg(dev, "Chip revision: 0x%x, firmware version: 0x%x\n", 508 + ret, fw_version); 509 + 510 + priv->client[0] = client; 511 + i2c_set_clientdata(client, priv); 512 + 513 + priv->client[1] = i2c_new_ancillary_device(priv->client[0], "secondary", 514 + priv->client[0]->addr + 1); 515 + if (IS_ERR(priv->client[1])) 516 + return PTR_ERR(priv->client[1]); 517 + 518 + ret = devm_add_action_or_reset(dev, si3474_ancillary_i2c_remove, priv->client[1]); 519 + if (ret < 0) { 520 + dev_err(&priv->client[1]->dev, "Cannot register remove callback\n"); 521 + return ret; 522 + } 523 + 524 + ret = i2c_smbus_read_byte_data(priv->client[1], VENDOR_IC_ID_REG); 525 + if (ret < 0) { 526 + dev_err(&priv->client[1]->dev, "Cannot access secondary PSE controller\n"); 527 + return ret; 528 + } 529 + 530 + if (ret != SI3474_DEVICE_ID) { 531 + dev_err(&priv->client[1]->dev, 532 + "Wrong device ID for secondary PSE controller: 0x%x\n", ret); 533 + return -ENXIO; 534 + } 535 + 536 + priv->np = dev->of_node; 537 + priv->pcdev.owner = THIS_MODULE; 538 + priv->pcdev.ops = &si3474_ops; 539 + priv->pcdev.dev = dev; 540 + priv->pcdev.types = ETHTOOL_PSE_C33; 541 + priv->pcdev.nr_lines = SI3474_MAX_CHANS; 542 + 543 + ret = devm_pse_controller_register(dev, &priv->pcdev); 544 + if (ret) { 545 + dev_err(dev, "Failed to register PSE controller: 0x%x\n", ret); 546 + return ret; 547 + } 548 + 549 + return 0; 550 + } 551 + 552 + static const struct i2c_device_id si3474_id[] = { 553 + { "si3474" }, 554 + {} 555 + }; 556 + MODULE_DEVICE_TABLE(i2c, si3474_id); 557 + 558 + static const struct of_device_id si3474_of_match[] = { 559 + { 560 + .compatible = "skyworks,si3474", 561 + }, 562 + {}, 563 + }; 564 + MODULE_DEVICE_TABLE(of, si3474_of_match); 565 + 566 + static struct i2c_driver si3474_driver = { 567 + .probe = si3474_i2c_probe, 568 + .id_table = si3474_id, 569 + .driver = { 570 + .name = "si3474", 571 + .of_match_table = si3474_of_match, 572 + }, 573 + }; 574 + module_i2c_driver(si3474_driver); 575 + 576 + MODULE_AUTHOR("Piotr Kubik <piotr.kubik@adtran.com>"); 577 + MODULE_DESCRIPTION("Skyworks Si3474 PoE PSE Controller driver"); 578 + MODULE_LICENSE("GPL");