| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * mag3110.c - Support for Freescale MAG3110 magnetometer sensor |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This file is subject to the terms and conditions of version 2 of |
|---|
| 7 | | - * the GNU General Public License. See the file COPYING in the main |
|---|
| 8 | | - * directory of this archive for more details. |
|---|
| 9 | 6 | * |
|---|
| 10 | 7 | * (7-bit I2C slave address 0x0e) |
|---|
| 11 | 8 | * |
|---|
| .. | .. |
|---|
| 20 | 17 | #include <linux/iio/buffer.h> |
|---|
| 21 | 18 | #include <linux/iio/triggered_buffer.h> |
|---|
| 22 | 19 | #include <linux/delay.h> |
|---|
| 20 | +#include <linux/regulator/consumer.h> |
|---|
| 23 | 21 | |
|---|
| 24 | 22 | #define MAG3110_STATUS 0x00 |
|---|
| 25 | 23 | #define MAG3110_OUT_X 0x01 /* MSB first */ |
|---|
| .. | .. |
|---|
| 56 | 54 | struct mutex lock; |
|---|
| 57 | 55 | u8 ctrl_reg1; |
|---|
| 58 | 56 | int sleep_val; |
|---|
| 57 | + struct regulator *vdd_reg; |
|---|
| 58 | + struct regulator *vddio_reg; |
|---|
| 59 | 59 | /* Ensure natural alignment of timestamp */ |
|---|
| 60 | 60 | struct { |
|---|
| 61 | 61 | __be16 channels[3]; |
|---|
| .. | .. |
|---|
| 474 | 474 | struct iio_dev *indio_dev; |
|---|
| 475 | 475 | int ret; |
|---|
| 476 | 476 | |
|---|
| 477 | | - ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I); |
|---|
| 478 | | - if (ret < 0) |
|---|
| 479 | | - return ret; |
|---|
| 480 | | - if (ret != MAG3110_DEVICE_ID) |
|---|
| 481 | | - return -ENODEV; |
|---|
| 482 | | - |
|---|
| 483 | 477 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
|---|
| 484 | 478 | if (!indio_dev) |
|---|
| 485 | 479 | return -ENOMEM; |
|---|
| 486 | 480 | |
|---|
| 487 | 481 | data = iio_priv(indio_dev); |
|---|
| 482 | + |
|---|
| 483 | + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); |
|---|
| 484 | + if (IS_ERR(data->vdd_reg)) |
|---|
| 485 | + return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg), |
|---|
| 486 | + "failed to get VDD regulator!\n"); |
|---|
| 487 | + |
|---|
| 488 | + data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); |
|---|
| 489 | + if (IS_ERR(data->vddio_reg)) |
|---|
| 490 | + return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg), |
|---|
| 491 | + "failed to get VDDIO regulator!\n"); |
|---|
| 492 | + |
|---|
| 493 | + ret = regulator_enable(data->vdd_reg); |
|---|
| 494 | + if (ret) { |
|---|
| 495 | + dev_err(&client->dev, "failed to enable VDD regulator!\n"); |
|---|
| 496 | + return ret; |
|---|
| 497 | + } |
|---|
| 498 | + |
|---|
| 499 | + ret = regulator_enable(data->vddio_reg); |
|---|
| 500 | + if (ret) { |
|---|
| 501 | + dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); |
|---|
| 502 | + goto disable_regulator_vdd; |
|---|
| 503 | + } |
|---|
| 504 | + |
|---|
| 505 | + ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I); |
|---|
| 506 | + if (ret < 0) |
|---|
| 507 | + goto disable_regulators; |
|---|
| 508 | + if (ret != MAG3110_DEVICE_ID) { |
|---|
| 509 | + ret = -ENODEV; |
|---|
| 510 | + goto disable_regulators; |
|---|
| 511 | + } |
|---|
| 512 | + |
|---|
| 488 | 513 | data->client = client; |
|---|
| 489 | 514 | mutex_init(&data->lock); |
|---|
| 490 | 515 | |
|---|
| 491 | 516 | i2c_set_clientdata(client, indio_dev); |
|---|
| 492 | 517 | indio_dev->info = &mag3110_info; |
|---|
| 493 | 518 | indio_dev->name = id->name; |
|---|
| 494 | | - indio_dev->dev.parent = &client->dev; |
|---|
| 495 | 519 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 496 | 520 | indio_dev->channels = mag3110_channels; |
|---|
| 497 | 521 | indio_dev->num_channels = ARRAY_SIZE(mag3110_channels); |
|---|
| .. | .. |
|---|
| 504 | 528 | |
|---|
| 505 | 529 | ret = mag3110_change_config(data, MAG3110_CTRL_REG1, data->ctrl_reg1); |
|---|
| 506 | 530 | if (ret < 0) |
|---|
| 507 | | - return ret; |
|---|
| 531 | + goto disable_regulators; |
|---|
| 508 | 532 | |
|---|
| 509 | 533 | ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2, |
|---|
| 510 | 534 | MAG3110_CTRL_AUTO_MRST_EN); |
|---|
| .. | .. |
|---|
| 525 | 549 | iio_triggered_buffer_cleanup(indio_dev); |
|---|
| 526 | 550 | standby_on_error: |
|---|
| 527 | 551 | mag3110_standby(iio_priv(indio_dev)); |
|---|
| 552 | +disable_regulators: |
|---|
| 553 | + regulator_disable(data->vddio_reg); |
|---|
| 554 | +disable_regulator_vdd: |
|---|
| 555 | + regulator_disable(data->vdd_reg); |
|---|
| 556 | + |
|---|
| 528 | 557 | return ret; |
|---|
| 529 | 558 | } |
|---|
| 530 | 559 | |
|---|
| 531 | 560 | static int mag3110_remove(struct i2c_client *client) |
|---|
| 532 | 561 | { |
|---|
| 533 | 562 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
|---|
| 563 | + struct mag3110_data *data = iio_priv(indio_dev); |
|---|
| 534 | 564 | |
|---|
| 535 | 565 | iio_device_unregister(indio_dev); |
|---|
| 536 | 566 | iio_triggered_buffer_cleanup(indio_dev); |
|---|
| 537 | 567 | mag3110_standby(iio_priv(indio_dev)); |
|---|
| 568 | + regulator_disable(data->vddio_reg); |
|---|
| 569 | + regulator_disable(data->vdd_reg); |
|---|
| 538 | 570 | |
|---|
| 539 | 571 | return 0; |
|---|
| 540 | 572 | } |
|---|
| .. | .. |
|---|
| 542 | 574 | #ifdef CONFIG_PM_SLEEP |
|---|
| 543 | 575 | static int mag3110_suspend(struct device *dev) |
|---|
| 544 | 576 | { |
|---|
| 545 | | - return mag3110_standby(iio_priv(i2c_get_clientdata( |
|---|
| 577 | + struct mag3110_data *data = iio_priv(i2c_get_clientdata( |
|---|
| 578 | + to_i2c_client(dev))); |
|---|
| 579 | + int ret; |
|---|
| 580 | + |
|---|
| 581 | + ret = mag3110_standby(iio_priv(i2c_get_clientdata( |
|---|
| 546 | 582 | to_i2c_client(dev)))); |
|---|
| 583 | + if (ret) |
|---|
| 584 | + return ret; |
|---|
| 585 | + |
|---|
| 586 | + ret = regulator_disable(data->vddio_reg); |
|---|
| 587 | + if (ret) { |
|---|
| 588 | + dev_err(dev, "failed to disable VDDIO regulator\n"); |
|---|
| 589 | + return ret; |
|---|
| 590 | + } |
|---|
| 591 | + |
|---|
| 592 | + ret = regulator_disable(data->vdd_reg); |
|---|
| 593 | + if (ret) { |
|---|
| 594 | + dev_err(dev, "failed to disable VDD regulator\n"); |
|---|
| 595 | + return ret; |
|---|
| 596 | + } |
|---|
| 597 | + |
|---|
| 598 | + return 0; |
|---|
| 547 | 599 | } |
|---|
| 548 | 600 | |
|---|
| 549 | 601 | static int mag3110_resume(struct device *dev) |
|---|
| 550 | 602 | { |
|---|
| 551 | 603 | struct mag3110_data *data = iio_priv(i2c_get_clientdata( |
|---|
| 552 | 604 | to_i2c_client(dev))); |
|---|
| 605 | + int ret; |
|---|
| 606 | + |
|---|
| 607 | + ret = regulator_enable(data->vdd_reg); |
|---|
| 608 | + if (ret) { |
|---|
| 609 | + dev_err(dev, "failed to enable VDD regulator\n"); |
|---|
| 610 | + return ret; |
|---|
| 611 | + } |
|---|
| 612 | + |
|---|
| 613 | + ret = regulator_enable(data->vddio_reg); |
|---|
| 614 | + if (ret) { |
|---|
| 615 | + dev_err(dev, "failed to enable VDDIO regulator\n"); |
|---|
| 616 | + regulator_disable(data->vdd_reg); |
|---|
| 617 | + return ret; |
|---|
| 618 | + } |
|---|
| 553 | 619 | |
|---|
| 554 | 620 | return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1, |
|---|
| 555 | 621 | data->ctrl_reg1); |
|---|