* Re: [PATCH] HID: force setting drvdata to NULL when removing the driver
From: Benjamin Tissoires @ 2019-04-02 14:00 UTC (permalink / raw)
To: Hans de Goede
Cc: Dmitry Torokhov, Jiri Kosina, Bruno Prémont,
Jonathan Cameron, Srinivas Pandruvada, Jason Gerecke, Ping Cheng,
linux-input@vger.kernel.org, lkml
In-Reply-To: <a31a6f95-924a-4930-e4df-5576abc694fb@redhat.com>
On Tue, Apr 2, 2019 at 3:52 PM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 02-04-19 15:44, Benjamin Tissoires wrote:
> > Hi Dmitry,
> >
> > On Fri, Mar 29, 2019 at 11:26 PM Dmitry Torokhov
> > <dmitry.torokhov@gmail.com> wrote:
> >>
> >> Hi Benjamin,
> >>
> >> On Thu, Mar 28, 2019 at 8:52 AM Benjamin Tissoires
> >> <benjamin.tissoires@redhat.com> wrote:
> >>>
> >>> Or when the probe failed.
> >>>
> >>> This is a common pattern in the HID drivers to reset the drvdata. Some
> >>> do it properly, some do it only in case of failure.
> >>> Anyway, it's never a good thing to have breadcrumbs, so force a clean
> >>> state when removing or when probe is failing.
> >>
> >> Just a data point: driver core already clears drvdata, so as long as
> >> dev_get/set_drvdata() is the same as hid_get/set_drvdata() no special
> >> handling is needed in HID core.
> >
> > You are correct (as always ;-P). I'll drop the hid-core changes and
> > send a v2 ASAP.
>
> I was just looking at the same thing. I should have known about this
> since I wrote the patch to make the core clear drvdata. I should have
> mentioned that, but I was assuming that the hid code was special somehow,
> however now I see it just uses a regular device_add, so indeed the core
> changes are not necessary.
>
> Given the large hid-logitech-*.c patch-set it might be easier for
> Jiri if you split out the hid-logitech-*.c changes into a separate
> patch, then he can keep that on his logitech branch (just a thought).
>
I do not expect the logitech changes to now create some big conflict.
But looking at the current for-5.2* branches, I should probably split
the series per driver given that there is no more dependency on
hid-core. This way, we can take the logitech changes in the
for-5.2/logitech branch, and you can rebase your work on top of it.
Cheers,
Benjamin
> Regards,
>
> Hans
>
>
> >
> > Cheers,
> > Benjamin
> >
> >>
> >> Thanks.
> >>
> >> --
> >> Dmitry
> >>
> >> On Thu, Mar 28, 2019 at 8:52 AM Benjamin Tissoires
> >> <benjamin.tissoires@redhat.com> wrote:
> >>>
> >>> Or when the probe failed.
> >>>
> >>> This is a common pattern in the HID drivers to reset the drvdata. Some
> >>> do it properly, some do it only in case of failure.
> >>> Anyway, it's never a good thing to have breadcrumbs, so force a clean
> >>> state when removing or when probe is failing.
> >>>
> >>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> >>> ---
> >>> drivers/hid/hid-core.c | 2 ++
> >>> drivers/hid/hid-cougar.c | 6 ++----
> >>> drivers/hid/hid-gfrm.c | 7 -------
> >>> drivers/hid/hid-lenovo.c | 2 --
> >>> drivers/hid/hid-logitech-dj.c | 2 --
> >>> drivers/hid/hid-logitech-hidpp.c | 8 +++-----
> >>> drivers/hid/hid-picolcd_core.c | 7 +------
> >>> drivers/hid/hid-sensor-hub.c | 1 -
> >>> drivers/hid/wacom_sys.c | 18 +++++-------------
> >>> 9 files changed, 13 insertions(+), 40 deletions(-)
> >>>
> >>> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> >>> index b5a8af8daa74..011e49da4d63 100644
> >>> --- a/drivers/hid/hid-core.c
> >>> +++ b/drivers/hid/hid-core.c
> >>> @@ -2203,6 +2203,7 @@ static int hid_device_probe(struct device *dev)
> >>> if (ret) {
> >>> hid_close_report(hdev);
> >>> hdev->driver = NULL;
> >>> + hid_set_drvdata(hdev, NULL);
> >>> }
> >>> }
> >>> unlock:
> >>> @@ -2231,6 +2232,7 @@ static int hid_device_remove(struct device *dev)
> >>> else /* default remove */
> >>> hid_hw_stop(hdev);
> >>> hid_close_report(hdev);
> >>> + hid_set_drvdata(hdev, NULL);
> >>> hdev->driver = NULL;
> >>> }
> >>>
> >>> diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c
> >>> index e0bb7b34f3a4..4ff3bc1d25e2 100644
> >>> --- a/drivers/hid/hid-cougar.c
> >>> +++ b/drivers/hid/hid-cougar.c
> >>> @@ -207,7 +207,7 @@ static int cougar_probe(struct hid_device *hdev,
> >>> error = hid_parse(hdev);
> >>> if (error) {
> >>> hid_err(hdev, "parse failed\n");
> >>> - goto fail;
> >>> + return error;
> >>> }
> >>>
> >>> if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
> >>> @@ -219,7 +219,7 @@ static int cougar_probe(struct hid_device *hdev,
> >>> error = hid_hw_start(hdev, connect_mask);
> >>> if (error) {
> >>> hid_err(hdev, "hw start failed\n");
> >>> - goto fail;
> >>> + return error;
> >>> }
> >>>
> >>> error = cougar_bind_shared_data(hdev, cougar);
> >>> @@ -249,8 +249,6 @@ static int cougar_probe(struct hid_device *hdev,
> >>>
> >>> fail_stop_and_cleanup:
> >>> hid_hw_stop(hdev);
> >>> -fail:
> >>> - hid_set_drvdata(hdev, NULL);
> >>> return error;
> >>> }
> >>>
> >>> diff --git a/drivers/hid/hid-gfrm.c b/drivers/hid/hid-gfrm.c
> >>> index cf477f8c8f4c..1a20997e7750 100644
> >>> --- a/drivers/hid/hid-gfrm.c
> >>> +++ b/drivers/hid/hid-gfrm.c
> >>> @@ -127,12 +127,6 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >>> return ret;
> >>> }
> >>>
> >>> -static void gfrm_remove(struct hid_device *hdev)
> >>> -{
> >>> - hid_hw_stop(hdev);
> >>> - hid_set_drvdata(hdev, NULL);
> >>> -}
> >>> -
> >>> static const struct hid_device_id gfrm_devices[] = {
> >>> { HID_BLUETOOTH_DEVICE(0x58, 0x2000),
> >>> .driver_data = GFRM100 },
> >>> @@ -146,7 +140,6 @@ static struct hid_driver gfrm_driver = {
> >>> .name = "gfrm",
> >>> .id_table = gfrm_devices,
> >>> .probe = gfrm_probe,
> >>> - .remove = gfrm_remove,
> >>> .input_mapping = gfrm_input_mapping,
> >>> .raw_event = gfrm_raw_event,
> >>> .input_configured = gfrm_input_configured,
> >>> diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
> >>> index eacc76d2ab96..cde9d22bb3ec 100644
> >>> --- a/drivers/hid/hid-lenovo.c
> >>> +++ b/drivers/hid/hid-lenovo.c
> >>> @@ -869,8 +869,6 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev)
> >>>
> >>> led_classdev_unregister(&data_pointer->led_micmute);
> >>> led_classdev_unregister(&data_pointer->led_mute);
> >>> -
> >>> - hid_set_drvdata(hdev, NULL);
> >>> }
> >>>
> >>> static void lenovo_remove_cptkbd(struct hid_device *hdev)
> >>> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
> >>> index 826fa1e1c8d9..a75101293755 100644
> >>> --- a/drivers/hid/hid-logitech-dj.c
> >>> +++ b/drivers/hid/hid-logitech-dj.c
> >>> @@ -1094,7 +1094,6 @@ static int logi_dj_probe(struct hid_device *hdev,
> >>> hid_parse_fail:
> >>> kfifo_free(&djrcv_dev->notif_fifo);
> >>> kfree(djrcv_dev);
> >>> - hid_set_drvdata(hdev, NULL);
> >>> return retval;
> >>>
> >>> }
> >>> @@ -1145,7 +1144,6 @@ static void logi_dj_remove(struct hid_device *hdev)
> >>>
> >>> kfifo_free(&djrcv_dev->notif_fifo);
> >>> kfree(djrcv_dev);
> >>> - hid_set_drvdata(hdev, NULL);
> >>> }
> >>>
> >>> static const struct hid_device_id logi_dj_receivers[] = {
> >>> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> >>> index 199cc256e9d9..b950a44157a2 100644
> >>> --- a/drivers/hid/hid-logitech-hidpp.c
> >>> +++ b/drivers/hid/hid-logitech-hidpp.c
> >>> @@ -3237,15 +3237,15 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >>> if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
> >>> ret = wtp_allocate(hdev, id);
> >>> if (ret)
> >>> - goto allocate_fail;
> >>> + return ret;
> >>> } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) {
> >>> ret = m560_allocate(hdev);
> >>> if (ret)
> >>> - goto allocate_fail;
> >>> + return ret;
> >>> } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
> >>> ret = k400_allocate(hdev);
> >>> if (ret)
> >>> - goto allocate_fail;
> >>> + return ret;
> >>> }
> >>>
> >>> INIT_WORK(&hidpp->work, delayed_work_cb);
> >>> @@ -3343,8 +3343,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >>> sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
> >>> cancel_work_sync(&hidpp->work);
> >>> mutex_destroy(&hidpp->send_mutex);
> >>> -allocate_fail:
> >>> - hid_set_drvdata(hdev, NULL);
> >>> return ret;
> >>> }
> >>>
> >>> diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
> >>> index c1b29a9eb41a..a5d30f267a7b 100644
> >>> --- a/drivers/hid/hid-picolcd_core.c
> >>> +++ b/drivers/hid/hid-picolcd_core.c
> >>> @@ -550,8 +550,7 @@ static int picolcd_probe(struct hid_device *hdev,
> >>> data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
> >>> if (data == NULL) {
> >>> hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
> >>> - error = -ENOMEM;
> >>> - goto err_no_cleanup;
> >>> + return -ENOMEM;
> >>> }
> >>>
> >>> spin_lock_init(&data->lock);
> >>> @@ -613,9 +612,6 @@ static int picolcd_probe(struct hid_device *hdev,
> >>> hid_hw_stop(hdev);
> >>> err_cleanup_data:
> >>> kfree(data);
> >>> -err_no_cleanup:
> >>> - hid_set_drvdata(hdev, NULL);
> >>> -
> >>> return error;
> >>> }
> >>>
> >>> @@ -651,7 +647,6 @@ static void picolcd_remove(struct hid_device *hdev)
> >>> picolcd_exit_cir(data);
> >>> picolcd_exit_keys(data);
> >>>
> >>> - hid_set_drvdata(hdev, NULL);
> >>> mutex_destroy(&data->mutex);
> >>> /* Finally, clean up the picolcd data itself */
> >>> kfree(data);
> >>> diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
> >>> index 4256fdc5cd6d..a3db5d8b382d 100644
> >>> --- a/drivers/hid/hid-sensor-hub.c
> >>> +++ b/drivers/hid/hid-sensor-hub.c
> >>> @@ -755,7 +755,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
> >>> }
> >>> spin_unlock_irqrestore(&data->lock, flags);
> >>> mfd_remove_devices(&hdev->dev);
> >>> - hid_set_drvdata(hdev, NULL);
> >>> mutex_destroy(&data->mutex);
> >>> }
> >>>
> >>> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
> >>> index a8633b1437b2..c2fb614bff44 100644
> >>> --- a/drivers/hid/wacom_sys.c
> >>> +++ b/drivers/hid/wacom_sys.c
> >>> @@ -2716,14 +2716,12 @@ static int wacom_probe(struct hid_device *hdev,
> >>> wacom_wac->features = *((struct wacom_features *)id->driver_data);
> >>> features = &wacom_wac->features;
> >>>
> >>> - if (features->check_for_hid_type && features->hid_type != hdev->type) {
> >>> - error = -ENODEV;
> >>> - goto fail;
> >>> - }
> >>> + if (features->check_for_hid_type && features->hid_type != hdev->type)
> >>> + return -ENODEV;
> >>>
> >>> error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
> >>> if (error)
> >>> - goto fail;
> >>> + return error;
> >>>
> >>> wacom_wac->hid_data.inputmode = -1;
> >>> wacom_wac->mode_report = -1;
> >>> @@ -2741,12 +2739,12 @@ static int wacom_probe(struct hid_device *hdev,
> >>> error = hid_parse(hdev);
> >>> if (error) {
> >>> hid_err(hdev, "parse failed\n");
> >>> - goto fail;
> >>> + return error;
> >>> }
> >>>
> >>> error = wacom_parse_and_register(wacom, false);
> >>> if (error)
> >>> - goto fail;
> >>> + return error;
> >>>
> >>> if (hdev->bus == BUS_BLUETOOTH) {
> >>> error = device_create_file(&hdev->dev, &dev_attr_speed);
> >>> @@ -2757,10 +2755,6 @@ static int wacom_probe(struct hid_device *hdev,
> >>> }
> >>>
> >>> return 0;
> >>> -
> >>> -fail:
> >>> - hid_set_drvdata(hdev, NULL);
> >>> - return error;
> >>> }
> >>>
> >>> static void wacom_remove(struct hid_device *hdev)
> >>> @@ -2789,8 +2783,6 @@ static void wacom_remove(struct hid_device *hdev)
> >>> wacom_release_resources(wacom);
> >>>
> >>> kfifo_free(&wacom_wac->pen_fifo);
> >>> -
> >>> - hid_set_drvdata(hdev, NULL);
> >>> }
> >>>
> >>> #ifdef CONFIG_PM
> >>> --
> >>> 2.19.2
> >>>
> >>
> >>
> >> --
> >> Dmitry
^ permalink raw reply
* Re: [PATCH] HID: force setting drvdata to NULL when removing the driver
From: Hans de Goede @ 2019-04-02 14:02 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Bruno Prémont,
Jonathan Cameron, Srinivas Pandruvada, Jason Gerecke, Ping Cheng,
linux-input@vger.kernel.org, lkml
In-Reply-To: <CAO-hwJK5B1uEmw7vnt73k2BLv4YQeLMf_KwS58-LgAOrLfCqhA@mail.gmail.com>
Hi,
On 02-04-19 16:00, Benjamin Tissoires wrote:
> On Tue, Apr 2, 2019 at 3:52 PM Hans de Goede <hdegoede@redhat.com> wrote:
>>
>> Hi,
>>
>> On 02-04-19 15:44, Benjamin Tissoires wrote:
>>> Hi Dmitry,
>>>
>>> On Fri, Mar 29, 2019 at 11:26 PM Dmitry Torokhov
>>> <dmitry.torokhov@gmail.com> wrote:
>>>>
>>>> Hi Benjamin,
>>>>
>>>> On Thu, Mar 28, 2019 at 8:52 AM Benjamin Tissoires
>>>> <benjamin.tissoires@redhat.com> wrote:
>>>>>
>>>>> Or when the probe failed.
>>>>>
>>>>> This is a common pattern in the HID drivers to reset the drvdata. Some
>>>>> do it properly, some do it only in case of failure.
>>>>> Anyway, it's never a good thing to have breadcrumbs, so force a clean
>>>>> state when removing or when probe is failing.
>>>>
>>>> Just a data point: driver core already clears drvdata, so as long as
>>>> dev_get/set_drvdata() is the same as hid_get/set_drvdata() no special
>>>> handling is needed in HID core.
>>>
>>> You are correct (as always ;-P). I'll drop the hid-core changes and
>>> send a v2 ASAP.
>>
>> I was just looking at the same thing. I should have known about this
>> since I wrote the patch to make the core clear drvdata. I should have
>> mentioned that, but I was assuming that the hid code was special somehow,
>> however now I see it just uses a regular device_add, so indeed the core
>> changes are not necessary.
>>
>> Given the large hid-logitech-*.c patch-set it might be easier for
>> Jiri if you split out the hid-logitech-*.c changes into a separate
>> patch, then he can keep that on his logitech branch (just a thought).
>>
>
> I do not expect the logitech changes to now create some big conflict.
> But looking at the current for-5.2* branches, I should probably split
> the series per driver given that there is no more dependency on
> hid-core. This way, we can take the logitech changes in the
> for-5.2/logitech branch, and you can rebase your work on top of it.
Great, thank you.
Regards,
Hans
^ permalink raw reply
* RE: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Mario.Limonciello @ 2019-04-02 14:08 UTC (permalink / raw)
To: kai.heng.feng
Cc: andy.shevchenko, hdegoede, benjamin.tissoires, hotwater438, jikos,
swboyd, bigeasy, dtor, linux-input, linux-kernel
In-Reply-To: <6105BFF6-41B1-4DB8-A78D-20BC2E35C014@canonical.com>
> -----Original Message-----
> From: Kai Heng Feng <kai.heng.feng@canonical.com>
> Sent: Monday, April 1, 2019 11:18 PM
> To: Limonciello, Mario
> Cc: Andy Shevchenko; hdegoede@redhat.com; benjamin.tissoires@redhat.com;
> hotwater438@tutanota.com; jikos@kernel.org; swboyd@chromium.org;
> bigeasy@linutronix.de; dtor@chromium.org; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] ELAN touchpad i2c_hid bugs fix
>
>
> [EXTERNAL EMAIL]
>
>
>
> > On Apr 2, 2019, at 5:37 AM, <Mario.Limonciello@dell.com>
> > <Mario.Limonciello@dell.com> wrote:
> >
> >> -----Original Message-----
> >> From: Andy Shevchenko <andy.shevchenko@gmail.com>
> >> Sent: Thursday, March 21, 2019 4:48 AM
> >> To: Kai-Heng Feng; Limonciello, Mario
> >> Cc: Hans de Goede; Benjamin Tissoires; hotwater438@tutanota.com; Jiri
> >> Kosina;
> >> Stephen Boyd; Sebastian Andrzej Siewior; Dmitry Torokhov; open list:HID
> >> CORE
> >> LAYER; lkml
> >> Subject: Re: [PATCH] ELAN touchpad i2c_hid bugs fix
> >>
> >>
> >> [EXTERNAL EMAIL]
> >>
> >> +Cc: Mario
> >>
> >> Mario, do you have any insights about the issue with touchpad on Dell
> >> system described below?
> >
> > My apologies, this got lost while I was on vacation.
> >
> >>
> >> On Thu, Mar 21, 2019 at 6:08 AM Kai-Heng Feng
> >> <kai.heng.feng@canonical.com> wrote:
> >>>
> >>> at 01:18, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> >>>
> >>>> On Wed, Mar 20, 2019 at 6:55 PM Kai-Heng Feng
> >>>> <kai.heng.feng@canonical.com> wrote:
> >>>>> at 23:39, Hans de Goede <hdegoede@redhat.com> wrote:
> >>>>>> On 3/20/19 3:37 PM, Benjamin Tissoires wrote:
> >>>>
> >>>>>> Benjamin, what I find interesting here is that the BOGUS_IRQ quirk
> >>>>>> is also used on Elan devices, I suspect that these Elan devices
> >>>>>> likely also need the I2C_HID_QUIRK_FORCE_TRIGGER_FALLING quirk
> >>>>>> and then they probably will no longer need the bogus IRQ flag,
> >>>>>> if you know about bugreports with an acpidump for any of the devices
> >>>>>> needing the bogus IRQ quirk, then I (or you) can check how the IRQ is
> >>>>>> declared there, I suspect it will be declared as level-low, just like
> >>>>>> with the laptop this patch was written for. And it probably need to
> >>>>>> be edge-falling instead of level-low just like this case.
> >>>>>
> >>>>> First, I’ve already tried using IRQF_TRIGGER_FALLING, unfortunately it
> >>>>> doesn’t solve the issue for me.
> >>>>>
> >>>>> I talked to Elan once, and they confirm the correct IRQ trigger is
> >>>>> level
> >>>>> low. So forcing falling trigger may break other platforms.
> >>>>
> >>>> As far as I understood Vladislav the quirk he got from Elan as well.
> >>>
> >>> Ok, then this is really weird.
> >>>
> >>>>
> >>>>> Recently we found that Elan touchpad doesn’t like GpioInt() from its
> >>>>> _CRS.
> >>>>> Once the Interrupt() is used instead, the issue goes away.
> >>>>
> >>>> IIRC i2c core tries to get interrupt from Interrupt() resource and
> >>>> then falls back to GpioInt().
> >>>> See i2c_acpi_get_info() and i2c_device_probe().
> >>>
> >>> Here’s its ASL:
> >>>
> >>> Scope (\_SB.PCI0.I2C4)
> >>> {
> >>> Device (TPD0)
> >>> {
> >>> Name (_ADR, One) // _ADR: Address
> >>> Name (_HID, "DELL08AE") // _HID: Hardware ID
> >>> Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID:
> >> Compatible ID
> >>> Name (_UID, One) // _UID: Unique ID
> >>> Name (_S0W, 0x04) // _S0W: S0 Device Wake State
> >>> Name (SBFB, ResourceTemplate ()
> >>> {
> >>> I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
> >>> AddressingMode7Bit, "\\_SB.PCI0.I2C4",
> >>> 0x00, ResourceConsumer, , Exclusive,
> >>> )
> >>> })
> >>> Name (SBFG, ResourceTemplate ()
> >>> {
> >>> GpioInt (Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
> >>> "\\_SB.GPO1", 0x00, ResourceConsumer, ,
> >>> )
> >>> { // Pin list
> >>> 0x0012
> >>> }
> >>> })
> >>> Name (SBFI, ResourceTemplate ()
> >>> {
> >>> Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, )
> >>> {
> >>> 0x0000003C,
> >>> }
> >>> })
> >>> Method (_INI, 0, NotSerialized) // _INI: Initialize
> >>> {
> >>> }
> >>> Method (_STA, 0, NotSerialized) // _STA: Status
> >>> {
> >>> If ((TCPD == One))
> >>> {
> >>> Return (0x0F)
> >>> }
> >>>
> >>> Return (Zero)
> >>> }
> >>> Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
> >>> {
> >>> If ((OSYS < 0x07DC))
> >>> {
> >>> Return (SBFI) /* \_SB_.PCI0.I2C4.TPD0.SBFI */
> >>> }
> >>>
> >>> Return (ConcatenateResTemplate (SBFB, SBFG))
> >>> }
> >>> Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
> >>> {
> >>> If ((Arg0 == ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /*
> HID
> >> I2C Device */))
> >>> {
> >>> If ((Arg2 == Zero))
> >>> {
> >>> If ((Arg1 == One))
> >>> {
> >>> Return (Buffer (One)
> >>> {
> >>> 0x03 // .
> >>> })
> >>> }
> >>> Else
> >>> {
> >>> Return (Buffer (One)
> >>> {
> >>> 0x00 // .
> >>> })
> >>> }
> >>> }
> >>> ElseIf ((Arg2 == One))
> >>> {
> >>> Return (0x20)
> >>> }
> >>> Else
> >>> {
> >>> Return (Buffer (One)
> >>> {
> >>> 0x00 // .
> >>> })
> >>> }
> >>> }
> >>> ElseIf ((Arg0 == ToUUID ("ef87eb82-f951-46da-84ec-14871ac6f84b")))
> >>> {
> >>> If ((Arg2 == Zero))
> >>> {
> >>> If ((Arg1 == One))
> >>> {
> >>> Return (Buffer (One)
> >>> {
> >>> 0x03 // .
> >>> })
> >>> }
> >>> }
> >>>
> >>> If ((Arg2 == One))
> >>> {
> >>> Return (ConcatenateResTemplate (SBFB, SBFG))
> >>> }
> >>>
> >>> Return (Buffer (One)
> >>> {
> >>> 0x00 // .
> >>> })
> >>> }
> >>> }
> >>> Else
> >>> {
> >>> Return (Buffer (One)
> >>> {
> >>> 0x00 // .
> >>> })
> >>> }
> >>> }
> >>> }
> >>> }
> >>>
> >>> Change SBFG to SBFI in its _CRS can workaround the issue.
> >>> Is ASL in this form possible to do the flow you described?
> >>>
> >>> Kai-Heng
> >>>
> >>>>
> >>>>> But I am not sure how to patch its DSDT/SSDT in i2c-hid.
> >
> > Is this pre-production HW? If so, maybe this is a case that we should talk
> > about custom OSI string to run the ASL differently.
>
> Some are already shipped.
>
>
> >
> > The other option would be to create a new ASL method in FW and from Linux
> > side a quirk that calls this new ASL method.
> >
>
> Since this patch is for ASUS Laptop, I think a more generic solution from
> driver layer is preferred.
>
I thought this ASL was from Dell laptop. The HID make it looks like it at least.
> >>> Name (_HID, "DELL08AE") // _HID: Hardware ID
In general more generic solution from driver layer is preferred I agree. You might
need to check with ACPI guys to see if they have some ideas on situations that
GpioInt fail.
^ permalink raw reply
* Re: [PATCH v4] HID: core: move Usage Page concatenation to Main item
From: Benjamin Tissoires @ 2019-04-02 14:34 UTC (permalink / raw)
To: Nicolas Saenz Julienne
Cc: Jiri Kosina, oneukum, Junge, Terry, open list:HID CORE LAYER,
lkml
In-Reply-To: <20190327101848.25477-1-nsaenzjulienne@suse.de>
On Wed, Mar 27, 2019 at 11:19 AM Nicolas Saenz Julienne
<nsaenzjulienne@suse.de> wrote:
>
> As seen on some USB wireless keyboards manufactured by Primax, the HID
> parser was using some assumptions that are not always true. In this case
> it's s the fact that, inside the scope of a main item, an Usage Page
> will always precede an Usage.
>
> The spec is not pretty clear as 6.2.2.7 states "Any usage that follows
> is interpreted as a Usage ID and concatenated with the Usage Page".
> While 6.2.2.8 states "When the parser encounters a main item it
> concatenates the last declared Usage Page with a Usage to form a
> complete usage value." Being somewhat contradictory it was decided to
> match Window's implementation, which follows 6.2.2.8.
>
> In summary, the patch moves the Usage Page concatenation from the local
> item parsing function to the main item parsing function.
>
> Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
> ---
Applied to for-5.2/core with Terry's reviewed-by.
Thanks everybody.
Cheers,
Benjamin
>
> v3->v4: - Use u8 instead of __u8
> - Remove overly complex usage size calculation
>
> v2->v3: - Update patch title
>
> v1->v2: - Add usage concatenation to hid_scan_main()
> - Rework tests in hid-tools, making sure no-one is failing
>
> drivers/hid/hid-core.c | 36 ++++++++++++++++++++++++------------
> include/linux/hid.h | 1 +
> 2 files changed, 25 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 9993b692598f..852bbd303d9a 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -218,13 +218,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
> * Add a usage to the temporary parser table.
> */
>
> -static int hid_add_usage(struct hid_parser *parser, unsigned usage)
> +static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
> {
> if (parser->local.usage_index >= HID_MAX_USAGES) {
> hid_err(parser->device, "usage index exceeded\n");
> return -1;
> }
> parser->local.usage[parser->local.usage_index] = usage;
> + parser->local.usage_size[parser->local.usage_index] = size;
> parser->local.collection_index[parser->local.usage_index] =
> parser->collection_stack_ptr ?
> parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
> @@ -486,10 +487,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
> return 0;
> }
>
> - if (item->size <= 2)
> - data = (parser->global.usage_page << 16) + data;
> -
> - return hid_add_usage(parser, data);
> + return hid_add_usage(parser, data, item->size);
>
> case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
>
> @@ -498,9 +496,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
> return 0;
> }
>
> - if (item->size <= 2)
> - data = (parser->global.usage_page << 16) + data;
> -
> parser->local.usage_minimum = data;
> return 0;
>
> @@ -511,9 +506,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
> return 0;
> }
>
> - if (item->size <= 2)
> - data = (parser->global.usage_page << 16) + data;
> -
> count = data - parser->local.usage_minimum;
> if (count + parser->local.usage_index >= HID_MAX_USAGES) {
> /*
> @@ -533,7 +525,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
> }
>
> for (n = parser->local.usage_minimum; n <= data; n++)
> - if (hid_add_usage(parser, n)) {
> + if (hid_add_usage(parser, n, item->size)) {
> dbg_hid("hid_add_usage failed\n");
> return -1;
> }
> @@ -547,6 +539,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
> return 0;
> }
>
> +/*
> + * Concatenate Usage Pages into Usages where relevant:
> + * As per specification, 6.2.2.8: "When the parser encounters a main item it
> + * concatenates the last declared Usage Page with a Usage to form a complete
> + * usage value."
> + */
> +
> +static void hid_concatenate_usage_page(struct hid_parser *parser)
> +{
> + int i;
> +
> + for (i = 0; i < parser->local.usage_index; i++)
> + if (parser->local.usage_size[i] <= 2)
> + parser->local.usage[i] += parser->global.usage_page << 16;
> +}
> +
> /*
> * Process a main item.
> */
> @@ -556,6 +564,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
> __u32 data;
> int ret;
>
> + hid_concatenate_usage_page(parser);
> +
> data = item_udata(item);
>
> switch (item->tag) {
> @@ -765,6 +775,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
> __u32 data;
> int i;
>
> + hid_concatenate_usage_page(parser);
> +
> data = item_udata(item);
>
> switch (item->tag) {
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index f9707d1dcb58..ac0c70b4ce10 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -417,6 +417,7 @@ struct hid_global {
>
> struct hid_local {
> unsigned usage[HID_MAX_USAGES]; /* usage array */
> + u8 usage_size[HID_MAX_USAGES]; /* usage size array */
> unsigned collection_index[HID_MAX_USAGES]; /* collection index array */
> unsigned usage_index;
> unsigned usage_minimum;
> --
> 2.21.0
>
^ permalink raw reply
* Re: [PATCH 1/2] Input: synaptics-rmi4 - clear irqs before set irqs
From: Christopher Heiny @ 2019-04-02 16:16 UTC (permalink / raw)
To: Aaron Ma, dmitry.torokhov@gmail.com, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org, Andrew Duggan,
benjamin.tissoires@redhat.com
In-Reply-To: <acd07f4d-1602-46c5-c486-c917f1868b59@canonical.com>
On Thu, 2019-03-28 at 14:02 +0800, Aaron Ma wrote:
> Hi Dmitry and Chiristopher:
>
> Do you have any suggestion about these 2 patches?
>
> Many users confirmed that they fixed issues of Trackpoint/Touchpad
> after S3.
>
> Will you consider them be accepted?
Hi Aaron,
Sorry - I thought I'd replied on the NO SLEEP portion of these patches,
but looking back I don't find the draft or the sent email. Sorry about
that. I'll summarize here what I wrote last month.
This isn't so much a "fix" as a "hacky workaround" for the issue. From
the descriptions in the bug you linked in your original patch
submission, it appears that the root cause is somewhere in SMBus system
(could be SMBus driver, SMBus hardware, or the devices on the SMBus
(touch devices or other devices) - it's hard to tell with the info
available), where the SMBus is failing to come online correctly coming
out of S3 state. Anyway, this patch doesn't fix the root cause, but
merely works around it.
Setting the NO SLEEP bit will force the touch sensor to remain in a
high power consumption state while the rest of the system is in S3.
While not a lot of power compared to things like the CPU, display, and
others, it is still non-trivial and will result in shorter time-on-
battery capability.
If you have access to the power pin(s) for the touch sensor(s)/styk(s),
it might be interesting to try turning power off on entering S3, and
restoring it on exit. That's very hacky, and has the side effect of
slightly delaying touchpad readiness on exit from S3. Plus you'll need
to restore touch sensor configuration settings on exit. But it
definitely reduces power consumption.
Separately, I am still concerned about the possibility of dropped touch
events in the IRQ clearing. I'm not convinced that the code is safe
(as you mentioned in your reply to my earlier comment), so I'll have to
study the implementation more carefully.
Cheers,
Chris
>
> Thanks,
> Aaron
^ permalink raw reply
* [PATCH] HID: input: add mapping for Assistant key
From: Dmitry Torokhov @ 2019-04-02 16:57 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
According to HUTRR89 usage 0x1cb from the consumer page was assigned to
allow launching desktop-aware assistant application, so let's add the
mapping.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-input.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index da76358cde06..a7046a322ddd 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -999,6 +999,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1b8: map_key_clear(KEY_VIDEO); break;
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
+ case 0x1cb: map_key_clear(KEY_ASSISTANT); break;
case 0x201: map_key_clear(KEY_NEW); break;
case 0x202: map_key_clear(KEY_OPEN); break;
case 0x203: map_key_clear(KEY_CLOSE); break;
--
2.21.0.392.gf8f6787159e-goog
--
Dmitry
^ permalink raw reply related
* Re: [PATCH v7 00/11] mfd: add support for max77650 PMIC
From: Lee Jones @ 2019-04-03 7:37 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Sebastian Reichel, Liam Girdwood,
Greg Kroah-Hartman, linux-kernel, linux-gpio, devicetree,
linux-input, linux-leds, linux-pm, Bartosz Golaszewski
In-Reply-To: <20190326173208.30614-1-brgl@bgdev.pl>
On Tue, 26 Mar 2019, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> This series adds support for max77650 ultra low-power PMIC. It provides
> the core mfd driver and a set of five sub-drivers for the regulator,
> power supply, gpio, leds and input subsystems.
>
> Patches 1-4 add the DT binding documents. Patch 5 documents mfd_add_devices().
> Patches 6-10 add all drivers. Last patch adds a MAINTAINERS entry for this
> device.
My review carries forward to this version.
Please apply Acks, make changes and resubmit.
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v8 00/11] mfd: add support for max77650 PMIC
From: Bartosz Golaszewski @ 2019-04-03 9:00 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This series adds support for max77650 ultra low-power PMIC. It provides
the core mfd driver and a set of five sub-drivers for the regulator,
power supply, gpio, leds and input subsystems.
Patches 1-4 add the DT binding documents. Patch 5 documents mfd_add_devices().
Patches 6-10 add all drivers. Last patch adds a MAINTAINERS entry for this
device.
The regulator part is already upstream.
v1 -> v2:
=========
General:
- use C++ style comments for the SPDX license identifier and the
copyright header
- s/MODULE_LICENSE("GPL")/MODULE_LICENSE("GPL v2")/
- lookup the virtual interrupt numbers in the MFD driver, setup
resources for child devices and use platform_get_irq_byname()
in sub-drivers
- picked up review tags
- use devm_request_any_context_irq() for interrupt requests
LEDs:
- changed the max77650_leds_ prefix to max77650_led_
- drop the max77650_leds structure as the only field it held was the
regmap pointer, move said pointer to struct max77650_led
- change the driver name to "max77650-led"
- drop the last return value check and return the result of
regmap_write() directly
- change the labeling scheme to one consistent with other LED drivers
ONKEY:
- drop the key reporting helper and call the input functions directly
from interrupt handlers
- rename the rv local variable to error
- drop parent device asignment
Regulator:
- drop the unnecessary init_data lookup from the driver code
- drop unnecessary include
Charger:
- disable the charger on driver remove
- change the power supply type to POWER_SUPPLY_TYPE_USB
GPIO:
- drop interrupt support until we have correct implementation of hierarchical
irqs in gpiolib
v2 -> v3:
=========
General:
- dropped regulator patches as they're already in Mark Brown's branch
LED:
- fix the compatible string in the DT binding example
- use the max_brightness property
- use a common prefix ("MAX77650_LED") for all defines in the driver
MFD:
- add the MODULE_DEVICE_TABLE()
- add a sentinel to the of_device_id array
- constify the pointers to irq names
- use an enum instead of defines for interrupt indexes
v3 -> v4:
=========
GPIO:
- as discussed with Linus Walleij: the gpio-controller is now part of
the core mfd module (we don't spawn a sub-node anymore), the binding
document for GPIO has been dropped, the GPIO properties have been
defined in the binding document for the mfd core, the interrupt
functionality has been reintroduced with the irq directly passed from
the mfd part
- due to the above changes the Reviewed-by tag from Linus was dropped
v4 -> v5:
=========
General:
- add a patch documenting mfd_add_devices()
MFD:
- pass the regmap irq_chip irq domain to mfd over mfd_add_devices so that
the hw interrupts from resources can be correctly mapped to virtual irqs
- remove the enum listing cell indexes
- extend Kconfig help
- add a link to the programming manual
- use REGMAP_IRQ_REG() for regmap interrupts (except for GPI which has
is composed of two hw interrupts for rising and falling edge)
- add error messages in probe
- use PLATFORM_DEVID_NONE constant in devm_mfd_add_devices()
- set irq_base to 0 in regmap_add_irq_chip() as other users to, it's only
relevant if it's > 0
Charger:
- use non-maxim specific property names for minimum input voltage and current
limit
- code shrink by using the enable/disable charger helpers everywhere
- use more descriptive names for constants
Onkey:
- use EV_SW event type for slide mode
LED:
- remove stray " from Kconfig help
v5 -> v6:
=========
MFD:
- remove stray spaces in the binding document
- rename the example dt node
- remove unnecessary interrupt-parent property from the bindings
LED:
- add a missing dependency on LEDS_CLASS to Kconfig
Onkey:
- use boolean for the slide button property
Charger:
- fix the property names in DT example
- make constants even more readable
v6 -> v7:
=========
Charger:
- rename the current limit property to current-limit-microamp
v7 -> v8:
=========
General:
- collected acks from Lee
- changed the documentation for mfd_add_devices() as suggested by Lee
- rebased on top of v5.1-rc3
Bartosz Golaszewski (11):
dt-bindings: mfd: add DT bindings for max77650
dt-bindings: power: supply: add DT bindings for max77650
dt-bindings: leds: add DT bindings for max77650
dt-bindings: input: add DT bindings for max77650
mfd: core: document mfd_add_devices()
mfd: max77650: new core mfd driver
power: supply: max77650: add support for battery charger
gpio: max77650: add GPIO support
leds: max77650: add LEDs support
input: max77650: add onkey support
MAINTAINERS: add an entry for max77650 mfd driver
.../bindings/input/max77650-onkey.txt | 26 ++
.../bindings/leds/leds-max77650.txt | 57 +++
.../devicetree/bindings/mfd/max77650.txt | 46 +++
.../power/supply/max77650-charger.txt | 27 ++
MAINTAINERS | 14 +
drivers/gpio/Kconfig | 7 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-max77650.c | 190 +++++++++
drivers/input/misc/Kconfig | 9 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/max77650-onkey.c | 121 ++++++
drivers/leds/Kconfig | 6 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-max77650.c | 147 +++++++
drivers/mfd/Kconfig | 14 +
drivers/mfd/Makefile | 1 +
drivers/mfd/max77650.c | 234 +++++++++++
drivers/mfd/mfd-core.c | 13 +
drivers/power/supply/Kconfig | 7 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/max77650-charger.c | 367 ++++++++++++++++++
include/linux/mfd/max77650.h | 59 +++
22 files changed, 1349 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/max77650-onkey.txt
create mode 100644 Documentation/devicetree/bindings/leds/leds-max77650.txt
create mode 100644 Documentation/devicetree/bindings/mfd/max77650.txt
create mode 100644 Documentation/devicetree/bindings/power/supply/max77650-charger.txt
create mode 100644 drivers/gpio/gpio-max77650.c
create mode 100644 drivers/input/misc/max77650-onkey.c
create mode 100644 drivers/leds/leds-max77650.c
create mode 100644 drivers/mfd/max77650.c
create mode 100644 drivers/power/supply/max77650-charger.c
create mode 100644 include/linux/mfd/max77650.h
--
2.21.0
^ permalink raw reply
* [PATCH v8 01/11] dt-bindings: mfd: add DT bindings for max77650
From: Bartosz Golaszewski @ 2019-04-03 9:00 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski, Rob Herring
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add a DT binding document for max77650 ultra-low power PMIC. This
describes the core mfd device and the GPIO module.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Acked-by: Pavel Machek <pavel@ucw.cz>
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
---
.../devicetree/bindings/mfd/max77650.txt | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/max77650.txt
diff --git a/Documentation/devicetree/bindings/mfd/max77650.txt b/Documentation/devicetree/bindings/mfd/max77650.txt
new file mode 100644
index 000000000000..b529d8d19335
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77650.txt
@@ -0,0 +1,46 @@
+MAX77650 ultra low-power PMIC from Maxim Integrated.
+
+Required properties:
+-------------------
+- compatible: Must be "maxim,max77650"
+- reg: I2C device address.
+- interrupts: The interrupt on the parent the controller is
+ connected to.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Must be <2>.
+
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Must be <2>. The first cell is the pin number and
+ the second cell is used to specify the gpio active
+ state.
+
+Optional properties:
+--------------------
+gpio-line-names: Single string containing the name of the GPIO line.
+
+The GPIO-controller module is represented as part of the top-level PMIC
+node. The device exposes a single GPIO line.
+
+For device-tree bindings of other sub-modules (regulator, power supply,
+LEDs and onkey) refer to the binding documents under the respective
+sub-system directories.
+
+For more details on GPIO bindings, please refer to the generic GPIO DT
+binding document <devicetree/bindings/gpio/gpio.txt>.
+
+Example:
+--------
+
+ pmic@48 {
+ compatible = "maxim,max77650";
+ reg = <0x48>;
+
+ interrupt-controller;
+ interrupt-parent = <&gpio2>;
+ #interrupt-cells = <2>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-line-names = "max77650-charger";
+ };
--
2.21.0
^ permalink raw reply related
* [PATCH v8 02/11] dt-bindings: power: supply: add DT bindings for max77650
From: Bartosz Golaszewski @ 2019-04-03 9:00 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add the DT binding document for the battery charger module of max77650.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
.../power/supply/max77650-charger.txt | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/supply/max77650-charger.txt
diff --git a/Documentation/devicetree/bindings/power/supply/max77650-charger.txt b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
new file mode 100644
index 000000000000..fef188144386
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
@@ -0,0 +1,27 @@
+Battery charger driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The charger is represented as a sub-node of the PMIC node on the device tree.
+
+Required properties:
+--------------------
+- compatible: Must be "maxim,max77650-charger"
+
+Optional properties:
+--------------------
+- min-microvolt: Minimum CHGIN regulation voltage (in microvolts). Must be
+ one of: 4000000, 4100000, 4200000, 4300000, 4400000,
+ 4500000, 4600000, 4700000.
+- current-limit-microamp: CHGIN input current limit (in microamps). Must
+ be one of: 95000, 190000, 285000, 380000, 475000.
+
+Example:
+--------
+
+ charger {
+ compatible = "maxim,max77650-charger";
+ min-microvolt = <4200000>;
+ curr-lim-microamp = <285000>;
+ };
--
2.21.0
^ permalink raw reply related
* [PATCH v8 03/11] dt-bindings: leds: add DT bindings for max77650
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski, Rob Herring
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add the DT binding document for the LEDs module of max77650.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/leds/leds-max77650.txt | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 Documentation/devicetree/bindings/leds/leds-max77650.txt
diff --git a/Documentation/devicetree/bindings/leds/leds-max77650.txt b/Documentation/devicetree/bindings/leds/leds-max77650.txt
new file mode 100644
index 000000000000..3a67115cc1da
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-max77650.txt
@@ -0,0 +1,57 @@
+LED driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The LED controller is represented as a sub-node of the PMIC node on
+the device tree.
+
+This device has three current sinks.
+
+Required properties:
+--------------------
+- compatible: Must be "maxim,max77650-led"
+- #address-cells: Must be <1>.
+- #size-cells: Must be <0>.
+
+Each LED is represented as a sub-node of the LED-controller node. Up to
+three sub-nodes can be defined.
+
+Required properties of the sub-node:
+------------------------------------
+
+- reg: Must be <0>, <1> or <2>.
+
+Optional properties of the sub-node:
+------------------------------------
+
+- label: See Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger: See Documentation/devicetree/bindings/leds/common.txt
+
+For more details, please refer to the generic GPIO DT binding document
+<devicetree/bindings/gpio/gpio.txt>.
+
+Example:
+--------
+
+ leds {
+ compatible = "maxim,max77650-led";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ label = "blue:usr0";
+ };
+
+ led@1 {
+ reg = <1>;
+ label = "red:usr1";
+ linux,default-trigger = "heartbeat";
+ };
+
+ led@2 {
+ reg = <2>;
+ label = "green:usr2";
+ };
+ };
--
2.21.0
^ permalink raw reply related
* [PATCH v8 04/11] dt-bindings: input: add DT bindings for max77650
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski, Rob Herring
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add the DT binding document for the onkey module of max77650.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/input/max77650-onkey.txt | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/max77650-onkey.txt
diff --git a/Documentation/devicetree/bindings/input/max77650-onkey.txt b/Documentation/devicetree/bindings/input/max77650-onkey.txt
new file mode 100644
index 000000000000..477dc74f452a
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/max77650-onkey.txt
@@ -0,0 +1,26 @@
+Onkey driver for MAX77650 PMIC from Maxim Integrated.
+
+This module is part of the MAX77650 MFD device. For more details
+see Documentation/devicetree/bindings/mfd/max77650.txt.
+
+The onkey controller is represented as a sub-node of the PMIC node on
+the device tree.
+
+Required properties:
+--------------------
+- compatible: Must be "maxim,max77650-onkey".
+
+Optional properties:
+- linux,code: The key-code to be reported when the key is pressed.
+ Defaults to KEY_POWER.
+- maxim,onkey-slide: The system's button is a slide switch, not the default
+ push button.
+
+Example:
+--------
+
+ onkey {
+ compatible = "maxim,max77650-onkey";
+ linux,code = <KEY_END>;
+ maxim,onkey-slide;
+ };
--
2.21.0
^ permalink raw reply related
* [PATCH v8 05/11] mfd: core: document mfd_add_devices()
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add a kernel doc for mfd_add_devices().
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/mfd/mfd-core.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 94e3f32ce935..1ade4c8cc91f 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -269,6 +269,19 @@ static int mfd_add_device(struct device *parent, int id,
return ret;
}
+/**
+ * mfd_add_devices - register child devices
+ *
+ * @parent: Pointer to parent device.
+ * @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care
+ * of device numbering, or will be added to a device's cell_id.
+ * @cells: Array of (struct mfd_cell)s describing child devices.
+ * @n_devs: Number of child devices to register.
+ * @mem_base: Parent register range resource for child devices.
+ * @irq_base: Base of the range of virtual interrupt numbers allocated for
+ * this MFD device. Unused if @domain is specified.
+ * @domain: Interrupt domain to create mappings for hardware interrupts.
+ */
int mfd_add_devices(struct device *parent, int id,
const struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
--
2.21.0
^ permalink raw reply related
* [PATCH v8 06/11] mfd: max77650: new core mfd driver
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add the core mfd driver for max77650 PMIC. We define five sub-devices
for which the drivers will be added in subsequent patches.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/mfd/Kconfig | 14 +++
drivers/mfd/Makefile | 1 +
drivers/mfd/max77650.c | 234 +++++++++++++++++++++++++++++++++++
include/linux/mfd/max77650.h | 59 +++++++++
4 files changed, 308 insertions(+)
create mode 100644 drivers/mfd/max77650.c
create mode 100644 include/linux/mfd/max77650.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0ce2d8dfc5f1..ade04e124aa0 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -733,6 +733,20 @@ config MFD_MAX77620
provides common support for accessing the device; additional drivers
must be enabled in order to use the functionality of the device.
+config MFD_MAX77650
+ tristate "Maxim MAX77650/77651 PMIC Support"
+ depends on I2C
+ depends on OF || COMPILE_TEST
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Say Y here to add support for Maxim Semiconductor MAX77650 and
+ MAX77651 Power Management ICs. This is the core multifunction
+ driver for interacting with the device. The module name is
+ 'max77650'. Additional drivers can be enabled in order to use
+ the following functionalities of the device: GPIO, regulator,
+ charger, LED, onkey.
+
config MFD_MAX77686
tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b4569ed7f3f3..5727d099c16f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -155,6 +155,7 @@ obj-$(CONFIG_MFD_DA9150) += da9150-core.o
obj-$(CONFIG_MFD_MAX14577) += max14577.o
obj-$(CONFIG_MFD_MAX77620) += max77620.o
+obj-$(CONFIG_MFD_MAX77650) += max77650.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o
obj-$(CONFIG_MFD_MAX77843) += max77843.o
diff --git a/drivers/mfd/max77650.c b/drivers/mfd/max77650.c
new file mode 100644
index 000000000000..7a6c0a5cf602
--- /dev/null
+++ b/drivers/mfd/max77650.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// Core MFD driver for MAXIM 77650/77651 charger/power-supply.
+// Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define MAX77650_INT_GPI_F_MSK BIT(0)
+#define MAX77650_INT_GPI_R_MSK BIT(1)
+#define MAX77650_INT_GPI_MSK \
+ (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK)
+#define MAX77650_INT_nEN_F_MSK BIT(2)
+#define MAX77650_INT_nEN_R_MSK BIT(3)
+#define MAX77650_INT_TJAL1_R_MSK BIT(4)
+#define MAX77650_INT_TJAL2_R_MSK BIT(5)
+#define MAX77650_INT_DOD_R_MSK BIT(6)
+
+#define MAX77650_INT_THM_MSK BIT(0)
+#define MAX77650_INT_CHG_MSK BIT(1)
+#define MAX77650_INT_CHGIN_MSK BIT(2)
+#define MAX77650_INT_TJ_REG_MSK BIT(3)
+#define MAX77650_INT_CHGIN_CTRL_MSK BIT(4)
+#define MAX77650_INT_SYS_CTRL_MSK BIT(5)
+#define MAX77650_INT_SYS_CNFG_MSK BIT(6)
+
+#define MAX77650_INT_GLBL_OFFSET 0
+#define MAX77650_INT_CHG_OFFSET 1
+
+#define MAX77650_SBIA_LPM_MASK BIT(5)
+#define MAX77650_SBIA_LPM_DISABLED 0x00
+
+enum {
+ MAX77650_INT_GPI,
+ MAX77650_INT_nEN_F,
+ MAX77650_INT_nEN_R,
+ MAX77650_INT_TJAL1_R,
+ MAX77650_INT_TJAL2_R,
+ MAX77650_INT_DOD_R,
+ MAX77650_INT_THM,
+ MAX77650_INT_CHG,
+ MAX77650_INT_CHGIN,
+ MAX77650_INT_TJ_REG,
+ MAX77650_INT_CHGIN_CTRL,
+ MAX77650_INT_SYS_CTRL,
+ MAX77650_INT_SYS_CNFG,
+};
+
+static const struct resource max77650_charger_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"),
+ DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"),
+};
+
+static const struct resource max77650_gpio_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"),
+};
+
+static const struct resource max77650_onkey_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"),
+ DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"),
+};
+
+static const struct mfd_cell max77650_cells[] = {
+ {
+ .name = "max77650-regulator",
+ .of_compatible = "maxim,max77650-regulator",
+ },
+ {
+ .name = "max77650-charger",
+ .of_compatible = "maxim,max77650-charger",
+ .resources = max77650_charger_resources,
+ .num_resources = ARRAY_SIZE(max77650_charger_resources),
+ },
+ {
+ .name = "max77650-gpio",
+ .of_compatible = "maxim,max77650-gpio",
+ .resources = max77650_gpio_resources,
+ .num_resources = ARRAY_SIZE(max77650_gpio_resources),
+ },
+ {
+ .name = "max77650-led",
+ .of_compatible = "maxim,max77650-led",
+ },
+ {
+ .name = "max77650-onkey",
+ .of_compatible = "maxim,max77650-onkey",
+ .resources = max77650_onkey_resources,
+ .num_resources = ARRAY_SIZE(max77650_onkey_resources),
+ },
+};
+
+static const struct regmap_irq max77650_irqs[] = {
+ [MAX77650_INT_GPI] = {
+ .reg_offset = MAX77650_INT_GLBL_OFFSET,
+ .mask = MAX77650_INT_GPI_MSK,
+ .type = {
+ .type_falling_val = MAX77650_INT_GPI_F_MSK,
+ .type_rising_val = MAX77650_INT_GPI_R_MSK,
+ .types_supported = IRQ_TYPE_EDGE_BOTH,
+ },
+ },
+ REGMAP_IRQ_REG(MAX77650_INT_nEN_F,
+ MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_nEN_R,
+ MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R,
+ MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R,
+ MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_DOD_R,
+ MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_THM,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_CHG,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_CHGIN,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_TJ_REG,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK),
+ REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG,
+ MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK),
+};
+
+static const struct regmap_irq_chip max77650_irq_chip = {
+ .name = "max77650-irq",
+ .irqs = max77650_irqs,
+ .num_irqs = ARRAY_SIZE(max77650_irqs),
+ .num_regs = 2,
+ .status_base = MAX77650_REG_INT_GLBL,
+ .mask_base = MAX77650_REG_INTM_GLBL,
+ .type_in_mask = true,
+ .type_invert = true,
+ .init_ack_masked = true,
+ .clear_on_unmask = true,
+};
+
+static const struct regmap_config max77650_regmap_config = {
+ .name = "max77650",
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int max77650_i2c_probe(struct i2c_client *i2c)
+{
+ struct regmap_irq_chip_data *irq_data;
+ struct device *dev = &i2c->dev;
+ struct irq_domain *domain;
+ struct regmap *map;
+ unsigned int val;
+ int rv;
+
+ map = devm_regmap_init_i2c(i2c, &max77650_regmap_config);
+ if (IS_ERR(map)) {
+ dev_err(dev, "unable to initialize i2c regmap\n");
+ return PTR_ERR(map);
+ }
+
+ rv = regmap_read(map, MAX77650_REG_CID, &val);
+ if (rv) {
+ dev_err(dev, "unable to read the CID from device\n");
+ return rv;
+ }
+
+ switch (MAX77650_CID_BITS(val)) {
+ case MAX77650_CID_77650A:
+ case MAX77650_CID_77650C:
+ case MAX77650_CID_77651A:
+ case MAX77650_CID_77651B:
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ /*
+ * This IC has a low-power mode which reduces the quiescent current
+ * consumption to ~5.6uA but is only suitable for systems consuming
+ * less than ~2mA. Since this is not likely the case even on
+ * linux-based wearables - keep the chip in normal power mode.
+ */
+ rv = regmap_update_bits(map,
+ MAX77650_REG_CNFG_GLBL,
+ MAX77650_SBIA_LPM_MASK,
+ MAX77650_SBIA_LPM_DISABLED);
+ if (rv) {
+ dev_err(dev, "unable to change the power mode\n");
+ return rv;
+ }
+
+ rv = devm_regmap_add_irq_chip(dev, map, i2c->irq,
+ IRQF_ONESHOT | IRQF_SHARED, 0,
+ &max77650_irq_chip, &irq_data);
+ if (rv) {
+ dev_err(dev, "unable to add the regmap irq chip\n");
+ return rv;
+ }
+
+ domain = regmap_irq_get_domain(irq_data);
+
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ max77650_cells, ARRAY_SIZE(max77650_cells),
+ NULL, 0, domain);
+}
+
+static const struct of_device_id max77650_of_match[] = {
+ { .compatible = "maxim,max77650" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max77650_of_match);
+
+static struct i2c_driver max77650_i2c_driver = {
+ .driver = {
+ .name = "max77650",
+ .of_match_table = of_match_ptr(max77650_of_match),
+ },
+ .probe_new = max77650_i2c_probe,
+};
+module_i2c_driver(max77650_i2c_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/max77650.h b/include/linux/mfd/max77650.h
new file mode 100644
index 000000000000..c809e211a8cd
--- /dev/null
+++ b/include/linux/mfd/max77650.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 BayLibre SAS
+ * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ *
+ * Common definitions for MAXIM 77650/77651 charger/power-supply.
+ */
+
+#ifndef MAX77650_H
+#define MAX77650_H
+
+#include <linux/bits.h>
+
+#define MAX77650_REG_INT_GLBL 0x00
+#define MAX77650_REG_INT_CHG 0x01
+#define MAX77650_REG_STAT_CHG_A 0x02
+#define MAX77650_REG_STAT_CHG_B 0x03
+#define MAX77650_REG_ERCFLAG 0x04
+#define MAX77650_REG_STAT_GLBL 0x05
+#define MAX77650_REG_INTM_GLBL 0x06
+#define MAX77650_REG_INTM_CHG 0x07
+#define MAX77650_REG_CNFG_GLBL 0x10
+#define MAX77650_REG_CID 0x11
+#define MAX77650_REG_CNFG_GPIO 0x12
+#define MAX77650_REG_CNFG_CHG_A 0x18
+#define MAX77650_REG_CNFG_CHG_B 0x19
+#define MAX77650_REG_CNFG_CHG_C 0x1a
+#define MAX77650_REG_CNFG_CHG_D 0x1b
+#define MAX77650_REG_CNFG_CHG_E 0x1c
+#define MAX77650_REG_CNFG_CHG_F 0x1d
+#define MAX77650_REG_CNFG_CHG_G 0x1e
+#define MAX77650_REG_CNFG_CHG_H 0x1f
+#define MAX77650_REG_CNFG_CHG_I 0x20
+#define MAX77650_REG_CNFG_SBB_TOP 0x28
+#define MAX77650_REG_CNFG_SBB0_A 0x29
+#define MAX77650_REG_CNFG_SBB0_B 0x2a
+#define MAX77650_REG_CNFG_SBB1_A 0x2b
+#define MAX77650_REG_CNFG_SBB1_B 0x2c
+#define MAX77650_REG_CNFG_SBB2_A 0x2d
+#define MAX77650_REG_CNFG_SBB2_B 0x2e
+#define MAX77650_REG_CNFG_LDO_A 0x38
+#define MAX77650_REG_CNFG_LDO_B 0x39
+#define MAX77650_REG_CNFG_LED0_A 0x40
+#define MAX77650_REG_CNFG_LED1_A 0x41
+#define MAX77650_REG_CNFG_LED2_A 0x42
+#define MAX77650_REG_CNFG_LED0_B 0x43
+#define MAX77650_REG_CNFG_LED1_B 0x44
+#define MAX77650_REG_CNFG_LED2_B 0x45
+#define MAX77650_REG_CNFG_LED_TOP 0x46
+
+#define MAX77650_CID_MASK GENMASK(3, 0)
+#define MAX77650_CID_BITS(_reg) (_reg & MAX77650_CID_MASK)
+
+#define MAX77650_CID_77650A 0x03
+#define MAX77650_CID_77650C 0x0a
+#define MAX77650_CID_77651A 0x06
+#define MAX77650_CID_77651B 0x08
+
+#endif /* MAX77650_H */
--
2.21.0
^ permalink raw reply related
* [PATCH v8 07/11] power: supply: max77650: add support for battery charger
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add basic support for the battery charger for max77650 PMIC.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/power/supply/Kconfig | 7 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/max77650-charger.c | 367 ++++++++++++++++++++++++
3 files changed, 375 insertions(+)
create mode 100644 drivers/power/supply/max77650-charger.c
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index e901b9879e7e..0230c96fa94d 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -499,6 +499,13 @@ config CHARGER_DETECTOR_MAX14656
Revision 1.2 and can be found e.g. in Kindle 4/5th generation
readers and certain LG devices.
+config CHARGER_MAX77650
+ tristate "Maxim MAX77650 battery charger driver"
+ depends on MFD_MAX77650
+ help
+ Say Y to enable support for the battery charger control of MAX77650
+ PMICs.
+
config CHARGER_MAX77693
tristate "Maxim MAX77693 battery charger driver"
depends on MFD_MAX77693
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index b731c2a9b695..b73eb8c5c1a9 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
+obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c
new file mode 100644
index 000000000000..e7cca32944bd
--- /dev/null
+++ b/drivers/power/supply/max77650-charger.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// Battery charger driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+#define MAX77650_CHARGER_ENABLED BIT(0)
+#define MAX77650_CHARGER_DISABLED 0x00
+#define MAX77650_CHARGER_CHG_EN_MASK BIT(0)
+
+#define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4)
+#define MAX77650_CHG_DETAILS_BITS(_reg) \
+ (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
+
+/* Charger is OFF. */
+#define MAX77650_CHG_OFF 0x00
+/* Charger is in prequalification mode. */
+#define MAX77650_CHG_PREQ 0x01
+/* Charger is in fast-charge constant current mode. */
+#define MAX77650_CHG_ON_CURR 0x02
+/* Charger is in JEITA modified fast-charge constant-current mode. */
+#define MAX77650_CHG_ON_CURR_JEITA 0x03
+/* Charger is in fast-charge constant-voltage mode. */
+#define MAX77650_CHG_ON_VOLT 0x04
+/* Charger is in JEITA modified fast-charge constant-voltage mode. */
+#define MAX77650_CHG_ON_VOLT_JEITA 0x05
+/* Charger is in top-off mode. */
+#define MAX77650_CHG_ON_TOPOFF 0x06
+/* Charger is in JEITA modified top-off mode. */
+#define MAX77650_CHG_ON_TOPOFF_JEITA 0x07
+/* Charger is done. */
+#define MAX77650_CHG_DONE 0x08
+/* Charger is JEITA modified done. */
+#define MAX77650_CHG_DONE_JEITA 0x09
+/* Charger is suspended due to a prequalification timer fault. */
+#define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a
+/* Charger is suspended due to a fast-charge timer fault. */
+#define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b
+/* Charger is suspended due to a battery temperature fault. */
+#define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c
+
+#define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2)
+#define MAX77650_CHGIN_DETAILS_BITS(_reg) \
+ (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
+
+#define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00
+#define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01
+#define MAX77650_CHGIN_OKAY 0x11
+
+#define MAX77650_CHARGER_CHG_MASK BIT(1)
+#define MAX77650_CHARGER_CHG_CHARGING(_reg) \
+ (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
+
+#define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0
+#define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5)
+
+#define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c
+#define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2)
+
+struct max77650_charger_data {
+ struct regmap *map;
+ struct device *dev;
+};
+
+static enum power_supply_property max77650_charger_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CHARGE_TYPE
+};
+
+static const unsigned int max77650_charger_vchgin_min_table[] = {
+ 4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
+};
+
+static const unsigned int max77650_charger_ichgin_lim_table[] = {
+ 95000, 190000, 285000, 380000, 475000
+};
+
+static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
+ unsigned int val)
+{
+ int i, rv;
+
+ for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
+ if (val == max77650_charger_vchgin_min_table[i]) {
+ rv = regmap_update_bits(chg->map,
+ MAX77650_REG_CNFG_CHG_B,
+ MAX77650_CHARGER_VCHGIN_MIN_MASK,
+ MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
+ if (rv)
+ return rv;
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
+ unsigned int val)
+{
+ int i, rv;
+
+ for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
+ if (val == max77650_charger_ichgin_lim_table[i]) {
+ rv = regmap_update_bits(chg->map,
+ MAX77650_REG_CNFG_CHG_B,
+ MAX77650_CHARGER_ICHGIN_LIM_MASK,
+ MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
+ if (rv)
+ return rv;
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int max77650_charger_enable(struct max77650_charger_data *chg)
+{
+ int rv;
+
+ rv = regmap_update_bits(chg->map,
+ MAX77650_REG_CNFG_CHG_B,
+ MAX77650_CHARGER_CHG_EN_MASK,
+ MAX77650_CHARGER_ENABLED);
+ if (rv)
+ dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
+
+ return rv;
+}
+
+static int max77650_charger_disable(struct max77650_charger_data *chg)
+{
+ int rv;
+
+ rv = regmap_update_bits(chg->map,
+ MAX77650_REG_CNFG_CHG_B,
+ MAX77650_CHARGER_CHG_EN_MASK,
+ MAX77650_CHARGER_DISABLED);
+ if (rv)
+ dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
+
+ return rv;
+}
+
+static irqreturn_t max77650_charger_check_status(int irq, void *data)
+{
+ struct max77650_charger_data *chg = data;
+ int rv, reg;
+
+ rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
+ if (rv) {
+ dev_err(chg->dev,
+ "unable to read the charger status: %d\n", rv);
+ return IRQ_HANDLED;
+ }
+
+ switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
+ case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
+ dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
+ max77650_charger_disable(chg);
+ break;
+ case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
+ dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
+ max77650_charger_disable(chg);
+ break;
+ case MAX77650_CHGIN_OKAY:
+ max77650_charger_enable(chg);
+ break;
+ default:
+ /* May be 0x10 - debouncing */
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int max77650_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
+ int rv, reg;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
+ if (rv)
+ return rv;
+
+ if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ }
+
+ switch (MAX77650_CHG_DETAILS_BITS(reg)) {
+ case MAX77650_CHG_OFF:
+ case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
+ case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
+ case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case MAX77650_CHG_PREQ:
+ case MAX77650_CHG_ON_CURR:
+ case MAX77650_CHG_ON_CURR_JEITA:
+ case MAX77650_CHG_ON_VOLT:
+ case MAX77650_CHG_ON_VOLT_JEITA:
+ case MAX77650_CHG_ON_TOPOFF:
+ case MAX77650_CHG_ON_TOPOFF_JEITA:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case MAX77650_CHG_DONE:
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
+ if (rv)
+ return rv;
+
+ val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
+ if (rv)
+ return rv;
+
+ if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ }
+
+ switch (MAX77650_CHG_DETAILS_BITS(reg)) {
+ case MAX77650_CHG_PREQ:
+ case MAX77650_CHG_ON_CURR:
+ case MAX77650_CHG_ON_CURR_JEITA:
+ case MAX77650_CHG_ON_VOLT:
+ case MAX77650_CHG_ON_VOLT_JEITA:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case MAX77650_CHG_ON_TOPOFF:
+ case MAX77650_CHG_ON_TOPOFF_JEITA:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct power_supply_desc max77650_battery_desc = {
+ .name = "max77650",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .get_property = max77650_charger_get_property,
+ .properties = max77650_charger_properties,
+ .num_properties = ARRAY_SIZE(max77650_charger_properties),
+};
+
+static int max77650_charger_probe(struct platform_device *pdev)
+{
+ struct power_supply_config pscfg = {};
+ struct max77650_charger_data *chg;
+ struct power_supply *battery;
+ struct device *dev, *parent;
+ int rv, chg_irq, chgin_irq;
+ unsigned int prop;
+
+ dev = &pdev->dev;
+ parent = dev->parent;
+
+ chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, chg);
+
+ chg->map = dev_get_regmap(parent, NULL);
+ if (!chg->map)
+ return -ENODEV;
+
+ chg->dev = dev;
+
+ pscfg.of_node = dev->of_node;
+ pscfg.drv_data = chg;
+
+ chg_irq = platform_get_irq_byname(pdev, "CHG");
+ if (chg_irq < 0)
+ return chg_irq;
+
+ chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
+ if (chgin_irq < 0)
+ return chgin_irq;
+
+ rv = devm_request_any_context_irq(dev, chg_irq,
+ max77650_charger_check_status,
+ IRQF_ONESHOT, "chg", chg);
+ if (rv < 0)
+ return rv;
+
+ rv = devm_request_any_context_irq(dev, chgin_irq,
+ max77650_charger_check_status,
+ IRQF_ONESHOT, "chgin", chg);
+ if (rv < 0)
+ return rv;
+
+ battery = devm_power_supply_register(dev,
+ &max77650_battery_desc, &pscfg);
+ if (IS_ERR(battery))
+ return PTR_ERR(battery);
+
+ rv = of_property_read_u32(dev->of_node, "min-microvolt", &prop);
+ if (rv == 0) {
+ rv = max77650_charger_set_vchgin_min(chg, prop);
+ if (rv)
+ return rv;
+ }
+
+ rv = of_property_read_u32(dev->of_node,
+ "current-limit-microamp", &prop);
+ if (rv == 0) {
+ rv = max77650_charger_set_ichgin_lim(chg, prop);
+ if (rv)
+ return rv;
+ }
+
+ return max77650_charger_enable(chg);
+}
+
+static int max77650_charger_remove(struct platform_device *pdev)
+{
+ struct max77650_charger_data *chg = platform_get_drvdata(pdev);
+
+ return max77650_charger_disable(chg);
+}
+
+static struct platform_driver max77650_charger_driver = {
+ .driver = {
+ .name = "max77650-charger",
+ },
+ .probe = max77650_charger_probe,
+ .remove = max77650_charger_remove,
+};
+module_platform_driver(max77650_charger_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
--
2.21.0
^ permalink raw reply related
* [PATCH v8 08/11] gpio: max77650: add GPIO support
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add GPIO support for max77650 mfd device. This PMIC exposes a single
GPIO line.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/gpio/Kconfig | 7 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-max77650.c | 190 +++++++++++++++++++++++++++++++++++
3 files changed, 198 insertions(+)
create mode 100644 drivers/gpio/gpio-max77650.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3f50526a771f..c4f912104440 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1112,6 +1112,13 @@ config GPIO_MAX77620
driver also provides interrupt support for each of the gpios.
Say yes here to enable the max77620 to be used as gpio controller.
+config GPIO_MAX77650
+ tristate "Maxim MAX77650/77651 GPIO support"
+ depends on MFD_MAX77650
+ help
+ GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor.
+ These chips have a single pin that can be configured as GPIO.
+
config GPIO_MSIC
bool "Intel MSIC mixed signal gpio support"
depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 54d55274b93a..075722d8317d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
+obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
diff --git a/drivers/gpio/gpio-max77650.c b/drivers/gpio/gpio-max77650.c
new file mode 100644
index 000000000000..3f03f4e8956c
--- /dev/null
+++ b/drivers/gpio/gpio-max77650.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// GPIO driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_GPIO_DIR_MASK BIT(0)
+#define MAX77650_GPIO_INVAL_MASK BIT(1)
+#define MAX77650_GPIO_DRV_MASK BIT(2)
+#define MAX77650_GPIO_OUTVAL_MASK BIT(3)
+#define MAX77650_GPIO_DEBOUNCE_MASK BIT(4)
+
+#define MAX77650_GPIO_DIR_OUT 0x00
+#define MAX77650_GPIO_DIR_IN BIT(0)
+#define MAX77650_GPIO_OUT_LOW 0x00
+#define MAX77650_GPIO_OUT_HIGH BIT(3)
+#define MAX77650_GPIO_DRV_OPEN_DRAIN 0x00
+#define MAX77650_GPIO_DRV_PUSH_PULL BIT(2)
+#define MAX77650_GPIO_DEBOUNCE BIT(4)
+
+#define MAX77650_GPIO_DIR_BITS(_reg) \
+ ((_reg) & MAX77650_GPIO_DIR_MASK)
+#define MAX77650_GPIO_INVAL_BITS(_reg) \
+ (((_reg) & MAX77650_GPIO_INVAL_MASK) >> 1)
+
+struct max77650_gpio_chip {
+ struct regmap *map;
+ struct gpio_chip gc;
+ int irq;
+};
+
+static int max77650_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+ return regmap_update_bits(chip->map,
+ MAX77650_REG_CNFG_GPIO,
+ MAX77650_GPIO_DIR_MASK,
+ MAX77650_GPIO_DIR_IN);
+}
+
+static int max77650_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int offset, int value)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+ int mask, regval;
+
+ mask = MAX77650_GPIO_DIR_MASK | MAX77650_GPIO_OUTVAL_MASK;
+ regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
+ regval |= MAX77650_GPIO_DIR_OUT;
+
+ return regmap_update_bits(chip->map,
+ MAX77650_REG_CNFG_GPIO, mask, regval);
+}
+
+static void max77650_gpio_set_value(struct gpio_chip *gc,
+ unsigned int offset, int value)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+ int rv, regval;
+
+ regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
+
+ rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO,
+ MAX77650_GPIO_OUTVAL_MASK, regval);
+ if (rv)
+ dev_err(gc->parent, "cannot set GPIO value: %d\n", rv);
+}
+
+static int max77650_gpio_get_value(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+ unsigned int val;
+ int rv;
+
+ rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
+ if (rv)
+ return rv;
+
+ return MAX77650_GPIO_INVAL_BITS(val);
+}
+
+static int max77650_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+ unsigned int val;
+ int rv;
+
+ rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
+ if (rv)
+ return rv;
+
+ return MAX77650_GPIO_DIR_BITS(val);
+}
+
+static int max77650_gpio_set_config(struct gpio_chip *gc,
+ unsigned int offset, unsigned long cfg)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+ switch (pinconf_to_config_param(cfg)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ return regmap_update_bits(chip->map,
+ MAX77650_REG_CNFG_GPIO,
+ MAX77650_GPIO_DRV_MASK,
+ MAX77650_GPIO_DRV_OPEN_DRAIN);
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return regmap_update_bits(chip->map,
+ MAX77650_REG_CNFG_GPIO,
+ MAX77650_GPIO_DRV_MASK,
+ MAX77650_GPIO_DRV_PUSH_PULL);
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return regmap_update_bits(chip->map,
+ MAX77650_REG_CNFG_GPIO,
+ MAX77650_GPIO_DEBOUNCE_MASK,
+ MAX77650_GPIO_DEBOUNCE);
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int max77650_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+ struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
+
+ return chip->irq;
+}
+
+static int max77650_gpio_probe(struct platform_device *pdev)
+{
+ struct max77650_gpio_chip *chip;
+ struct device *dev, *parent;
+ struct i2c_client *i2c;
+
+ dev = &pdev->dev;
+ parent = dev->parent;
+ i2c = to_i2c_client(parent);
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->map = dev_get_regmap(parent, NULL);
+ if (!chip->map)
+ return -ENODEV;
+
+ chip->irq = platform_get_irq_byname(pdev, "GPI");
+ if (chip->irq < 0)
+ return chip->irq;
+
+ chip->gc.base = -1;
+ chip->gc.ngpio = 1;
+ chip->gc.label = i2c->name;
+ chip->gc.parent = dev;
+ chip->gc.owner = THIS_MODULE;
+ chip->gc.can_sleep = true;
+
+ chip->gc.direction_input = max77650_gpio_direction_input;
+ chip->gc.direction_output = max77650_gpio_direction_output;
+ chip->gc.set = max77650_gpio_set_value;
+ chip->gc.get = max77650_gpio_get_value;
+ chip->gc.get_direction = max77650_gpio_get_direction;
+ chip->gc.set_config = max77650_gpio_set_config;
+ chip->gc.to_irq = max77650_gpio_to_irq;
+
+ return devm_gpiochip_add_data(dev, &chip->gc, chip);
+}
+
+static struct platform_driver max77650_gpio_driver = {
+ .driver = {
+ .name = "max77650-gpio",
+ },
+ .probe = max77650_gpio_probe,
+};
+module_platform_driver(max77650_gpio_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
--
2.21.0
^ permalink raw reply related
* [PATCH v8 09/11] leds: max77650: add LEDs support
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This adds basic support for LEDs for the max77650 PMIC. The device has
three current sinks for driving LEDs.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
---
drivers/leds/Kconfig | 6 ++
drivers/leds/Makefile | 1 +
drivers/leds/leds-max77650.c | 147 +++++++++++++++++++++++++++++++++++
3 files changed, 154 insertions(+)
create mode 100644 drivers/leds/leds-max77650.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a72f97fca57b..d8c70cc6a714 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -608,6 +608,12 @@ config LEDS_TLC591XX
This option enables support for Texas Instruments TLC59108
and TLC59116 LED controllers.
+config LEDS_MAX77650
+ tristate "LED support for Maxim MAX77650 PMIC"
+ depends on LEDS_CLASS && MFD_MAX77650
+ help
+ LEDs driver for MAX77650 family of PMICs from Maxim Integrated.
+
config LEDS_MAX77693
tristate "LED support for MAX77693 Flash"
depends on LEDS_CLASS_FLASH
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 4c1b0054f379..f48b2404dbb7 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
+obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c
new file mode 100644
index 000000000000..6b74ce9cac12
--- /dev/null
+++ b/drivers/leds/leds-max77650.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// LED driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_LED_NUM_LEDS 3
+
+#define MAX77650_LED_A_BASE 0x40
+#define MAX77650_LED_B_BASE 0x43
+
+#define MAX77650_LED_BR_MASK GENMASK(4, 0)
+#define MAX77650_LED_EN_MASK GENMASK(7, 6)
+
+#define MAX77650_LED_MAX_BRIGHTNESS MAX77650_LED_BR_MASK
+
+/* Enable EN_LED_MSTR. */
+#define MAX77650_LED_TOP_DEFAULT BIT(0)
+
+#define MAX77650_LED_ENABLE GENMASK(7, 6)
+#define MAX77650_LED_DISABLE 0x00
+
+#define MAX77650_LED_A_DEFAULT MAX77650_LED_DISABLE
+/* 100% on duty */
+#define MAX77650_LED_B_DEFAULT GENMASK(3, 0)
+
+struct max77650_led {
+ struct led_classdev cdev;
+ struct regmap *map;
+ unsigned int regA;
+ unsigned int regB;
+};
+
+static struct max77650_led *max77650_to_led(struct led_classdev *cdev)
+{
+ return container_of(cdev, struct max77650_led, cdev);
+}
+
+static int max77650_led_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct max77650_led *led = max77650_to_led(cdev);
+ int val, mask;
+
+ mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK;
+
+ if (brightness == LED_OFF)
+ val = MAX77650_LED_DISABLE;
+ else
+ val = MAX77650_LED_ENABLE | brightness;
+
+ return regmap_update_bits(led->map, led->regA, mask, val);
+}
+
+static int max77650_led_probe(struct platform_device *pdev)
+{
+ struct device_node *of_node, *child;
+ struct max77650_led *leds, *led;
+ struct device *parent;
+ struct device *dev;
+ struct regmap *map;
+ const char *label;
+ int rv, num_leds;
+ u32 reg;
+
+ dev = &pdev->dev;
+ parent = dev->parent;
+ of_node = dev->of_node;
+
+ if (!of_node)
+ return -ENODEV;
+
+ leds = devm_kcalloc(dev, sizeof(*leds),
+ MAX77650_LED_NUM_LEDS, GFP_KERNEL);
+ if (!leds)
+ return -ENOMEM;
+
+ map = dev_get_regmap(dev->parent, NULL);
+ if (!map)
+ return -ENODEV;
+
+ num_leds = of_get_child_count(of_node);
+ if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS)
+ return -ENODEV;
+
+ for_each_child_of_node(of_node, child) {
+ rv = of_property_read_u32(child, "reg", ®);
+ if (rv || reg >= MAX77650_LED_NUM_LEDS)
+ return -EINVAL;
+
+ led = &leds[reg];
+ led->map = map;
+ led->regA = MAX77650_LED_A_BASE + reg;
+ led->regB = MAX77650_LED_B_BASE + reg;
+ led->cdev.brightness_set_blocking = max77650_led_brightness_set;
+ led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
+
+ label = of_get_property(child, "label", NULL);
+ if (!label) {
+ led->cdev.name = "max77650::";
+ } else {
+ led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
+ "max77650:%s", label);
+ if (!led->cdev.name)
+ return -ENOMEM;
+ }
+
+ of_property_read_string(child, "linux,default-trigger",
+ &led->cdev.default_trigger);
+
+ rv = devm_of_led_classdev_register(dev, child, &led->cdev);
+ if (rv)
+ return rv;
+
+ rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT);
+ if (rv)
+ return rv;
+
+ rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT);
+ if (rv)
+ return rv;
+ }
+
+ return regmap_write(map,
+ MAX77650_REG_CNFG_LED_TOP,
+ MAX77650_LED_TOP_DEFAULT);
+}
+
+static struct platform_driver max77650_led_driver = {
+ .driver = {
+ .name = "max77650-led",
+ },
+ .probe = max77650_led_probe,
+};
+module_platform_driver(max77650_led_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
--
2.21.0
^ permalink raw reply related
* [PATCH v8 10/11] input: max77650: add onkey support
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Add support for the push- and slide-button events for max77650.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/input/misc/Kconfig | 9 +++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/max77650-onkey.c | 121 ++++++++++++++++++++++++++++
3 files changed, 131 insertions(+)
create mode 100644 drivers/input/misc/max77650-onkey.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index e15ed1bb8558..85bc675eecd3 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -190,6 +190,15 @@ config INPUT_M68K_BEEP
tristate "M68k Beeper support"
depends on M68K
+config INPUT_MAX77650_ONKEY
+ tristate "Maxim MAX77650 ONKEY support"
+ depends on MFD_MAX77650
+ help
+ Support the ONKEY of the MAX77650 PMIC as an input device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called max77650-onkey.
+
config INPUT_MAX77693_HAPTIC
tristate "MAXIM MAX77693/MAX77843 haptic controller support"
depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b936c5b1d4ac..ffd72161c79b 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c
new file mode 100644
index 000000000000..fbf6caab7217
--- /dev/null
+++ b/drivers/input/misc/max77650-onkey.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// ONKEY driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_ONKEY_MODE_MASK BIT(3)
+#define MAX77650_ONKEY_MODE_PUSH 0x00
+#define MAX77650_ONKEY_MODE_SLIDE BIT(3)
+
+struct max77650_onkey {
+ struct input_dev *input;
+ unsigned int code;
+};
+
+static irqreturn_t max77650_onkey_falling(int irq, void *data)
+{
+ struct max77650_onkey *onkey = data;
+
+ input_report_key(onkey->input, onkey->code, 0);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max77650_onkey_rising(int irq, void *data)
+{
+ struct max77650_onkey *onkey = data;
+
+ input_report_key(onkey->input, onkey->code, 1);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int max77650_onkey_probe(struct platform_device *pdev)
+{
+ int irq_r, irq_f, error, mode;
+ struct max77650_onkey *onkey;
+ struct device *dev, *parent;
+ struct regmap *map;
+ unsigned int type;
+
+ dev = &pdev->dev;
+ parent = dev->parent;
+
+ map = dev_get_regmap(parent, NULL);
+ if (!map)
+ return -ENODEV;
+
+ onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ error = device_property_read_u32(dev, "linux,code", &onkey->code);
+ if (error)
+ onkey->code = KEY_POWER;
+
+ if (device_property_read_bool(dev, "maxim,onkey-slide")) {
+ mode = MAX77650_ONKEY_MODE_SLIDE;
+ type = EV_SW;
+ } else {
+ mode = MAX77650_ONKEY_MODE_PUSH;
+ type = EV_KEY;
+ }
+
+ error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL,
+ MAX77650_ONKEY_MODE_MASK, mode);
+ if (error)
+ return error;
+
+ irq_f = platform_get_irq_byname(pdev, "nEN_F");
+ if (irq_f < 0)
+ return irq_f;
+
+ irq_r = platform_get_irq_byname(pdev, "nEN_R");
+ if (irq_r < 0)
+ return irq_r;
+
+ onkey->input = devm_input_allocate_device(dev);
+ if (!onkey->input)
+ return -ENOMEM;
+
+ onkey->input->name = "max77650_onkey";
+ onkey->input->phys = "max77650_onkey/input0";
+ onkey->input->id.bustype = BUS_I2C;
+ input_set_capability(onkey->input, type, onkey->code);
+
+ error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling,
+ IRQF_ONESHOT, "onkey-down", onkey);
+ if (error < 0)
+ return error;
+
+ error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising,
+ IRQF_ONESHOT, "onkey-up", onkey);
+ if (error < 0)
+ return error;
+
+ return input_register_device(onkey->input);
+}
+
+static struct platform_driver max77650_onkey_driver = {
+ .driver = {
+ .name = "max77650-onkey",
+ },
+ .probe = max77650_onkey_probe,
+};
+module_platform_driver(max77650_onkey_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
--
2.21.0
^ permalink raw reply related
* [PATCH v8 11/11] MAINTAINERS: add an entry for max77650 mfd driver
From: Bartosz Golaszewski @ 2019-04-03 9:01 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Linus Walleij, Dmitry Torokhov,
Jacek Anaszewski, Pavel Machek, Lee Jones, Sebastian Reichel,
Liam Girdwood, Greg Kroah-Hartman
Cc: linux-kernel, linux-gpio, devicetree, linux-input, linux-leds,
linux-pm, Bartosz Golaszewski
In-Reply-To: <20190403090108.24788-1-brgl@bgdev.pl>
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
I plan on extending this set of drivers so add myself as maintainer.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
MAINTAINERS | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 43b36dbed48e..d8bdaeb72b95 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9406,6 +9406,20 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/max9860.txt
F: sound/soc/codecs/max9860.*
+MAXIM MAX77650 PMIC MFD DRIVER
+M: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/*/*max77650.txt
+F: Documentation/devicetree/bindings/*/max77650*.txt
+F: include/linux/mfd/max77650.h
+F: drivers/mfd/max77650.c
+F: drivers/regulator/max77650-regulator.c
+F: drivers/power/supply/max77650-charger.c
+F: drivers/input/misc/max77650-onkey.c
+F: drivers/leds/leds-max77650.c
+F: drivers/gpio/gpio-max77650.c
+
MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
M: Javier Martinez Canillas <javier@dowhile0.org>
L: linux-kernel@vger.kernel.org
--
2.21.0
^ permalink raw reply related
* Re: [PATCH 2/6] input: da9063_onkey: remove platform_data support
From: Wolfram Sang @ 2019-04-03 9:24 UTC (permalink / raw)
To: Steve Twiss
Cc: Wolfram Sang, Dmitry Torokhov, LKML,
linux-renesas-soc@vger.kernel.org, Lee Jones, Mark Brown,
Support Opensource, linux-input@vger.kernel.org
In-Reply-To: <VI1PR10MB2352701871983EF8677C5CB8FE5A0@VI1PR10MB2352.EURPRD10.PROD.OUTLOOK.COM>
[-- Attachment #1: Type: text/plain, Size: 635 bytes --]
> > Subject: [PATCH 2/6] input: da9063_onkey: remove platform_data support
> >
> > There are no in-kernel users anymore, so remove this outdated interface.
> >
> > Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> > ---
> > drivers/input/misc/da9063_onkey.c | 11 ++---------
> > 1 file changed, 2 insertions(+), 9 deletions(-)
>
> Thanks!
> Acked-by: Steve Twiss <stwiss.opensource@diasemi.com>
> Tested-by: Steve Twiss <stwiss.opensource@diasemi.com>
Dmitry, if you are OK with the series going in via MFD, could you ack
this patch? As you see, Steve is fine with the patch and tested it, too.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Kai-Heng Feng @ 2019-04-03 9:24 UTC (permalink / raw)
To: Mario.Limonciello
Cc: Andy Shevchenko, Hans de Goede, benjamin.tissoires, hotwater438,
jikos, swboyd, bigeasy, dtor, linux-input, linux-kernel
In-Reply-To: <16218e1c23bb4cb6b0b739d561a707bc@ausx13mpc120.AMER.DELL.COM>
at 22:08, <Mario.Limonciello@dell.com> <Mario.Limonciello@dell.com> wrote:
>> -----Original Message-----
>> From: Kai Heng Feng <kai.heng.feng@canonical.com>
>> Sent: Monday, April 1, 2019 11:18 PM
>> To: Limonciello, Mario
>> Cc: Andy Shevchenko; hdegoede@redhat.com; benjamin.tissoires@redhat.com;
>> hotwater438@tutanota.com; jikos@kernel.org; swboyd@chromium.org;
>> bigeasy@linutronix.de; dtor@chromium.org; linux-input@vger.kernel.org;
>> linux-
>> kernel@vger.kernel.org
>> Subject: Re: [PATCH] ELAN touchpad i2c_hid bugs fix
>>
>>
>> [EXTERNAL EMAIL]
>>
>>
>>
>>> On Apr 2, 2019, at 5:37 AM, <Mario.Limonciello@dell.com>
>>> <Mario.Limonciello@dell.com> wrote:
>>>
>>>> -----Original Message-----
>>>> From: Andy Shevchenko <andy.shevchenko@gmail.com>
>>>> Sent: Thursday, March 21, 2019 4:48 AM
>>>> To: Kai-Heng Feng; Limonciello, Mario
>>>> Cc: Hans de Goede; Benjamin Tissoires; hotwater438@tutanota.com; Jiri
>>>> Kosina;
>>>> Stephen Boyd; Sebastian Andrzej Siewior; Dmitry Torokhov; open list:HID
>>>> CORE
>>>> LAYER; lkml
>>>> Subject: Re: [PATCH] ELAN touchpad i2c_hid bugs fix
>>>>
>>>>
>>>> [EXTERNAL EMAIL]
>>>>
>>>> +Cc: Mario
>>>>
>>>> Mario, do you have any insights about the issue with touchpad on Dell
>>>> system described below?
>>>
>>> My apologies, this got lost while I was on vacation.
>>>
>>>> On Thu, Mar 21, 2019 at 6:08 AM Kai-Heng Feng
>>>> <kai.heng.feng@canonical.com> wrote:
>>>>> at 01:18, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>>>>>
>>>>>> On Wed, Mar 20, 2019 at 6:55 PM Kai-Heng Feng
>>>>>> <kai.heng.feng@canonical.com> wrote:
>>>>>>> at 23:39, Hans de Goede <hdegoede@redhat.com> wrote:
>>>>>>>> On 3/20/19 3:37 PM, Benjamin Tissoires wrote:
>>>>>>
>>>>>>>> Benjamin, what I find interesting here is that the BOGUS_IRQ quirk
>>>>>>>> is also used on Elan devices, I suspect that these Elan devices
>>>>>>>> likely also need the I2C_HID_QUIRK_FORCE_TRIGGER_FALLING quirk
>>>>>>>> and then they probably will no longer need the bogus IRQ flag,
>>>>>>>> if you know about bugreports with an acpidump for any of the devices
>>>>>>>> needing the bogus IRQ quirk, then I (or you) can check how the IRQ
>>>>>>>> is
>>>>>>>> declared there, I suspect it will be declared as level-low, just
>>>>>>>> like
>>>>>>>> with the laptop this patch was written for. And it probably need to
>>>>>>>> be edge-falling instead of level-low just like this case.
>>>>>>>
>>>>>>> First, I’ve already tried using IRQF_TRIGGER_FALLING, unfortunately
>>>>>>> it
>>>>>>> doesn’t solve the issue for me.
>>>>>>>
>>>>>>> I talked to Elan once, and they confirm the correct IRQ trigger is
>>>>>>> level
>>>>>>> low. So forcing falling trigger may break other platforms.
>>>>>>
>>>>>> As far as I understood Vladislav the quirk he got from Elan as well.
>>>>>
>>>>> Ok, then this is really weird.
>>>>>
>>>>>>> Recently we found that Elan touchpad doesn’t like GpioInt() from its
>>>>>>> _CRS.
>>>>>>> Once the Interrupt() is used instead, the issue goes away.
>>>>>>
>>>>>> IIRC i2c core tries to get interrupt from Interrupt() resource and
>>>>>> then falls back to GpioInt().
>>>>>> See i2c_acpi_get_info() and i2c_device_probe().
>>>>>
>>>>> Here’s its ASL:
>>>>>
>>>>> Scope (\_SB.PCI0.I2C4)
>>>>> {
>>>>> Device (TPD0)
>>>>> {
>>>>> Name (_ADR, One) // _ADR: Address
>>>>> Name (_HID, "DELL08AE") // _HID: Hardware ID
>>>>> Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID:
>>>> Compatible ID
>>>>> Name (_UID, One) // _UID: Unique ID
>>>>> Name (_S0W, 0x04) // _S0W: S0 Device Wake State
>>>>> Name (SBFB, ResourceTemplate ()
>>>>> {
>>>>> I2cSerialBusV2 (0x002C, ControllerInitiated, 0x00061A80,
>>>>> AddressingMode7Bit, "\\_SB.PCI0.I2C4",
>>>>> 0x00, ResourceConsumer, , Exclusive,
>>>>> )
>>>>> })
>>>>> Name (SBFG, ResourceTemplate ()
>>>>> {
>>>>> GpioInt (Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
>>>>> "\\_SB.GPO1", 0x00, ResourceConsumer, ,
>>>>> )
>>>>> { // Pin list
>>>>> 0x0012
>>>>> }
>>>>> })
>>>>> Name (SBFI, ResourceTemplate ()
>>>>> {
>>>>> Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, )
>>>>> {
>>>>> 0x0000003C,
>>>>> }
>>>>> })
>>>>> Method (_INI, 0, NotSerialized) // _INI: Initialize
>>>>> {
>>>>> }
>>>>> Method (_STA, 0, NotSerialized) // _STA: Status
>>>>> {
>>>>> If ((TCPD == One))
>>>>> {
>>>>> Return (0x0F)
>>>>> }
>>>>>
>>>>> Return (Zero)
>>>>> }
>>>>> Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
>>>>> {
>>>>> If ((OSYS < 0x07DC))
>>>>> {
>>>>> Return (SBFI) /* \_SB_.PCI0.I2C4.TPD0.SBFI */
>>>>> }
>>>>>
>>>>> Return (ConcatenateResTemplate (SBFB, SBFG))
>>>>> }
>>>>> Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
>>>>> {
>>>>> If ((Arg0 == ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /*
>> HID
>>>> I2C Device */))
>>>>> {
>>>>> If ((Arg2 == Zero))
>>>>> {
>>>>> If ((Arg1 == One))
>>>>> {
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x03 // .
>>>>> })
>>>>> }
>>>>> Else
>>>>> {
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x00 // .
>>>>> })
>>>>> }
>>>>> }
>>>>> ElseIf ((Arg2 == One))
>>>>> {
>>>>> Return (0x20)
>>>>> }
>>>>> Else
>>>>> {
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x00 // .
>>>>> })
>>>>> }
>>>>> }
>>>>> ElseIf ((Arg0 == ToUUID ("ef87eb82-f951-46da-84ec-14871ac6f84b")))
>>>>> {
>>>>> If ((Arg2 == Zero))
>>>>> {
>>>>> If ((Arg1 == One))
>>>>> {
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x03 // .
>>>>> })
>>>>> }
>>>>> }
>>>>>
>>>>> If ((Arg2 == One))
>>>>> {
>>>>> Return (ConcatenateResTemplate (SBFB, SBFG))
>>>>> }
>>>>>
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x00 // .
>>>>> })
>>>>> }
>>>>> }
>>>>> Else
>>>>> {
>>>>> Return (Buffer (One)
>>>>> {
>>>>> 0x00 // .
>>>>> })
>>>>> }
>>>>> }
>>>>> }
>>>>> }
>>>>>
>>>>> Change SBFG to SBFI in its _CRS can workaround the issue.
>>>>> Is ASL in this form possible to do the flow you described?
>>>>>
>>>>> Kai-Heng
>>>>>
>>>>>>> But I am not sure how to patch its DSDT/SSDT in i2c-hid.
>>>
>>> Is this pre-production HW? If so, maybe this is a case that we should
>>> talk
>>> about custom OSI string to run the ASL differently.
>>
>> Some are already shipped.
>>
>>
>>> The other option would be to create a new ASL method in FW and from Linux
>>> side a quirk that calls this new ASL method.
>>
>> Since this patch is for ASUS Laptop, I think a more generic solution from
>> driver layer is preferred.
>
> I thought this ASL was from Dell laptop. The HID make it looks like it
> at least.
Yes this ASL is from a Dell system.
>>>>> Name (_HID, "DELL08AE") // _HID: Hardware ID
>
> In general more generic solution from driver layer is preferred I agree.
> You might
> need to check with ACPI guys to see if they have some ideas on situations
> that
> GpioInt fail.
I’ve filed a bug here but we don’t find any proper solution:
https://bugzilla.kernel.org/show_bug.cgi?id=201311
Kai-Heng
^ permalink raw reply
* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Hans de Goede @ 2019-04-03 11:18 UTC (permalink / raw)
To: hotwater438
Cc: Dmitry Torokhov, Vladislav Dalechyn, Benjamin Tissoires,
Jiri Kosina, Kai Heng Feng, Swboyd, Bigeasy,
open list:HID CORE LAYER, lkml
In-Reply-To: <LbI7kio--3-1@tutanota.com>
Hi,
On 31-03-19 11:50, hotwater438@tutanota.com wrote:
> Hi. I've done everything you said, here are results:
>
> Vladislav can you check the output of /cat/interrupts on a kernel
> without the patch and while *not* using the touchpad; and check
> if the amount of touchpads-interrupts still keeps increasing in this
> case?
>
> IWI or IRQ work interrupts keep increasing with speed at least 3 interrupts/s.
I'm really only interested in the touchpad related IRQs, so e.g. the line
about "intel-gpio 129 ELAN1200:00", if you're seeing 3 interrupts/s on
some others that is fine, so I take it the ELAN1200:00 interrupt count
does not increase on an *unpatched* kernel, unless you use the touchpad?
> Also when I am moving touchpad IR-IO-APIC 14-fasteoi INT345D:00 get's triggered and increased.
That is the GPIO controller interrupt, so that one increasing is normal.
If I understand things correctly then this all means that the IRQ indeed
is a normal level IRQ and Dmitry is likely correct that there is an
pinctrl / gpiochip driver problem here.
Can you try the following with an *unpatched* kernel? :
1) Run "cat /proc/interrupts | grep ELAN" , note down the value
2) Very quickly/briefly touch the touchpad once
3) Run "cat /proc/interrupts | grep ELAN" , note down the value again
4) Subtract result from 1. from result from 3, this difference is
the value we are interested in. E.g. my testing got 254 and 257, so
a difference of 3.
The goal here is to get an as low as possible difference. Feel free
to repeat this a couple of times.
On an Apollo Lake laptop with an I2C hid mt touchpad I can get the
amount of interrupts triggered for a single touch down to 3,
given the huge interrupt counts of 130000+ reported in:
https://bugzilla.redhat.com/show_bug.cgi?id=1543769
I expect you to get a much bigger smallest possible difference
between 2 "cat /proc/interrupts | grep ELAN" commands, note a
difference of 0 means your touch did not register.
Assuming you indeed see much more interrupts for a very quick
touch + release, then we indeed have an interrupt handling problem
we need to investigate further.
> I don't know if it's important or not, but for some reason these interrupts keep popping only on CPU2 (i have 4cpu processor).
That does not matter.
> 1) Suspending the machine by selecting suspend from a menu in your
> desktop environment, or by briefly pressing the power-button, do
> not close the lid
> 2) As soon as the system starts suspending and while it is suspended, move
> your finger around the touchpad
> 3) Wake the system up with the powerbutton while moving your finger around
> 4) Check if the touchpad still works after this
>
> It works, but as it seems, looses edge. JournalCTL is being flooded with i2c_hid_get_input: incomplete report (16/65535)
That is probably a different issue. If you loose the edge IRQ, then the touchpad
would stop working without any messages. I believe that the suspend / resume
issue may be fixed by:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=52cf93e63ee672a92f349edc6ddad86ec8808fd8
Does your kernel have this commit? (please always use the latest kernel while
testing).
> Also a thing to notice, that after manually removing and modprobing i2c_hid module, it says next in journalctl:
>
> i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00 supply vdd not found, using dummy regulator
> i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00 supply vddl not found, using dummy regulator
Those messages can safely be ignored.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH] HID: input: add mapping for Assistant key
From: Jiri Kosina @ 2019-04-03 11:34 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <20190402165713.GA161074@dtor-ws>
On Tue, 2 Apr 2019, Dmitry Torokhov wrote:
> According to HUTRR89 usage 0x1cb from the consumer page was assigned to
> allow launching desktop-aware assistant application, so let's add the
> mapping.
>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Applied, thanks Dmitry.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v5] HID: intel-ish-hid: ISH firmware loader client driver
From: Jiri Kosina @ 2019-04-03 13:11 UTC (permalink / raw)
To: Rushikesh S Kadam
Cc: srinivas.pandruvada, benjamin.tissoires, ncrews, jettrink,
gwendal, linux-kernel, linux-input
In-Reply-To: <1554184061-2872-1-git-send-email-rushikesh.s.kadam@intel.com>
On Tue, 2 Apr 2019, Rushikesh S Kadam wrote:
> This driver adds support for loading Intel Integrated
> Sensor Hub (ISH) firmware from host file system to ISH
> SRAM and start execution.
>
> At power-on, the ISH subsystem shall boot to an interim
> Shim loader-firmware, which shall expose an ISHTP loader
> device.
>
> The driver implements an ISHTP client that communicates
> with the Shim ISHTP loader device over the intel-ish-hid
> stack, to download the main ISH firmware.
>
> Signed-off-by: Rushikesh S Kadam <rushikesh.s.kadam@intel.com>
> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> Acked-by: Nick Crews <ncrews@chromium.org>
> Tested-by: Jett Rink <jettrink@chromium.org>
Now queued in for-5.2/ish. Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH v5] HID: intel-ish-hid: ISH firmware loader client driver
From: Rushikesh S Kadam @ 2019-04-03 13:35 UTC (permalink / raw)
To: Jiri Kosina
Cc: srinivas.pandruvada, benjamin.tissoires, ncrews, jettrink,
gwendal, linux-kernel, linux-input
In-Reply-To: <nycvar.YFH.7.76.1904031510430.9803@cbobk.fhfr.pm>
On Wed, Apr 03, 2019 at 03:11:02PM +0200, Jiri Kosina wrote:
> On Tue, 2 Apr 2019, Rushikesh S Kadam wrote:
>
> > This driver adds support for loading Intel Integrated
> > Sensor Hub (ISH) firmware from host file system to ISH
> > SRAM and start execution.
> >
> > At power-on, the ISH subsystem shall boot to an interim
> > Shim loader-firmware, which shall expose an ISHTP loader
> > device.
> >
> > The driver implements an ISHTP client that communicates
> > with the Shim ISHTP loader device over the intel-ish-hid
> > stack, to download the main ISH firmware.
> >
> > Signed-off-by: Rushikesh S Kadam <rushikesh.s.kadam@intel.com>
> > Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> > Acked-by: Nick Crews <ncrews@chromium.org>
> > Tested-by: Jett Rink <jettrink@chromium.org>
>
> Now queued in for-5.2/ish. Thanks,
>
> --
> Jiri Kosina
> SUSE Labs
>
Thanks Jirk & all for help with this.
Rushikesh
--
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox