cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/greybus/arche-apb-ctrl.c

/*
 * Arche Platform driver to control APB.
 *
 * Copyright 2014-2015 Google Inc.
 * Copyright 2014-2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include "arche_platform.h"



struct arche_apb_ctrl_drvdata {
	/* Control GPIO signals to and from AP <=> AP Bridges */
	
int resetn_gpio;
	
int boot_ret_gpio;
	
int pwroff_gpio;
	
int wake_in_gpio;
	
int wake_out_gpio;
	
int pwrdn_gpio;

	
enum arche_platform_state state;
	
bool init_disabled;

	
struct regulator *vcore;
	
struct regulator *vio;

	
int clk_en_gpio;
	
struct clk *clk;

	
struct pinctrl *pinctrl;
	
struct pinctrl_state *pin_default;

	/* V2: SPI Bus control  */
	
int spi_en_gpio;
	
bool spi_en_polarity_high;
};

/*
 * Note that these low level api's are active high
 */

static inline void deassert_reset(unsigned int gpio) { gpio_set_value(gpio, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath18100.00%2100.00%
Total18100.00%2100.00%


static inline void assert_reset(unsigned int gpio) { gpio_set_value(gpio, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath18100.00%2100.00%
Total18100.00%2100.00%

/* * Note: Please do not modify the below sequence, as it is as per the spec */
static int coldboot_seq(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); int ret; if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_ACTIVE) return 0; /* Hold APB in reset state */ assert_reset(apb->resetn_gpio); if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && gpio_is_valid(apb->spi_en_gpio)) devm_gpio_free(dev, apb->spi_en_gpio); /* Enable power to APB */ if (!IS_ERR(apb->vcore)) { ret = regulator_enable(apb->vcore); if (ret) { dev_err(dev, "failed to enable core regulator\n"); return ret; } } if (!IS_ERR(apb->vio)) { ret = regulator_enable(apb->vio); if (ret) { dev_err(dev, "failed to enable IO regulator\n"); return ret; } } apb_bootret_deassert(dev); /* On DB3 clock was not mandatory */ if (gpio_is_valid(apb->clk_en_gpio)) gpio_set_value(apb->clk_en_gpio, 1); usleep_range(100, 200); /* deassert reset to APB : Active-low signal */ deassert_reset(apb->resetn_gpio); apb->state = ARCHE_PLATFORM_STATE_ACTIVE; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath18691.18%872.73%
Viresh Kumar167.84%218.18%
Bryan O'Donoghue20.98%19.09%
Total204100.00%11100.00%


static int fw_flashing_seq(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); int ret; if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING) return 0; ret = regulator_enable(apb->vcore); if (ret) { dev_err(dev, "failed to enable core regulator\n"); return ret; } ret = regulator_enable(apb->vio); if (ret) { dev_err(dev, "failed to enable IO regulator\n"); return ret; } if (gpio_is_valid(apb->spi_en_gpio)) { unsigned long flags; if (apb->spi_en_polarity_high) flags = GPIOF_OUT_INIT_HIGH; else flags = GPIOF_OUT_INIT_LOW; ret = devm_gpio_request_one(dev, apb->spi_en_gpio, flags, "apb_spi_en"); if (ret) { dev_err(dev, "Failed requesting SPI bus en gpio %d\n", apb->spi_en_gpio); return ret; } } /* for flashing device should be in reset state */ assert_reset(apb->resetn_gpio); apb->state = ARCHE_PLATFORM_STATE_FW_FLASHING; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath181100.00%5100.00%
Total181100.00%5100.00%


static int standby_boot_seq(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); if (apb->init_disabled) return 0; /* * Even if it is in OFF state, * then we do not want to change the state */ if (apb->state == ARCHE_PLATFORM_STATE_STANDBY || apb->state == ARCHE_PLATFORM_STATE_OFF) return 0; if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && gpio_is_valid(apb->spi_en_gpio)) devm_gpio_free(dev, apb->spi_en_gpio); /* * As per WDM spec, do nothing * * Pasted from WDM spec, * - A falling edge on POWEROFF_L is detected (a) * - WDM enters standby mode, but no output signals are changed */ /* TODO: POWEROFF_L is input to WDM module */ apb->state = ARCHE_PLATFORM_STATE_STANDBY; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath9197.85%571.43%
Hisao Tanabe11.08%114.29%
Gioh Kim11.08%114.29%
Total93100.00%7100.00%


