Skip to content

Commit

Permalink
drivers: ps2: microchip: Low power and wakeup enabled
Browse files Browse the repository at this point in the history
ps2 driver updated to support low power and wakeup.

Signed-off-by: Manimaran A <manimaran.a@microchip.com>
  • Loading branch information
Manimaran-A authored and nashif committed Jun 17, 2023
1 parent 1b51be4 commit 0f6cb5e
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@
&ps2_0 {
status = "okay";
pinctrl-0 = <&ps2_clk0b_gpio007 &ps2_dat0b_gpio010>;
pinctrl-names = "default";
pinctrl-1 = <&ps2_clk0b_gpio007_sleep &ps2_dat0b_gpio010_sleep>;
pinctrl-names = "default", "sleep";
};

&ps2_1 {
status = "okay";
pinctrl-0 = <&ps2_clk1b_gpio154 &ps2_dat1b_gpio155>;
pinctrl-names = "default";
pinctrl-1 = <&ps2_clk1b_gpio154_sleep &ps2_dat1b_gpio155_sleep>;
pinctrl-names = "default", "sleep";
};

&pwm0 {
Expand Down
6 changes: 4 additions & 2 deletions boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,15 @@
&ps2_0 {
status = "okay";
pinctrl-0 = <&ps2_clk0b_gpio007 &ps2_dat0b_gpio010>;
pinctrl-names = "default";
pinctrl-1 = <&ps2_clk0b_gpio007_sleep &ps2_dat0b_gpio010_sleep>;
pinctrl-names = "default", "sleep";
};

&ps2_1 {
status = "okay";
pinctrl-0 = <&ps2_clk1b_gpio154 &ps2_dat1b_gpio155>;
pinctrl-names = "default";
pinctrl-1 = <&ps2_clk1b_gpio154_sleep &ps2_dat1b_gpio155_sleep>;
pinctrl-names = "default", "sleep";
};

&pwm0 {
Expand Down
3 changes: 2 additions & 1 deletion boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@
&ps2_0 {
status = "okay";
pinctrl-0 = <&ps2_clk0a_gpio114 &ps2_dat0a_gpio115>;
pinctrl-names = "default";
pinctrl-1 = <&ps2_clk0a_gpio114_sleep &ps2_dat0a_gpio115_sleep>;
pinctrl-names = "default", "sleep";
};

&timer5 {
Expand Down
170 changes: 144 additions & 26 deletions drivers/ps2/ps2_mchp_xec.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
#include <zephyr/drivers/interrupt_controller/intc_mchp_xec_ecia.h>
#endif
#include <zephyr/drivers/pinctrl.h>
#ifdef CONFIG_PM_DEVICE
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#endif
#include <zephyr/drivers/ps2.h>
#include <soc.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/gpio.h>

#define LOG_LEVEL CONFIG_PS2_LOG_LEVEL
LOG_MODULE_REGISTER(ps2_mchp_xec);
Expand All @@ -32,17 +37,25 @@ struct ps2_xec_config {
int isr_nvic;
uint8_t girq_id;
uint8_t girq_bit;
uint8_t girq_id_wk;
uint8_t girq_bit_wk;
uint8_t pcr_idx;
uint8_t pcr_pos;
void (*irq_config_func)(void);
const struct pinctrl_dev_config *pcfg;
#ifdef CONFIG_PM_DEVICE
struct gpio_dt_spec wakerx_gpio;
bool wakeup_source;
#endif
};


struct ps2_xec_data {
ps2_callback_t callback_isr;
struct k_sem tx_lock;
};


#ifdef CONFIG_SOC_SERIES_MEC172X
static inline void ps2_xec_slp_en_clr(const struct device *dev)
{
Expand All @@ -51,18 +64,19 @@ static inline void ps2_xec_slp_en_clr(const struct device *dev)
z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0);
}

static inline void ps2_xec_girq_clr(const struct device *dev)
static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn)
{
const struct ps2_xec_config * const cfg = dev->config;

mchp_soc_ecia_girq_src_clr(cfg->girq_id, cfg->girq_bit);
mchp_soc_ecia_girq_src_clr(girq_idx, girq_posn);
}

static inline void ps2_xec_girq_en(const struct device *dev)
static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn)
{
const struct ps2_xec_config * const cfg = dev->config;
mchp_xec_ecia_girq_src_en(girq_idx, girq_posn);
}

mchp_xec_ecia_girq_src_en(cfg->girq_id, cfg->girq_bit);
static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn)
{
mchp_xec_ecia_girq_src_dis(girq_idx, girq_posn);
}
#else
static inline void ps2_xec_slp_en_clr(const struct device *dev)
Expand All @@ -76,18 +90,19 @@ static inline void ps2_xec_slp_en_clr(const struct device *dev)
}
}

static inline void ps2_xec_girq_clr(const struct device *dev)
static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn)
{
const struct ps2_xec_config * const cfg = dev->config;

MCHP_GIRQ_SRC(cfg->girq_id) = BIT(cfg->girq_bit);
MCHP_GIRQ_SRC(girq_idx) = BIT(girq_posn);
}

