1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de> |
4 | */ |
5 | #include <linux/kernel.h> |
6 | #include <linux/module.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/of.h> |
9 | |
10 | #include "lan9303.h" |
11 | |
12 | struct lan9303_i2c { |
13 | struct i2c_client *device; |
14 | struct lan9303 chip; |
15 | }; |
16 | |
17 | static const struct regmap_config lan9303_i2c_regmap_config = { |
18 | .reg_bits = 8, |
19 | .val_bits = 32, |
20 | .reg_stride = 1, |
21 | .can_multi_write = true, |
22 | .max_register = 0x0ff, /* address bits 0..1 are not used */ |
23 | .reg_format_endian = REGMAP_ENDIAN_LITTLE, |
24 | |
25 | .volatile_table = &lan9303_register_set, |
26 | .wr_table = &lan9303_register_set, |
27 | .rd_table = &lan9303_register_set, |
28 | |
29 | .cache_type = REGCACHE_NONE, |
30 | }; |
31 | |
32 | static int lan9303_i2c_probe(struct i2c_client *client) |
33 | { |
34 | struct lan9303_i2c *sw_dev; |
35 | int ret; |
36 | |
37 | sw_dev = devm_kzalloc(dev: &client->dev, size: sizeof(struct lan9303_i2c), |
38 | GFP_KERNEL); |
39 | if (!sw_dev) |
40 | return -ENOMEM; |
41 | |
42 | sw_dev->chip.regmap = devm_regmap_init_i2c(client, |
43 | &lan9303_i2c_regmap_config); |
44 | if (IS_ERR(ptr: sw_dev->chip.regmap)) { |
45 | ret = PTR_ERR(ptr: sw_dev->chip.regmap); |
46 | dev_err(&client->dev, "Failed to allocate register map: %d\n" , |
47 | ret); |
48 | return ret; |
49 | } |
50 | |
51 | /* link forward and backward */ |
52 | sw_dev->device = client; |
53 | i2c_set_clientdata(client, data: sw_dev); |
54 | sw_dev->chip.dev = &client->dev; |
55 | |
56 | sw_dev->chip.ops = &lan9303_indirect_phy_ops; |
57 | |
58 | ret = lan9303_probe(chip: &sw_dev->chip, np: client->dev.of_node); |
59 | if (ret != 0) |
60 | return ret; |
61 | |
62 | dev_info(&client->dev, "LAN9303 I2C driver loaded successfully\n" ); |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | static void lan9303_i2c_remove(struct i2c_client *client) |
68 | { |
69 | struct lan9303_i2c *sw_dev = i2c_get_clientdata(client); |
70 | |
71 | if (!sw_dev) |
72 | return; |
73 | |
74 | lan9303_remove(chip: &sw_dev->chip); |
75 | } |
76 | |
77 | static void lan9303_i2c_shutdown(struct i2c_client *client) |
78 | { |
79 | struct lan9303_i2c *sw_dev = i2c_get_clientdata(client); |
80 | |
81 | if (!sw_dev) |
82 | return; |
83 | |
84 | lan9303_shutdown(chip: &sw_dev->chip); |
85 | |
86 | i2c_set_clientdata(client, NULL); |
87 | } |
88 | |
89 | /*-------------------------------------------------------------------------*/ |
90 | |
91 | static const struct i2c_device_id lan9303_i2c_id[] = { |
92 | { "lan9303" , 0 }, |
93 | { /* sentinel */ } |
94 | }; |
95 | MODULE_DEVICE_TABLE(i2c, lan9303_i2c_id); |
96 | |
97 | static const struct of_device_id lan9303_i2c_of_match[] = { |
98 | { .compatible = "smsc,lan9303-i2c" , }, |
99 | { /* sentinel */ }, |
100 | }; |
101 | MODULE_DEVICE_TABLE(of, lan9303_i2c_of_match); |
102 | |
103 | static struct i2c_driver lan9303_i2c_driver = { |
104 | .driver = { |
105 | .name = "LAN9303_I2C" , |
106 | .of_match_table = lan9303_i2c_of_match, |
107 | }, |
108 | .probe = lan9303_i2c_probe, |
109 | .remove = lan9303_i2c_remove, |
110 | .shutdown = lan9303_i2c_shutdown, |
111 | .id_table = lan9303_i2c_id, |
112 | }; |
113 | module_i2c_driver(lan9303_i2c_driver); |
114 | |
115 | MODULE_AUTHOR("Juergen Borleis <kernel@pengutronix.de>" ); |
116 | MODULE_DESCRIPTION("Driver for SMSC/Microchip LAN9303 three port ethernet switch in I2C managed mode" ); |
117 | MODULE_LICENSE("GPL v2" ); |
118 | |