.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * I2C multiplexer |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> |
---|
5 | 6 | * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> |
---|
6 | 7 | * |
---|
7 | | - * This module supports the PCA954x and PCA954x series of I2C multiplexer/switch |
---|
| 8 | + * This module supports the PCA954x and PCA984x series of I2C multiplexer/switch |
---|
8 | 9 | * chips made by NXP Semiconductors. |
---|
9 | 10 | * This includes the: |
---|
10 | 11 | * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547, |
---|
.. | .. |
---|
29 | 30 | * i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com> |
---|
30 | 31 | * and |
---|
31 | 32 | * pca9540.c from Jean Delvare <jdelvare@suse.de>. |
---|
32 | | - * |
---|
33 | | - * This file is licensed under the terms of the GNU General Public |
---|
34 | | - * License version 2. This program is licensed "as is" without any |
---|
35 | | - * warranty of any kind, whether express or implied. |
---|
36 | 33 | */ |
---|
37 | 34 | |
---|
38 | 35 | #include <linux/device.h> |
---|
.. | .. |
---|
43 | 40 | #include <linux/interrupt.h> |
---|
44 | 41 | #include <linux/irq.h> |
---|
45 | 42 | #include <linux/module.h> |
---|
46 | | -#include <linux/of.h> |
---|
47 | | -#include <linux/of_device.h> |
---|
48 | | -#include <linux/of_irq.h> |
---|
49 | | -#include <linux/platform_data/pca954x.h> |
---|
50 | 43 | #include <linux/pm.h> |
---|
| 44 | +#include <linux/property.h> |
---|
51 | 45 | #include <linux/slab.h> |
---|
52 | 46 | #include <linux/spinlock.h> |
---|
| 47 | +#include <dt-bindings/mux/mux.h> |
---|
53 | 48 | |
---|
54 | 49 | #define PCA954X_MAX_NCHANS 8 |
---|
55 | 50 | |
---|
.. | .. |
---|
85 | 80 | const struct chip_desc *chip; |
---|
86 | 81 | |
---|
87 | 82 | u8 last_chan; /* last register value */ |
---|
88 | | - u8 deselect; |
---|
| 83 | + /* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */ |
---|
| 84 | + s32 idle_state; |
---|
| 85 | + |
---|
89 | 86 | struct i2c_client *client; |
---|
90 | 87 | |
---|
91 | 88 | struct irq_domain *irq; |
---|
.. | .. |
---|
196 | 193 | }; |
---|
197 | 194 | MODULE_DEVICE_TABLE(i2c, pca954x_id); |
---|
198 | 195 | |
---|
199 | | -#ifdef CONFIG_OF |
---|
200 | 196 | static const struct of_device_id pca954x_of_match[] = { |
---|
201 | 197 | { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, |
---|
202 | 198 | { .compatible = "nxp,pca9542", .data = &chips[pca_9542] }, |
---|
.. | .. |
---|
213 | 209 | {} |
---|
214 | 210 | }; |
---|
215 | 211 | MODULE_DEVICE_TABLE(of, pca954x_of_match); |
---|
216 | | -#endif |
---|
217 | 212 | |
---|
218 | 213 | /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() |
---|
219 | 214 | for this as they will try to lock adapter a second time */ |
---|
.. | .. |
---|
227 | 222 | I2C_SMBUS_BYTE, &dummy); |
---|
228 | 223 | } |
---|
229 | 224 | |
---|
| 225 | +static u8 pca954x_regval(struct pca954x *data, u8 chan) |
---|
| 226 | +{ |
---|
| 227 | + /* We make switches look like muxes, not sure how to be smarter. */ |
---|
| 228 | + if (data->chip->muxtype == pca954x_ismux) |
---|
| 229 | + return chan | data->chip->enable; |
---|
| 230 | + else |
---|
| 231 | + return 1 << chan; |
---|
| 232 | +} |
---|
| 233 | + |
---|
230 | 234 | static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) |
---|
231 | 235 | { |
---|
232 | 236 | struct pca954x *data = i2c_mux_priv(muxc); |
---|
233 | 237 | struct i2c_client *client = data->client; |
---|
234 | | - const struct chip_desc *chip = data->chip; |
---|
235 | 238 | u8 regval; |
---|
236 | 239 | int ret = 0; |
---|
237 | 240 | |
---|
238 | | - /* we make switches look like muxes, not sure how to be smarter */ |
---|
239 | | - if (chip->muxtype == pca954x_ismux) |
---|
240 | | - regval = chan | chip->enable; |
---|
241 | | - else |
---|
242 | | - regval = 1 << chan; |
---|
243 | | - |
---|
| 241 | + regval = pca954x_regval(data, chan); |
---|
244 | 242 | /* Only select the channel if its different from the last channel */ |
---|
245 | 243 | if (data->last_chan != regval) { |
---|
246 | 244 | ret = pca954x_reg_write(muxc->parent, client, regval); |
---|
.. | .. |
---|
254 | 252 | { |
---|
255 | 253 | struct pca954x *data = i2c_mux_priv(muxc); |
---|
256 | 254 | struct i2c_client *client = data->client; |
---|
| 255 | + s32 idle_state; |
---|
257 | 256 | |
---|
258 | | - if (!(data->deselect & (1 << chan))) |
---|
259 | | - return 0; |
---|
| 257 | + idle_state = READ_ONCE(data->idle_state); |
---|
| 258 | + if (idle_state >= 0) |
---|
| 259 | + /* Set the mux back to a predetermined channel */ |
---|
| 260 | + return pca954x_select_chan(muxc, idle_state); |
---|
260 | 261 | |
---|
261 | | - /* Deselect active channel */ |
---|
262 | | - data->last_chan = 0; |
---|
263 | | - return pca954x_reg_write(muxc->parent, client, data->last_chan); |
---|
| 262 | + if (idle_state == MUX_IDLE_DISCONNECT) { |
---|
| 263 | + /* Deselect active channel */ |
---|
| 264 | + data->last_chan = 0; |
---|
| 265 | + return pca954x_reg_write(muxc->parent, client, |
---|
| 266 | + data->last_chan); |
---|
| 267 | + } |
---|
| 268 | + |
---|
| 269 | + /* otherwise leave as-is */ |
---|
| 270 | + |
---|
| 271 | + return 0; |
---|
264 | 272 | } |
---|
| 273 | + |
---|
| 274 | +static ssize_t idle_state_show(struct device *dev, |
---|
| 275 | + struct device_attribute *attr, |
---|
| 276 | + char *buf) |
---|
| 277 | +{ |
---|
| 278 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 279 | + struct i2c_mux_core *muxc = i2c_get_clientdata(client); |
---|
| 280 | + struct pca954x *data = i2c_mux_priv(muxc); |
---|
| 281 | + |
---|
| 282 | + return sprintf(buf, "%d\n", READ_ONCE(data->idle_state)); |
---|
| 283 | +} |
---|
| 284 | + |
---|
| 285 | +static ssize_t idle_state_store(struct device *dev, |
---|
| 286 | + struct device_attribute *attr, |
---|
| 287 | + const char *buf, size_t count) |
---|
| 288 | +{ |
---|
| 289 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 290 | + struct i2c_mux_core *muxc = i2c_get_clientdata(client); |
---|
| 291 | + struct pca954x *data = i2c_mux_priv(muxc); |
---|
| 292 | + int val; |
---|
| 293 | + int ret; |
---|
| 294 | + |
---|
| 295 | + ret = kstrtoint(buf, 0, &val); |
---|
| 296 | + if (ret < 0) |
---|
| 297 | + return ret; |
---|
| 298 | + |
---|
| 299 | + if (val != MUX_IDLE_AS_IS && val != MUX_IDLE_DISCONNECT && |
---|
| 300 | + (val < 0 || val >= data->chip->nchans)) |
---|
| 301 | + return -EINVAL; |
---|
| 302 | + |
---|
| 303 | + i2c_lock_bus(muxc->parent, I2C_LOCK_SEGMENT); |
---|
| 304 | + |
---|
| 305 | + WRITE_ONCE(data->idle_state, val); |
---|
| 306 | + /* |
---|
| 307 | + * Set the mux into a state consistent with the new |
---|
| 308 | + * idle_state. |
---|
| 309 | + */ |
---|
| 310 | + if (data->last_chan || val != MUX_IDLE_DISCONNECT) |
---|
| 311 | + ret = pca954x_deselect_mux(muxc, 0); |
---|
| 312 | + |
---|
| 313 | + i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT); |
---|
| 314 | + |
---|
| 315 | + return ret < 0 ? ret : count; |
---|
| 316 | +} |
---|
| 317 | + |
---|
| 318 | +static DEVICE_ATTR_RW(idle_state); |
---|
265 | 319 | |
---|
266 | 320 | static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) |
---|
267 | 321 | { |
---|
268 | 322 | struct pca954x *data = dev_id; |
---|
269 | | - unsigned int child_irq; |
---|
270 | | - int ret, i, handled = 0; |
---|
| 323 | + unsigned long pending; |
---|
| 324 | + int ret, i; |
---|
271 | 325 | |
---|
272 | 326 | ret = i2c_smbus_read_byte(data->client); |
---|
273 | 327 | if (ret < 0) |
---|
274 | 328 | return IRQ_NONE; |
---|
275 | 329 | |
---|
276 | | - for (i = 0; i < data->chip->nchans; i++) { |
---|
277 | | - if (ret & BIT(PCA954X_IRQ_OFFSET + i)) { |
---|
278 | | - child_irq = irq_linear_revmap(data->irq, i); |
---|
279 | | - handle_nested_irq(child_irq); |
---|
280 | | - handled++; |
---|
281 | | - } |
---|
282 | | - } |
---|
283 | | - return handled ? IRQ_HANDLED : IRQ_NONE; |
---|
| 330 | + pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1); |
---|
| 331 | + for_each_set_bit(i, &pending, data->chip->nchans) |
---|
| 332 | + handle_nested_irq(irq_linear_revmap(data->irq, i)); |
---|
| 333 | + |
---|
| 334 | + return IRQ_RETVAL(pending); |
---|
284 | 335 | } |
---|
285 | 336 | |
---|
286 | 337 | static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) |
---|
.. | .. |
---|
341 | 392 | i2c_mux_del_adapters(muxc); |
---|
342 | 393 | } |
---|
343 | 394 | |
---|
| 395 | +static int pca954x_init(struct i2c_client *client, struct pca954x *data) |
---|
| 396 | +{ |
---|
| 397 | + int ret; |
---|
| 398 | + |
---|
| 399 | + if (data->idle_state >= 0) |
---|
| 400 | + data->last_chan = pca954x_regval(data, data->idle_state); |
---|
| 401 | + else |
---|
| 402 | + data->last_chan = 0; /* Disconnect multiplexer */ |
---|
| 403 | + |
---|
| 404 | + ret = i2c_smbus_write_byte(client, data->last_chan); |
---|
| 405 | + if (ret < 0) |
---|
| 406 | + data->last_chan = 0; |
---|
| 407 | + |
---|
| 408 | + return ret; |
---|
| 409 | +} |
---|
| 410 | + |
---|
344 | 411 | /* |
---|
345 | 412 | * I2C init/probing/exit functions |
---|
346 | 413 | */ |
---|
347 | 414 | static int pca954x_probe(struct i2c_client *client, |
---|
348 | 415 | const struct i2c_device_id *id) |
---|
349 | 416 | { |
---|
350 | | - struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); |
---|
351 | | - struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); |
---|
| 417 | + struct i2c_adapter *adap = client->adapter; |
---|
352 | 418 | struct device *dev = &client->dev; |
---|
353 | | - struct device_node *np = dev->of_node; |
---|
354 | | - bool idle_disconnect_dt; |
---|
355 | 419 | struct gpio_desc *gpio; |
---|
356 | | - int num, force, class; |
---|
357 | 420 | struct i2c_mux_core *muxc; |
---|
358 | 421 | struct pca954x *data; |
---|
| 422 | + int num; |
---|
359 | 423 | int ret; |
---|
360 | 424 | |
---|
361 | 425 | if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) |
---|
.. | .. |
---|
381 | 445 | udelay(1); |
---|
382 | 446 | } |
---|
383 | 447 | |
---|
384 | | - data->chip = of_device_get_match_data(dev); |
---|
| 448 | + data->chip = device_get_match_data(dev); |
---|
385 | 449 | if (!data->chip) |
---|
386 | 450 | data->chip = &chips[id->driver_data]; |
---|
387 | 451 | |
---|
.. | .. |
---|
402 | 466 | } |
---|
403 | 467 | } |
---|
404 | 468 | |
---|
405 | | - /* Write the mux register at addr to verify |
---|
| 469 | + data->idle_state = MUX_IDLE_AS_IS; |
---|
| 470 | + if (device_property_read_u32(dev, "idle-state", &data->idle_state)) { |
---|
| 471 | + if (device_property_read_bool(dev, "i2c-mux-idle-disconnect")) |
---|
| 472 | + data->idle_state = MUX_IDLE_DISCONNECT; |
---|
| 473 | + } |
---|
| 474 | + |
---|
| 475 | + /* |
---|
| 476 | + * Write the mux register at addr to verify |
---|
406 | 477 | * that the mux is in fact present. This also |
---|
407 | | - * initializes the mux to disconnected state. |
---|
| 478 | + * initializes the mux to a channel |
---|
| 479 | + * or disconnected state. |
---|
408 | 480 | */ |
---|
409 | | - if (i2c_smbus_write_byte(client, 0) < 0) { |
---|
| 481 | + ret = pca954x_init(client, data); |
---|
| 482 | + if (ret < 0) { |
---|
410 | 483 | dev_warn(dev, "probe failed\n"); |
---|
411 | 484 | return -ENODEV; |
---|
412 | 485 | } |
---|
413 | | - |
---|
414 | | - data->last_chan = 0; /* force the first selection */ |
---|
415 | | - |
---|
416 | | - idle_disconnect_dt = np && |
---|
417 | | - of_property_read_bool(np, "i2c-mux-idle-disconnect"); |
---|
418 | 486 | |
---|
419 | 487 | ret = pca954x_irq_setup(muxc); |
---|
420 | 488 | if (ret) |
---|
.. | .. |
---|
422 | 490 | |
---|
423 | 491 | /* Now create an adapter for each channel */ |
---|
424 | 492 | for (num = 0; num < data->chip->nchans; num++) { |
---|
425 | | - bool idle_disconnect_pd = false; |
---|
426 | | - |
---|
427 | | - force = 0; /* dynamic adap number */ |
---|
428 | | - class = 0; /* no class by default */ |
---|
429 | | - if (pdata) { |
---|
430 | | - if (num < pdata->num_modes) { |
---|
431 | | - /* force static number */ |
---|
432 | | - force = pdata->modes[num].adap_id; |
---|
433 | | - class = pdata->modes[num].class; |
---|
434 | | - } else |
---|
435 | | - /* discard unconfigured channels */ |
---|
436 | | - break; |
---|
437 | | - idle_disconnect_pd = pdata->modes[num].deselect_on_exit; |
---|
438 | | - } |
---|
439 | | - data->deselect |= (idle_disconnect_pd || |
---|
440 | | - idle_disconnect_dt) << num; |
---|
441 | | - |
---|
442 | | - ret = i2c_mux_add_adapter(muxc, force, num, class); |
---|
| 493 | + ret = i2c_mux_add_adapter(muxc, 0, num, 0); |
---|
443 | 494 | if (ret) |
---|
444 | 495 | goto fail_cleanup; |
---|
445 | 496 | } |
---|
.. | .. |
---|
452 | 503 | if (ret) |
---|
453 | 504 | goto fail_cleanup; |
---|
454 | 505 | } |
---|
| 506 | + |
---|
| 507 | + /* |
---|
| 508 | + * The attr probably isn't going to be needed in most cases, |
---|
| 509 | + * so don't fail completely on error. |
---|
| 510 | + */ |
---|
| 511 | + device_create_file(dev, &dev_attr_idle_state); |
---|
455 | 512 | |
---|
456 | 513 | dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n", |
---|
457 | 514 | num, data->chip->muxtype == pca954x_ismux |
---|
.. | .. |
---|
468 | 525 | { |
---|
469 | 526 | struct i2c_mux_core *muxc = i2c_get_clientdata(client); |
---|
470 | 527 | |
---|
| 528 | + device_remove_file(&client->dev, &dev_attr_idle_state); |
---|
| 529 | + |
---|
471 | 530 | pca954x_cleanup(muxc); |
---|
472 | 531 | return 0; |
---|
473 | 532 | } |
---|
.. | .. |
---|
478 | 537 | struct i2c_client *client = to_i2c_client(dev); |
---|
479 | 538 | struct i2c_mux_core *muxc = i2c_get_clientdata(client); |
---|
480 | 539 | struct pca954x *data = i2c_mux_priv(muxc); |
---|
| 540 | + int ret; |
---|
481 | 541 | |
---|
482 | | - data->last_chan = 0; |
---|
483 | | - return i2c_smbus_write_byte(client, 0); |
---|
| 542 | + ret = pca954x_init(client, data); |
---|
| 543 | + if (ret < 0) |
---|
| 544 | + dev_err(&client->dev, "failed to verify mux presence\n"); |
---|
| 545 | + |
---|
| 546 | + return ret; |
---|
484 | 547 | } |
---|
485 | 548 | #endif |
---|
486 | 549 | |
---|
.. | .. |
---|
490 | 553 | .driver = { |
---|
491 | 554 | .name = "pca954x", |
---|
492 | 555 | .pm = &pca954x_pm, |
---|
493 | | - .of_match_table = of_match_ptr(pca954x_of_match), |
---|
| 556 | + .of_match_table = pca954x_of_match, |
---|
494 | 557 | }, |
---|
495 | 558 | .probe = pca954x_probe, |
---|
496 | 559 | .remove = pca954x_remove, |
---|