Lines Matching +full:cmd +full:- +full:gpios

1 // SPDX-License-Identifier: GPL-2.0
14 #include <linux/devm-helpers.h>
26 #include <linux/turris-omnia-mcu-interface.h>
27 #include "turris-omnia-mcu.h"
33 /* GPIOs with value read from the 16-bit wide status */
36 [6] = "Front USB3 port over-current",
37 [7] = "Rear USB3 port over-current",
42 /* GPIOs with value read from the 32-bit wide extended status */
65 /* GPIOs with value read from the 16-bit wide extended control status */
77 u8 cmd; member
90 .cmd = _cmd, \
107 -1, 0, 0)
132 __bf_shf(OMNIA_EXT_CTL_ ## _name), -1, \
141 return gpio->int_bit != OMNIA_GPIO_INVALID_INT_BIT; in is_int_bit_valid()
145 /* GPIOs with value read from the 16-bit wide status */
164 /* GPIOs with value read from the 32-bit wide extended status */
187 /* GPIOs with value read from the 16-bit wide extended control status */
198 /* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
234 static int omnia_ctl_cmd_locked(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask) in omnia_ctl_cmd_locked() argument
239 buf[0] = cmd; in omnia_ctl_cmd_locked()
241 switch (cmd) { in omnia_ctl_cmd_locked()
258 return omnia_cmd_write(mcu->client, buf, len); in omnia_ctl_cmd_locked()
261 static int omnia_ctl_cmd(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask) in omnia_ctl_cmd() argument
263 guard(mutex)(&mcu->lock); in omnia_ctl_cmd()
265 return omnia_ctl_cmd_locked(mcu, cmd, val, mask); in omnia_ctl_cmd()
270 if (!omnia_gpios[offset].cmd) in omnia_gpio_request()
271 return -EINVAL; in omnia_gpio_request()
283 scoped_guard(mutex, &mcu->lock) { in omnia_gpio_get_direction()
284 val = omnia_cmd_read_bit(mcu->client, in omnia_gpio_get_direction()
313 if (gpio->ctl_cmd) in omnia_gpio_direction_input()
314 return -ENOTSUPP; in omnia_gpio_direction_input()
326 if (!gpio->ctl_cmd) in omnia_gpio_direction_output()
327 return -ENOTSUPP; in omnia_gpio_direction_output()
329 mask = BIT(gpio->ctl_bit); in omnia_gpio_direction_output()
335 return omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask); in omnia_gpio_direction_output()
349 if (gpio->cmd == OMNIA_CMD_GET_STATUS_WORD && in omnia_gpio_get()
350 !(mcu->features & OMNIA_FEAT_NEW_INT_API)) in omnia_gpio_get()
351 return test_bit(gpio->bit, &mcu->last_status); in omnia_gpio_get()
353 guard(mutex)(&mcu->lock); in omnia_gpio_get()
360 if (is_int_bit_valid(gpio) && test_bit(gpio->int_bit, &mcu->is_cached)) in omnia_gpio_get()
361 return test_bit(gpio->int_bit, &mcu->cached); in omnia_gpio_get()
363 return omnia_cmd_read_bit(mcu->client, gpio->cmd, BIT(gpio->bit)); in omnia_gpio_get()
367 _relevant_field_for_sts_cmd(u8 cmd, unsigned long *sts, unsigned long *ext_sts, in _relevant_field_for_sts_cmd() argument
370 switch (cmd) { in _relevant_field_for_sts_cmd()
387 struct i2c_client *client = mcu->client; in omnia_gpio_get_multiple()
393 field = _relevant_field_for_sts_cmd(omnia_gpios[i].cmd, in omnia_gpio_get_multiple()
401 guard(mutex)(&mcu->lock); in omnia_gpio_get_multiple()
403 if (mcu->features & OMNIA_FEAT_NEW_INT_API) { in omnia_gpio_get_multiple()
414 sts = mcu->last_status; in omnia_gpio_get_multiple()
431 field = _relevant_field_for_sts_cmd(omnia_gpios[i].cmd, in omnia_gpio_get_multiple()
448 if (!gpio->ctl_cmd) in omnia_gpio_set()
449 return -EINVAL; in omnia_gpio_set()
451 mask = BIT(gpio->ctl_bit); in omnia_gpio_set()
454 return omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask); in omnia_gpio_set()
490 guard(mutex)(&mcu->lock); in omnia_gpio_set_multiple()
512 if (gpio->feat_mask) in omnia_gpio_available()
513 return (mcu->features & gpio->feat_mask) == gpio->feat; in omnia_gpio_available()
515 if (gpio->feat) in omnia_gpio_available()
516 return mcu->features & gpio->feat; in omnia_gpio_available()
530 if (gpio->cmd || is_int_bit_valid(gpio)) in omnia_gpio_init_valid_mask()
546 if (WARN_ON(gpiospec->args_count != 3)) in omnia_gpio_of_xlate()
547 return -EINVAL; in omnia_gpio_of_xlate()
550 *flags = gpiospec->args[2]; in omnia_gpio_of_xlate()
552 bank = gpiospec->args[0]; in omnia_gpio_of_xlate()
553 gpio = gpiospec->args[1]; in omnia_gpio_of_xlate()
557 return gpio < 16 ? gpio : -EINVAL; in omnia_gpio_of_xlate()
559 return gpio < 32 ? 16 + gpio : -EINVAL; in omnia_gpio_of_xlate()
561 return gpio < 16 ? 48 + gpio : -EINVAL; in omnia_gpio_of_xlate()
563 return -EINVAL; in omnia_gpio_of_xlate()
574 __clear_bit(bit, &mcu->rising); in omnia_irq_shutdown()
575 __clear_bit(bit, &mcu->falling); in omnia_irq_shutdown()
585 if (!omnia_gpios[hwirq].cmd) in omnia_irq_mask()
586 __clear_bit(bit, &mcu->rising); in omnia_irq_mask()
587 __clear_bit(bit, &mcu->mask); in omnia_irq_mask()
599 __set_bit(bit, &mcu->mask); in omnia_irq_unmask()
600 if (!omnia_gpios[hwirq].cmd) in omnia_irq_unmask()
601 __set_bit(bit, &mcu->rising); in omnia_irq_unmask()
609 struct device *dev = &mcu->client->dev; in omnia_irq_set_type()
613 dev_err(dev, "irq %u: unsupported type %u\n", d->irq, type); in omnia_irq_set_type()
614 return -EINVAL; in omnia_irq_set_type()
617 __assign_bit(bit, &mcu->rising, type & IRQ_TYPE_EDGE_RISING); in omnia_irq_set_type()
618 __assign_bit(bit, &mcu->falling, type & IRQ_TYPE_EDGE_FALLING); in omnia_irq_set_type()
629 if (!(mcu->features & OMNIA_FEAT_NEW_INT_API)) in omnia_irq_bus_lock()
632 mutex_lock(&mcu->lock); in omnia_irq_bus_lock()
636 * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
641 * Interleaves the little-endian bytes from @rising and @falling words.
647 * this interleaved format. The rationale behind this is that the low-indexed
648 * bits are more important - in many cases, the user will be interested only in
665 * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
687 struct device *dev = &mcu->client->dev; in omnia_irq_bus_sync_unlock()
688 u8 cmd[1 + OMNIA_CMD_INT_ARG_LEN]; in omnia_irq_bus_sync_unlock() local
693 if (!(mcu->features & OMNIA_FEAT_NEW_INT_API)) in omnia_irq_bus_sync_unlock()
696 cmd[0] = OMNIA_CMD_SET_INT_MASK; in omnia_irq_bus_sync_unlock()
698 rising = mcu->rising & mcu->mask; in omnia_irq_bus_sync_unlock()
699 falling = mcu->falling & mcu->mask; in omnia_irq_bus_sync_unlock()
702 omnia_mask_interleave(&cmd[1], rising, falling); in omnia_irq_bus_sync_unlock()
704 dev_dbg(dev, "set int mask %8ph\n", &cmd[1]); in omnia_irq_bus_sync_unlock()
706 err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd)); in omnia_irq_bus_sync_unlock()
713 * Remember which GPIOs have both rising and falling interrupts enabled. in omnia_irq_bus_sync_unlock()
715 * We also need to forget cached values of GPIOs that aren't cached in omnia_irq_bus_sync_unlock()
718 mcu->both = rising & falling; in omnia_irq_bus_sync_unlock()
719 mcu->is_cached &= mcu->both; in omnia_irq_bus_sync_unlock()
722 mutex_unlock(&mcu->lock); in omnia_irq_bus_sync_unlock()
757 u8 cmd[1 + OMNIA_CMD_INT_ARG_LEN] = {}; in omnia_irq_init_hw() local
759 cmd[0] = OMNIA_CMD_SET_INT_MASK; in omnia_irq_init_hw()
761 return omnia_cmd_write(mcu->client, cmd, sizeof(cmd)); in omnia_irq_init_hw()
779 struct device *dev = &mcu->client->dev; in omnia_irq_read_pending_new()
785 len = omnia_irq_compute_pending_length(mcu->rising & mcu->mask, in omnia_irq_read_pending_new()
786 mcu->falling & mcu->mask); in omnia_irq_read_pending_new()
790 guard(mutex)(&mcu->lock); in omnia_irq_read_pending_new()
792 err = omnia_cmd_read(mcu->client, OMNIA_CMD_GET_INT_AND_CLEAR, reply, in omnia_irq_read_pending_new()
802 rising &= mcu->mask; in omnia_irq_read_pending_new()
803 falling &= mcu->mask; in omnia_irq_read_pending_new()
806 /* cache values for GPIOs that have both edges enabled */ in omnia_irq_read_pending_new()
807 mcu->is_cached &= ~(rising & falling); in omnia_irq_read_pending_new()
808 mcu->is_cached |= mcu->both & (rising ^ falling); in omnia_irq_read_pending_new()
809 mcu->cached = (mcu->cached | rising) & ~falling; in omnia_irq_read_pending_new()
820 err = omnia_cmd_read_u16(mcu->client, OMNIA_CMD_GET_STATUS_WORD, in omnia_read_status_word_old_fw()
840 mcu->button_pressed_emul = false; in button_release_emul_fn()
841 generic_handle_irq_safe(mcu->client->irq); in button_release_emul_fn()
859 struct device *dev = &mcu->client->dev; in omnia_irq_read_pending_old()
862 guard(mutex)(&mcu->lock); in omnia_irq_read_pending_old()
879 * - first we get an interrupt, we read the status word where in omnia_irq_read_pending_old()
881 * - MCU clears the OMNIA_STS_BUTTON_PRESSED bit because we read the in omnia_irq_read_pending_old()
883 * - we get another interrupt because the status word changed again in omnia_irq_read_pending_old()
886 * The gpiolib-cdev, gpiolib-sysfs and gpio-keys input driver all call in omnia_irq_read_pending_old()
895 mcu->button_pressed_emul = true; in omnia_irq_read_pending_old()
896 mod_delayed_work(system_wq, &mcu->button_release_emul_work, in omnia_irq_read_pending_old()
898 } else if (mcu->button_pressed_emul) { in omnia_irq_read_pending_old()
902 rising_sts = ~mcu->last_status & status; in omnia_irq_read_pending_old()
903 falling_sts = mcu->last_status & ~status; in omnia_irq_read_pending_old()
905 mcu->last_status = status; in omnia_irq_read_pending_old()
921 rising &= mcu->rising & mcu->mask; in omnia_irq_read_pending_old()
922 falling &= mcu->falling & mcu->mask; in omnia_irq_read_pending_old()
931 if (mcu->features & OMNIA_FEAT_NEW_INT_API) in omnia_irq_read_pending()
947 domain = mcu->gc.irq.domain; in omnia_irq_thread_handler()
968 if (mcu->features & OMNIA_FEAT_NEW_INT_API) { in front_button_mode_show()
969 val = omnia_cmd_read_bit(mcu->client, OMNIA_CMD_GET_STATUS_WORD, in front_button_mode_show()
974 val = !!(mcu->last_status & OMNIA_STS_BUTTON_MODE); in front_button_mode_show()
1012 bool new_api = mcu->features & OMNIA_FEAT_NEW_INT_API; in omnia_mcu_register_gpiochip()
1013 struct device *dev = &mcu->client->dev; in omnia_mcu_register_gpiochip()
1017 err = devm_mutex_init(dev, &mcu->lock); in omnia_mcu_register_gpiochip()
1021 mcu->gc.request = omnia_gpio_request; in omnia_mcu_register_gpiochip()
1022 mcu->gc.get_direction = omnia_gpio_get_direction; in omnia_mcu_register_gpiochip()
1023 mcu->gc.direction_input = omnia_gpio_direction_input; in omnia_mcu_register_gpiochip()
1024 mcu->gc.direction_output = omnia_gpio_direction_output; in omnia_mcu_register_gpiochip()
1025 mcu->gc.get = omnia_gpio_get; in omnia_mcu_register_gpiochip()
1026 mcu->gc.get_multiple = omnia_gpio_get_multiple; in omnia_mcu_register_gpiochip()
1027 mcu->gc.set = omnia_gpio_set; in omnia_mcu_register_gpiochip()
1028 mcu->gc.set_multiple = omnia_gpio_set_multiple; in omnia_mcu_register_gpiochip()
1029 mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask; in omnia_mcu_register_gpiochip()
1030 mcu->gc.can_sleep = true; in omnia_mcu_register_gpiochip()
1031 mcu->gc.names = omnia_mcu_gpio_names; in omnia_mcu_register_gpiochip()
1032 mcu->gc.base = -1; in omnia_mcu_register_gpiochip()
1033 mcu->gc.ngpio = ARRAY_SIZE(omnia_gpios); in omnia_mcu_register_gpiochip()
1034 mcu->gc.label = "Turris Omnia MCU GPIOs"; in omnia_mcu_register_gpiochip()
1035 mcu->gc.parent = dev; in omnia_mcu_register_gpiochip()
1036 mcu->gc.owner = THIS_MODULE; in omnia_mcu_register_gpiochip()
1037 mcu->gc.of_gpio_n_cells = 3; in omnia_mcu_register_gpiochip()
1038 mcu->gc.of_xlate = omnia_gpio_of_xlate; in omnia_mcu_register_gpiochip()
1040 gpio_irq_chip_set_chip(&mcu->gc.irq, &omnia_mcu_irq_chip); in omnia_mcu_register_gpiochip()
1042 mcu->gc.irq.parent_handler = NULL; in omnia_mcu_register_gpiochip()
1043 mcu->gc.irq.num_parents = 0; in omnia_mcu_register_gpiochip()
1044 mcu->gc.irq.parents = NULL; in omnia_mcu_register_gpiochip()
1045 mcu->gc.irq.default_type = IRQ_TYPE_NONE; in omnia_mcu_register_gpiochip()
1046 mcu->gc.irq.handler = handle_bad_irq; in omnia_mcu_register_gpiochip()
1047 mcu->gc.irq.threaded = true; in omnia_mcu_register_gpiochip()
1049 mcu->gc.irq.init_hw = omnia_irq_init_hw; in omnia_mcu_register_gpiochip()
1050 mcu->gc.irq.init_valid_mask = omnia_irq_init_valid_mask; in omnia_mcu_register_gpiochip()
1052 err = devm_gpiochip_add_data(dev, &mcu->gc, mcu); in omnia_mcu_register_gpiochip()
1063 err = omnia_read_status_word_old_fw(mcu, &mcu->last_status); in omnia_mcu_register_gpiochip()
1068 INIT_DELAYED_WORK(&mcu->button_release_emul_work, in omnia_mcu_register_gpiochip()
1078 err = devm_request_threaded_irq(dev, mcu->client->irq, NULL, in omnia_mcu_register_gpiochip()
1080 "turris-omnia-mcu", mcu); in omnia_mcu_register_gpiochip()
1099 &mcu->button_release_emul_work); in omnia_mcu_register_gpiochip()
1114 return -EINVAL; in omnia_mcu_request_irq()
1116 irq_idx = omnia_int_to_gpio_idx[ffs(spec) - 1]; in omnia_mcu_request_irq()
1117 irq = gpiod_to_irq(gpio_device_get_desc(mcu->gc.gpiodev, irq_idx)); in omnia_mcu_request_irq()
1121 return devm_request_threaded_irq(&mcu->client->dev, irq, NULL, in omnia_mcu_request_irq()