static inline void ps2_xec_girq_en(const struct device *dev)
static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn)
{
const struct ps2_xec_config * const cfg = dev->config;
MCHP_GIRQ_ENSET(girq_idx) = BIT(girq_posn);
}

MCHP_GIRQ_ENSET(cfg->girq_id) = BIT(cfg->girq_bit);
static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn)
{
MCHP_GIRQ_ENCLR(girq_idx) = MCHP_KBC_IBF_GIRQ;
}
#endif /* CONFIG_SOC_SERIES_MEC172X */

Expand All @@ -108,21 +123,21 @@ static int ps2_xec_configure(const struct device *dev,

/* In case the self test for a PS2 device already finished and
* set the SOURCE bit to 1 we clear it before enabling the
* interrupts. Instances must be allocated before the BAT or
* the host may time out.
* interrupts. Instances must be allocated before the BAT
* (Basic Assurance Test) or the host may time out.
*/
temp = regs->TRX_BUFF;
regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
/* clear next higher level */
ps2_xec_girq_clr(dev);
ps2_xec_girq_clr(config->girq_id, config->girq_bit);

/* Enable FSM and init instance in rx mode*/
regs->CTRL = MCHP_PS2_CTRL_EN_POS;

/* We enable the interrupts in the EC aggregator so that the
* result can be forwarded to the ARM NVIC
*/
ps2_xec_girq_en(dev);
ps2_xec_girq_en(config->girq_id, config->girq_bit);

k_sem_give(&data->tx_lock);

Expand Down Expand Up @@ -159,7 +174,9 @@ static int ps2_xec_write(const struct device *dev, uint8_t value)
LOG_DBG("PS2 write timed out");
return -ETIMEDOUT;
}

#ifdef CONFIG_PM_DEVICE
pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
#endif
/* Inhibit ps2 controller and clear status register */
regs->CTRL = 0x00;

Expand Down Expand Up @@ -191,7 +208,7 @@ static int ps2_xec_inhibit_interface(const struct device *dev)

regs->CTRL = 0x00;
regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
ps2_xec_girq_clr(dev);
ps2_xec_girq_clr(config->girq_id, config->girq_bit);
NVIC_ClearPendingIRQ(config->isr_nvic);

k_sem_give(&data->tx_lock);
Expand All @@ -205,14 +222,78 @@ static int ps2_xec_enable_interface(const struct device *dev)
struct ps2_xec_data * const data = dev->data;
struct ps2_regs * const regs = config->regs;

ps2_xec_girq_clr(dev);
ps2_xec_girq_clr(config->girq_id, config->girq_bit);
regs->CTRL = MCHP_PS2_CTRL_EN;

k_sem_give(&data->tx_lock);

return 0;
}

#ifdef CONFIG_PM_DEVICE
static int ps2_xec_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct ps2_xec_config *const devcfg = dev->config;
struct ps2_regs * const regs = devcfg->regs;
int ret = 0;

switch (action) {
case PM_DEVICE_ACTION_RESUME:
if (devcfg->wakeup_source) {
/* Disable PS2 wake interrupt
* Disable interrupt on PS2DAT pin
*/
if (devcfg->wakerx_gpio.port != NULL) {
ret = gpio_pin_interrupt_configure_dt(
&devcfg->wakerx_gpio,
GPIO_INT_DISABLE);
if (ret < 0) {
LOG_ERR("Fail to disable PS2 wake interrupt (ret %d)", ret);
return ret;
}
}
ps2_xec_girq_dis(devcfg->girq_id_wk, devcfg->girq_bit_wk);
ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk);
} else {
ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT);
regs->CTRL |= MCHP_PS2_CTRL_EN;
}
break;
case PM_DEVICE_ACTION_SUSPEND:
if (devcfg->wakeup_source) {
/* Enable PS2 wake interrupt
* Configure Falling Edge Trigger interrupt on PS2DAT pin
*/
ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk);
ps2_xec_girq_en(devcfg->girq_id_wk, devcfg->girq_bit_wk);
if (devcfg->wakerx_gpio.port != NULL) {
ret = gpio_pin_interrupt_configure_dt(
&devcfg->wakerx_gpio,
GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW);
if (ret < 0) {
LOG_ERR("Fail to enable PS2 wake interrupt(ret %d)", ret);
return ret;
}
}
} else {
regs->CTRL &= ~MCHP_PS2_CTRL_EN;
/* If application does not want to turn off PS2 pins it will
* not define pinctrl-1 for this node.
*/
ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP);
if (ret == -ENOENT) { /* pinctrl-1 does not exist. */
ret = 0;
}
}
break;
default:
ret = -ENOTSUP;
}

return ret;
}
#endif /* CONFIG_PM_DEVICE */