static void poweroff_seq(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_OFF) return; if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && gpio_is_valid(apb->spi_en_gpio)) devm_gpio_free(dev, apb->spi_en_gpio); /* disable the clock */ if (gpio_is_valid(apb->clk_en_gpio)) gpio_set_value(apb->clk_en_gpio, 0); if (!IS_ERR(apb->vcore) && regulator_is_enabled(apb->vcore) > 0) regulator_disable(apb->vcore); if (!IS_ERR(apb->vio) && regulator_is_enabled(apb->vio) > 0) regulator_disable(apb->vio); /* As part of exit, put APB back in reset state */ assert_reset(apb->resetn_gpio); apb->state = ARCHE_PLATFORM_STATE_OFF; /* TODO: May have to send an event to SVC about this exit */ }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath154100.00%6100.00%
Total154100.00%6100.00%


void apb_bootret_assert(struct device *dev) { struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev); gpio_set_value(apb->boot_ret_gpio, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Bryan O'Donoghue29100.00%1100.00%
Total29100.00%1100.00%


void apb_bootret_deassert(struct device *dev) { struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev); gpio_set_value(apb->boot_ret_gpio, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Bryan O'Donoghue29100.00%1100.00%
Total29100.00%1100.00%


int apb_ctrl_coldboot(struct device *dev) { return coldboot_seq(to_platform_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath19100.00%1100.00%
Total19100.00%1100.00%


int apb_ctrl_fw_flashing(struct device *dev) { return fw_flashing_seq(to_platform_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath19100.00%1100.00%
Total19100.00%1100.00%


int apb_ctrl_standby_boot(struct device *dev) { return standby_boot_seq(to_platform_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath19100.00%1100.00%
Total19100.00%1100.00%


void apb_ctrl_poweroff(struct device *dev) { poweroff_seq(to_platform_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath18100.00%1100.00%
Total18100.00%1100.00%


static ssize_t state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); int ret = 0; bool is_disabled; if (sysfs_streq(buf, "off")) { if (apb->state == ARCHE_PLATFORM_STATE_OFF) return count; poweroff_seq(pdev); } else if (sysfs_streq(buf, "active")) { if (apb->state == ARCHE_PLATFORM_STATE_ACTIVE) return count; poweroff_seq(pdev); is_disabled = apb->init_disabled; apb->init_disabled = false; ret = coldboot_seq(pdev); if (ret) apb->init_disabled = is_disabled; } else if (sysfs_streq(buf, "standby")) { if (apb->state == ARCHE_PLATFORM_STATE_STANDBY) return count; ret = standby_boot_seq(pdev); } else if (sysfs_streq(buf, "fw_flashing")) { if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING) return count; /* * First we want to make sure we power off everything * and then enter FW flashing state */ poweroff_seq(pdev); ret = fw_flashing_seq(pdev); } else { dev_err(dev, "unknown state\n"); ret = -EINVAL; } return ret ? ret : count; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath22399.55%375.00%
Sidhant Gupta10.45%125.00%
Total224100.00%4100.00%


static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev); switch (apb->state) { case ARCHE_PLATFORM_STATE_OFF: return sprintf(buf, "off%s\n", apb->init_disabled ? ",disabled" : ""); case ARCHE_PLATFORM_STATE_ACTIVE: return sprintf(buf, "active\n"); case ARCHE_PLATFORM_STATE_STANDBY: return sprintf(buf, "standby\n"); case ARCHE_PLATFORM_STATE_FW_FLASHING: return sprintf(buf, "fw_flashing\n"); default: return sprintf(buf, "unknown state\n"); } }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath99100.00%2100.00%
Total99100.00%2100.00%

static DEVICE_ATTR_RW(state);
static int apb_ctrl_get_devtree_data(struct platform_device *pdev, struct arche_apb_ctrl_drvdata *apb) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; int ret; apb->resetn_gpio = of_get_named_gpio(np, "reset-gpios", 0); if (apb->resetn_gpio < 0) { dev_err(dev, "failed to get reset gpio\n"); return apb->resetn_gpio; } ret = devm_gpio_request_one(dev, apb->resetn_gpio, GPIOF_OUT_INIT_LOW, "apb-reset"); if (ret) { dev_err(dev, "Failed requesting reset gpio %d\n", apb->resetn_gpio); return ret; } apb->boot_ret_gpio = of_get_named_gpio(np, "boot-ret-gpios", 0); if (apb->boot_ret_gpio < 0) { dev_err(dev, "failed to get boot retention gpio\n"); return apb->boot_ret_gpio; } ret = devm_gpio_request_one(dev, apb->boot_ret_gpio, GPIOF_OUT_INIT_LOW, "boot retention"); if (ret) { dev_err(dev, "Failed requesting bootret gpio %d\n", apb->boot_ret_gpio); return ret; } /* It's not mandatory to support power management interface */ apb->pwroff_gpio = of_get_named_gpio(np, "pwr-off-gpios", 0); if (apb->pwroff_gpio < 0) { dev_err(dev, "failed to get power off gpio\n"); return apb->pwroff_gpio; } ret = devm_gpio_request_one(dev, apb->pwroff_gpio, GPIOF_IN, "pwroff_n"); if (ret) { dev_err(dev, "Failed requesting pwroff_n gpio %d\n", apb->pwroff_gpio); return ret; } /* Do not make clock mandatory as of now (for DB3) */ apb->clk_en_gpio = of_get_named_gpio(np, "clock-en-gpio", 0); if (apb->clk_en_gpio < 0) { dev_warn(dev, "failed to get clock en gpio\n"); } else if (gpio_is_valid(apb->clk_en_gpio)) { ret = devm_gpio_request_one(dev, apb->clk_en_gpio, GPIOF_OUT_INIT_LOW, "apb_clk_en"); if (ret) { dev_warn(dev, "Failed requesting APB clock en gpio %d\n", apb->clk_en_gpio); return ret; } } apb->pwrdn_gpio = of_get_named_gpio(np, "pwr-down-gpios", 0); if (apb->pwrdn_gpio < 0) dev_warn(dev, "failed to get power down gpio\n"); /* Regulators are optional, as we may have fixed supply coming in */ apb->vcore = devm_regulator_get(dev, "vcore"); if (IS_ERR(apb->vcore)) dev_warn(dev, "no core regulator found\n"); apb->vio = devm_regulator_get(dev, "vio"); if (IS_ERR(apb->vio)) dev_warn(dev, "no IO regulator found\n"); apb->pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(apb->pinctrl)) { dev_err(&pdev->dev, "could not get pinctrl handle\n"); return PTR_ERR(apb->pinctrl); } apb->pin_default = pinctrl_lookup_state(apb->pinctrl, "default"); if (IS_ERR(apb->pin_default)) { dev_err(&pdev->dev, "could not get default pin state\n"); return PTR_ERR(apb->pin_default); } /* Only applicable for platform >= V2 */ apb->spi_en_gpio = of_get_named_gpio(np, "spi-en-gpio", 0); if (apb->spi_en_gpio >= 0) { if (of_property_read_bool(pdev->dev.of_node, "spi-en-active-high")) apb->spi_en_polarity_high = true; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath52296.85%350.00%
Viresh Kumar173.15%350.00%
Total539100.00%6100.00%


static int arche_apb_ctrl_probe(struct platform_device *pdev) { int ret; struct arche_apb_ctrl_drvdata *apb; struct device *dev = &pdev->dev; apb = devm_kzalloc(&pdev->dev, sizeof(*apb), GFP_KERNEL); if (!apb) return -ENOMEM; ret = apb_ctrl_get_devtree_data(pdev, apb); if (ret) { dev_err(dev, "failed to get apb devicetree data %d\n", ret); return ret; } /* Initially set APB to OFF state */ apb->state = ARCHE_PLATFORM_STATE_OFF; /* Check whether device needs to be enabled on boot */ if (of_property_read_bool(pdev->dev.of_node, "arche,init-disable")) apb->init_disabled = true; platform_set_drvdata(pdev, apb); /* Create sysfs interface to allow user to change state dynamically */ ret = device_create_file(dev, &dev_attr_state); if (ret) { dev_err(dev, "failed to create state file in sysfs\n"); return ret; } dev_info(&pdev->dev, "Device registered successfully\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath15699.36%685.71%
Viresh Kumar10.64%114.29%
Total157100.00%7100.00%


static int arche_apb_ctrl_remove(struct platform_device *pdev) { device_remove_file(&pdev->dev, &dev_attr_state); poweroff_seq(pdev); platform_set_drvdata(pdev, NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath3697.30%480.00%
Viresh Kumar12.70%120.00%
Total37100.00%5100.00%


static int __maybe_unused arche_apb_ctrl_suspend(struct device *dev) { /* * If timing profile permits, we may shutdown bridge * completely * * TODO: sequence ?? * * Also, need to make sure we meet precondition for unipro suspend * Precondition: Definition ??? */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath1487.50%133.33%
Jérémy Lefaure16.25%133.33%
Viresh Kumar16.25%133.33%
Total16100.00%3100.00%


static int __maybe_unused arche_apb_ctrl_resume(struct device *dev) { /* * Atleast for ES2 we have to meet the delay requirement between * unipro switch and AP bridge init, depending on whether bridge is in * OFF state or standby state. * * Based on whether bridge is in standby or OFF state we may have to * assert multiple signals. Please refer to WDM spec, for more info. * */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath1593.75%150.00%
Jérémy Lefaure16.25%150.00%
Total16100.00%2100.00%


static void arche_apb_ctrl_shutdown(struct platform_device *pdev) { apb_ctrl_poweroff(&pdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
David Lin19100.00%1100.00%
Total19100.00%1100.00%

static SIMPLE_DEV_PM_OPS(arche_apb_ctrl_pm_ops, arche_apb_ctrl_suspend, arche_apb_ctrl_resume); static const struct of_device_id arche_apb_ctrl_of_match[] = { { .compatible = "usbffff,2", }, { }, }; static struct platform_driver arche_apb_ctrl_device_driver = { .probe = arche_apb_ctrl_probe, .remove = arche_apb_ctrl_remove, .shutdown = arche_apb_ctrl_shutdown, .driver = { .name = "arche-apb-ctrl", .pm = &arche_apb_ctrl_pm_ops, .of_match_table = arche_apb_ctrl_of_match, } };
int __init arche_apb_init(void) { return platform_driver_register(&arche_apb_ctrl_device_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar15100.00%1100.00%
Total15100.00%1100.00%


void __exit arche_apb_exit(void) { platform_driver_unregister(&arche_apb_ctrl_device_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar14100.00%1100.00%
Total14100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Vaibhav Hiremath189789.40%1548.39%
Viresh Kumar1326.22%825.81%
Bryan O'Donoghue602.83%13.23%
David Lin241.13%13.23%
Greg Kroah-Hartman30.14%13.23%
Jérémy Lefaure20.09%13.23%
Sidhant Gupta10.05%13.23%
Hisao Tanabe10.05%13.23%
Eva Rachel Retuya10.05%13.23%
Gioh Kim10.05%13.23%
Total2122100.00%31100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.