static void ps2_xec_isr(const struct device *dev)
{
const struct ps2_xec_config * const config = dev->config;
Expand All @@ -224,18 +305,36 @@ static void ps2_xec_isr(const struct device *dev)
status = regs->STATUS;

/* clear next higher level the GIRQ */
ps2_xec_girq_clr(dev);
ps2_xec_girq_clr(config->girq_id, config->girq_bit);

if (status & MCHP_PS2_STATUS_RXD_RDY) {
#ifdef CONFIG_PM_DEVICE
pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
#endif
regs->CTRL = 0x00;
if (data->callback_isr) {
data->callback_isr(dev, regs->TRX_BUFF);
}
#ifdef CONFIG_PM_DEVICE
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
#endif
} else if (status &
(MCHP_PS2_STATUS_TX_TMOUT | MCHP_PS2_STATUS_TX_ST_TMOUT)) {
/* Clear sticky bits and go to read mode */
regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
LOG_ERR("TX time out: %0x", status);
#ifdef CONFIG_PM_DEVICE
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
#endif
} else if (status &
(MCHP_PS2_STATUS_RX_TMOUT | MCHP_PS2_STATUS_PE | MCHP_PS2_STATUS_FE)) {
/* catch and clear rx error if any */
regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK;
} else if (status & MCHP_PS2_STATUS_TX_IDLE) {
/* Transfer completed, release the lock to enter low per mode */
#ifdef CONFIG_PM_DEVICE
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
#endif
}

/* The control register reverts to RX automatically after
Expand All @@ -256,9 +355,7 @@ static int ps2_xec_init(const struct device *dev)
{
const struct ps2_xec_config * const cfg = dev->config;
struct ps2_xec_data * const data = dev->data;

int ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);

if (ret != 0) {
LOG_ERR("XEC PS2 pinctrl init failed (%d)", ret);
return ret;
Expand All @@ -273,16 +370,35 @@ static int ps2_xec_init(const struct device *dev)
return 0;
}

/* To enable wakeup on the PS2, the DTS needs to have two entries defined
* in the corresponding PS2 node in the DTS specifying it as a wake source
* and specifying the PS2DAT GPIO; example as below
*
* wakerx-gpios = <MCHP_GPIO_DECODE_115 GPIO_ACTIVE_HIGH>
* wakeup-source;
*/
#ifdef CONFIG_PM_DEVICE
#define XEC_PS2_PM_WAKEUP(n) \
.wakeup_source = (uint8_t)DT_INST_PROP_OR(n, wakeup_source, 0), \
.wakerx_gpio = GPIO_DT_SPEC_INST_GET_OR(n, wakerx_gpios, {0}),
#else
#define XEC_PS2_PM_WAKEUP(index) /* Not used */
#endif

#define XEC_PS2_PINCTRL_CFG(inst) PINCTRL_DT_INST_DEFINE(inst)
#define XEC_PS2_CONFIG(inst) \
static const struct ps2_xec_config ps2_xec_config_##inst = { \
.regs = (struct ps2_regs * const)(DT_INST_REG_ADDR(inst)), \
.isr_nvic = DT_INST_IRQN(inst), \
.girq_id = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 0)), \
.girq_bit = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 1)), \
.girq_id_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 2)), \
.girq_bit_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 3)), \
.pcr_idx = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 0)), \
.pcr_pos = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 1)), \
.irq_config_func = ps2_xec_irq_config_func_##inst, \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
XEC_PS2_PM_WAKEUP(inst) \
}

#define PS2_XEC_DEVICE(i) \
Expand All @@ -298,12 +414,14 @@ static int ps2_xec_init(const struct device *dev)
\
static struct ps2_xec_data ps2_xec_port_data_##i; \
\
PINCTRL_DT_INST_DEFINE(i); \
XEC_PS2_PINCTRL_CFG(i); \
\
XEC_PS2_CONFIG(i); \
\
PM_DEVICE_DT_INST_DEFINE(i, ps2_xec_pm_action); \
\
DEVICE_DT_INST_DEFINE(i, &ps2_xec_init, \
NULL, \
PM_DEVICE_DT_INST_GET(i), \
&ps2_xec_port_data_##i, &ps2_xec_config_##i, \
POST_KERNEL, CONFIG_PS2_INIT_PRIORITY, \
&ps2_xec_driver_api);
Expand Down
4 changes: 2 additions & 2 deletions dts/arm/microchip/mec1501hsz.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@
compatible = "microchip,xec-ps2";
reg = <0x40009000 0x40>;
interrupts = <100 1>;
girqs = <18 10>;
girqs = <18 10>, <21 18>;
pcrs = <3 5>;
#address-cells = <1>;
#size-cells = <0>;
Expand All @@ -352,7 +352,7 @@
compatible = "microchip,xec-ps2";
reg = <0x40009040 0x40>;
interrupts = <101 1>;
girqs = <18 11>;
girqs = <18 11>, <21 21>;
pcrs = <3 6>;
#address-cells = <1>;
#size-cells = <0>;
Expand Down
Loading

0 comments on commit 0f6cb5e

Please sign in to comment.