Loading Documentation/devicetree/bindings/platform/msm/qca1530.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ Required properties Optional properties - qca,pwr-supply: handle to the regulator device tree node - qca,pwr2-supply: handle to additional regulator device tree node - qca,pwr-gpio: handle the power control using GPIO interface - qca,reset-gpio: GPIO for reset control - qca,reset-supply: handle to the regulator for reset control Loading drivers/platform/msm/qca1530.c +288 −91 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <linux/platform_device.h> #include <linux/uaccess.h> #include <linux/types.h> #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> /* RTC clock name for lookup */ #define QCA1530_RTC_CLK_ID "qca,rtc_clk" Loading @@ -32,6 +35,8 @@ #define QCA1530_TCXO_CLK_ID "qca,tcxo_clk" /* SoC power regulator prefix for DTS */ #define QCA1530_OF_PWR_REG_NAME "qca,pwr" /* SoC optional power regulator prefix for DTS */ #define QCA1530_OF_PWR_OPT_REG_NAME "qca,pwr2" /* SoC power regulator pin for DTS */ #define QCA1530_OF_PWR_GPIO_NAME "qca,pwr-gpio" /* Reset power regulator prefix for DTS */ Loading @@ -49,6 +54,14 @@ /* xLNA pin name for DTS */ #define QCA1530_OF_XLNA_GPIO_NAME "qca,xlna-gpio" #define QCA1530_ALL_FLG 0x0f #define QCA1530_POWER_FLG 0x01 #define QCA1530_XLNA_FLG 0x02 #define QCA1530_CLK_FLG 0x04 #define QCA1530_RESET_FLG 0x08 #define SYSFS_NODE_NAME "qca1530" /** * struct qca1530_static - keeps all driver instance variables * @pdev: Platform device data Loading @@ -72,9 +85,11 @@ struct qca1530_static { int rtc_clk_gpio; struct clk *tcxo_clk; struct regulator *pwr_reg; struct regulator *pwr_opt_reg; int pwr_gpio; struct regulator *xlna_reg; int xlna_gpio; int chip_state; }; /* Loading @@ -85,6 +100,7 @@ static struct qca1530_static qca1530_data = { .rtc_clk_gpio = -1, .pwr_gpio = -1, .xlna_gpio = -1, .chip_state = 0, }; /** Loading Loading @@ -143,7 +159,7 @@ static int qca1530_clk_prepare(struct clk *clk, int mode) else clk_disable_unprepare(clk); pr_debug("Configured clk (%p): mode=%d ret=%d", clk, mode, ret); pr_debug("Configured clock (%p): mode=%d ret=%d", clk, mode, ret); return ret; } Loading @@ -157,8 +173,7 @@ static int qca1530_clk_prepare(struct clk *clk, int mode) static void qca1530_clk_set_gpio(int mode) { gpio_set_value(qca1530_data.rtc_clk_gpio, mode ? 1 : 0); pr_debug("Configured clk (GPIO): mode=%d", mode); pr_debug("Set clk GPIO (%d): mode=%d", qca1530_data.rtc_clk_gpio, mode); } /** Loading @@ -175,51 +190,57 @@ static int qca1530_clk_set(int mode) { int ret = 0; if (qca1530_data.rtc_clk_gpio < 0 && !qca1530_data.rtc_clk && !qca1530_data.tcxo_clk) { if (qca1530_data.rtc_clk_gpio < 0 && !qca1530_data.rtc_clk && !qca1530_data.tcxo_clk) { ret = -ENOSYS; } else if (mode) { } else { if (qca1530_data.rtc_clk_gpio >= 0) qca1530_clk_set_gpio(1); qca1530_clk_set_gpio(mode); if (qca1530_data.rtc_clk) ret = qca1530_clk_prepare(qca1530_data.rtc_clk, 1); ret = qca1530_clk_prepare(qca1530_data.rtc_clk, mode); if (!ret && qca1530_data.tcxo_clk) ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, 1); } else { if (qca1530_data.tcxo_clk) ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, 0); if (!ret && qca1530_data.rtc_clk) ret = qca1530_clk_prepare(qca1530_data.rtc_clk, 0); if (!ret && qca1530_data.rtc_clk_gpio >= 0) qca1530_clk_set_gpio(0); ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, mode); } pr_debug("Configured clk: mode=%d ret=%d", mode, ret); return ret; } /** * qca1530_clk_release_clocks() - release clocks * qca1530_clk_release_clock() - release clocks * @pdev: platform device data * @clk_name: clock name * @clk: pointer to clock handle pointer * * Function releases initialized clocks and sets clock handle * references to NULL. * pointer to NULL. */ static void qca1530_clk_release_clocks(struct platform_device *pdev) static void qca1530_clk_release_clock( struct platform_device *pdev, const char *clk_name, struct clk **clk) { if (qca1530_data.tcxo_clk) { pr_debug("Unregistering CLK: device=%s name=%s", dev_name(&pdev->dev), QCA1530_TCXO_CLK_ID); devm_clk_put(&pdev->dev, qca1530_data.tcxo_clk); qca1530_data.tcxo_clk = NULL; if (*clk) { pr_debug("Unregistering CLK: name=%s", clk_name); devm_clk_put(&pdev->dev, *clk); *clk = NULL; } if (qca1530_data.rtc_clk) { pr_debug("Unregistering CLK: device=%s name=%s", dev_name(&pdev->dev), QCA1530_RTC_CLK_ID); devm_clk_put(&pdev->dev, qca1530_data.rtc_clk); qca1530_data.rtc_clk = NULL; } /** * qca1530_clk_release_clocks() - release clocks * @pdev: platform device data * * Function releases initialized clocks and sets clock handle * pointers to NULL. */ static void qca1530_clk_release_clocks(struct platform_device *pdev) { qca1530_clk_release_clock(pdev, QCA1530_TCXO_CLK_ID, &qca1530_data.tcxo_clk); qca1530_clk_release_clock(pdev, QCA1530_RTC_CLK_ID, &qca1530_data.rtc_clk); } /** Loading @@ -237,13 +258,15 @@ static int qca1530_clk_init_gpio(struct platform_device *pdev) ret = of_get_named_gpio(pdev->dev.of_node, QCA1530_OF_CLK_GPIO_NAME, 0); if (ret == -ENOENT) { qca1530_data.rtc_clk_gpio = ret; pr_debug("%s GPIO is not defined", QCA1530_OF_CLK_GPIO_NAME); ret = 0; pr_debug("GPIO is not defined"); } else if (ret < 0) { pr_err("GPIO error: %d", ret); pr_err("Error getting GPIO %s: %d", QCA1530_OF_CLK_GPIO_NAME, ret); } else { qca1530_data.rtc_clk_gpio = ret; pr_debug("GPIO registered: gpio=%d", ret); pr_debug("GPIO %s registered: gpio=%d", QCA1530_OF_CLK_GPIO_NAME, ret); ret = 0; } return ret; Loading @@ -262,7 +285,7 @@ static int qca1530_clk_init(struct platform_device *pdev) { int ret; pr_debug("Clock initializing"); pr_debug("Initializing clock"); qca1530_data.rtc_clk = devm_clk_get(&pdev->dev, QCA1530_RTC_CLK_ID); Loading @@ -272,12 +295,15 @@ static int qca1530_clk_init(struct platform_device *pdev) if (ret == -ENOENT) { pr_debug("No RTC clock controller"); } else { pr_err("error: device=%s clock=%s ret=%d", pr_err("Clock init error: device=%s clock=%s ret=%d", dev_name(&pdev->dev), QCA1530_RTC_CLK_ID, ret); goto err_0; } } } else pr_debug("Ref to clock %s obtained: %p", QCA1530_RTC_CLK_ID, qca1530_data.rtc_clk); qca1530_data.tcxo_clk = devm_clk_get(&pdev->dev, QCA1530_TCXO_CLK_ID); if (IS_ERR(qca1530_data.tcxo_clk)) { ret = PTR_ERR(qca1530_data.tcxo_clk); Loading @@ -285,23 +311,26 @@ static int qca1530_clk_init(struct platform_device *pdev) if (ret == -ENOENT) { pr_debug("No TCXO clock controller"); } else { pr_err("error: device=%s clock=%s ret=%d", pr_err("Clock init error: device=%s clock=%s ret=%d", dev_name(&pdev->dev), QCA1530_TCXO_CLK_ID, ret); goto err_1; } } } else pr_debug("Ref to clock %s obtained: %p", QCA1530_TCXO_CLK_ID, qca1530_data.tcxo_clk); ret = qca1530_clk_init_gpio(pdev); if (ret) goto err_1; ret = qca1530_clk_set(1); if (ret < 0) { pr_err("error: ret=%d", ret); pr_err("Clock set error: ret=%d", ret); goto err_2; } pr_debug("init done: GPIO=%s RTC=%s TCXO=%s", pr_debug("Clock init done: GPIO=%s RTC=%s TCXO=%s", qca1530_data.rtc_clk_gpio >= 0 ? "ok" : "unused", qca1530_data.rtc_clk ? "ok" : "unused", qca1530_data.tcxo_clk ? "ok" : "unused"); Loading Loading @@ -379,7 +408,7 @@ static int qca1530_pwr_set_regulator(struct regulator *reg, int mode) } } pr_debug("Regulator result: regulator=%p mode=%d ret=%d", reg, mode, pr_debug("Regulator set result: regulator=%p mode=%d ret=%d", reg, mode, ret); return ret; Loading @@ -404,6 +433,8 @@ static int qca1530_pwr_init_gpio(struct platform_device *pdev) } else if (ret < 0) { pr_err("Power control GPIO error: %d", ret); } else { pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_PWR_GPIO_NAME, ret); qca1530_data.pwr_gpio = ret; ret = 0; } Loading Loading @@ -438,6 +469,7 @@ static int qca1530_pwr_init_regulator( } else pr_err("Failed to get regulator, ret=%d", ret); } else { pr_debug("Ref to regulator %s obtained: %p", name, pwr); *ppwr = pwr; ret = 0; } Loading @@ -455,20 +487,19 @@ static int qca1530_pwr_init_regulator( static int qca1530_pwr_set(int mode) { int ret = 0; if (!qca1530_data.pwr_reg && qca1530_data.pwr_gpio < 0) { if (!qca1530_data.pwr_reg && !qca1530_data.pwr_opt_reg && qca1530_data.pwr_gpio < 0) { ret = -ENOSYS; } else if (mode) { } else { if (qca1530_data.pwr_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_reg, mode); if (!ret && qca1530_data.pwr_opt_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_opt_reg, mode); if (!ret && qca1530_data.pwr_gpio >= 0) qca1530_pwr_set_gpio(mode); } else { if (qca1530_data.pwr_gpio >= 0) qca1530_pwr_set_gpio(mode); if (!ret && qca1530_data.pwr_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_reg, mode); } return ret; } Loading @@ -492,15 +523,22 @@ static int qca1530_pwr_init(struct platform_device *pdev) if (ret) goto err_0; ret = qca1530_pwr_init_gpio(pdev); ret = qca1530_pwr_init_regulator( pdev, QCA1530_OF_PWR_OPT_REG_NAME, &qca1530_data.pwr_opt_reg); if (ret) goto err_1; if (qca1530_data.pwr_reg || qca1530_data.pwr_gpio >= 0) { ret = qca1530_pwr_init_gpio(pdev); if (ret) goto err_2; if (qca1530_data.pwr_reg || qca1530_data.pwr_gpio >= 0 || qca1530_data.pwr_opt_reg) { ret = qca1530_pwr_set(1); if (ret) { pr_err("Failed to enable power, rc=%d", ret); goto err_2; goto err_3; } pr_debug("Configured: reg=%p gpio=%d", qca1530_data.pwr_reg, Loading @@ -510,8 +548,10 @@ static int qca1530_pwr_init(struct platform_device *pdev) } return ret; err_2: err_3: qca1530_deinit_gpio(pdev, &qca1530_data.pwr_gpio); err_2: qca1530_deinit_regulator(&qca1530_data.pwr_opt_reg); err_1: qca1530_deinit_regulator(&qca1530_data.pwr_reg); err_0: Loading @@ -528,6 +568,7 @@ static void qca1530_pwr_deinit(struct platform_device *pdev) { qca1530_pwr_set(0); qca1530_deinit_gpio(pdev, &qca1530_data.pwr_gpio); qca1530_deinit_regulator(&qca1530_data.pwr_opt_reg); qca1530_deinit_regulator(&qca1530_data.pwr_reg); } Loading @@ -544,7 +585,7 @@ static int qca1530_reset_init(struct platform_device *pdev) { int ret; pr_debug("reset control: initializing"); pr_debug("Initializing reset control"); ret = of_get_named_gpio(pdev->dev.of_node, QCA1530_OF_RESET_GPIO_NAME, 0); Loading @@ -552,6 +593,8 @@ static int qca1530_reset_init(struct platform_device *pdev) pr_err("failed to get gpio from config: %d", ret); goto err_gpio_get; } pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_RESET_GPIO_NAME, ret); qca1530_data.reset_gpio = ret; ret = devm_gpio_request(&pdev->dev, qca1530_data.reset_gpio, Loading Loading @@ -606,7 +649,7 @@ err_gpio_get: */ static void qca1530_reset_deinit(struct platform_device *pdev) { pr_debug("reset control: releasing"); pr_debug("Releasing reset control"); qca1530_deinit_gpio(pdev, &qca1530_data.reset_gpio); if (qca1530_data.reset_reg) { qca1530_pwr_set_regulator(qca1530_data.reset_reg, 0); Loading Loading @@ -635,6 +678,8 @@ static int qca1530_xlna_init_gpio(struct platform_device *pdev) } else if (ret < 0) { pr_err("xLNA control: GPIO error: %d", ret); } else { pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_XLNA_GPIO_NAME, ret); qca1530_data.xlna_gpio = ret; ret = 0; } Loading Loading @@ -726,7 +771,7 @@ static int qca1530_xlna_init(struct platform_device *pdev) int ret = 0; u32 tmp[2]; pr_debug("xLNA control: initializing"); pr_debug("Initializing xLNA control"); ret = qca1530_pwr_init_regulator( pdev, QCA1530_OF_XLNA_REG_NAME, &qca1530_data.xlna_reg); Loading Loading @@ -800,8 +845,9 @@ static void qca1530_xlna_deinit(struct platform_device *pdev) } /** * qca1530_probe() - performs driver initialization * qca1530_set_chip_state() - performs driver initialization * @pdev: platform device data * @on: target state, 1 - on, 0 - off * * The driver probing includes initialization of the subsystems in the * following order: Loading @@ -810,50 +856,202 @@ static void qca1530_xlna_deinit(struct platform_device *pdev) * - xLNA control * - SoC power control */ static int qca1530_probe(struct platform_device *pdev) static int qca1530_set_chip_state(struct platform_device *pdev, const int on_mask) { int ret; int on_req; ret = 0; on_req = on_mask; pr_debug("on_mask=%d", on_mask); pr_debug("Switching on"); if (!(qca1530_data.chip_state & QCA1530_RESET_FLG) && (on_req & QCA1530_RESET_FLG)) { ret = qca1530_reset_init(pdev); if (ret < 0) { pr_err("failed to init reset: %d", ret); goto err_reset_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_RESET_FLG; } } if (!(qca1530_data.chip_state & QCA1530_CLK_FLG) && (on_req & QCA1530_CLK_FLG)) { ret = qca1530_clk_init(pdev); if (ret) { pr_err("failed to initialize clock: %d", ret); goto err_clk_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_CLK_FLG; } } if (!(qca1530_data.chip_state & QCA1530_XLNA_FLG) && (on_req & QCA1530_XLNA_FLG)) { ret = qca1530_xlna_init(pdev); if (ret) { pr_err("failed to initialize xLNA: %d", ret); goto err_xlna_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_XLNA_FLG; } } if (!(qca1530_data.chip_state & QCA1530_POWER_FLG) && (on_req & QCA1530_POWER_FLG)) { ret = qca1530_pwr_init(pdev); if (ret < 0) { pr_err("failed to init power: %d", ret); goto err_pwr_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_POWER_FLG; } } qca1530_data.pdev = pdev; pr_debug("Probe OK"); return ret; pr_debug("Chip on section over, qca1530_data.chip_state=%d", qca1530_data.chip_state); err_pwr_init: switching_off: pr_debug("Switching off"); if ((qca1530_data.chip_state & QCA1530_POWER_FLG) && !(on_req & QCA1530_POWER_FLG)) { qca1530_pwr_deinit(pdev); qca1530_data.chip_state &= ~QCA1530_POWER_FLG; } if ((qca1530_data.chip_state & QCA1530_XLNA_FLG) && !(on_req & QCA1530_XLNA_FLG)) { qca1530_xlna_deinit(pdev); err_xlna_init: qca1530_data.chip_state &= ~QCA1530_XLNA_FLG; } if ((qca1530_data.chip_state & QCA1530_CLK_FLG) && !(on_req & QCA1530_CLK_FLG)) { qca1530_clk_deinit(pdev); err_clk_init: qca1530_data.chip_state &= ~QCA1530_CLK_FLG; } if ((qca1530_data.chip_state & QCA1530_RESET_FLG) && !(on_req & QCA1530_RESET_FLG)) { qca1530_reset_deinit(pdev); err_reset_init: qca1530_data.chip_state &= ~QCA1530_RESET_FLG; } pr_debug("Chip off section over, qca1530_data.chip_state=%d", qca1530_data.chip_state); pr_debug("Probe ret=%d", ret); return ret; } static ssize_t chip_state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return snprintf(buf, 16, "%d\n", qca1530_data.chip_state); } static ssize_t chip_state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { int retval; int new_state; sscanf(buf, "%du", &new_state); pr_debug("new_state=%d", new_state); if (count && ((new_state <= QCA1530_ALL_FLG) && (new_state >= 0))) { pr_debug("qca1530_data.chip_state=%d", qca1530_data.chip_state); retval = qca1530_set_chip_state(qca1530_data.pdev, new_state); pr_debug("qca1530_set_chip_state() returned %d", retval); pr_debug("qca1530_data.chip_state=%d", qca1530_data.chip_state); } return count; } static struct kobj_attribute chip_state_attribute = __ATTR(chip_state, 0600, chip_state_show, chip_state_store); static struct attribute *attrs[] = { &chip_state_attribute.attr, NULL, }; static struct attribute_group attr_group = { .attrs = attrs, }; static struct kobject *qca1530_kobject; static int qca1530_create_sysfs_node(void) { int retval; pr_debug("Creating sysfs node"); qca1530_kobject = kobject_create_and_add(SYSFS_NODE_NAME, kernel_kobj); pr_debug("qca1530_kobject=%p", qca1530_kobject); if (!qca1530_kobject) return -ENOMEM; retval = sysfs_create_group(qca1530_kobject, &attr_group); pr_debug("sysfs_create_group() returned %d", retval); if (retval) kobject_put(qca1530_kobject); return retval; } static void qca1530_remove_sysfs_node(void) { pr_debug("Removing sysfs node"); if (qca1530_kobject) { sysfs_remove_group(qca1530_kobject, &attr_group); kobject_put(qca1530_kobject); qca1530_kobject = NULL; } } /** * qca1530_probe() - performs driver initialization * @pdev: platform device data * * Function tried to turn on all required signals. * Refer to qca1530_set_chip_state() documentation for details. */ static int qca1530_probe(struct platform_device *pdev) { int retval; pr_debug("Probing to install"); retval = qca1530_set_chip_state(pdev, QCA1530_ALL_FLG); if (!retval) { qca1530_data.pdev = pdev; retval = qca1530_create_sysfs_node(); if (retval) { qca1530_set_chip_state(pdev, 0); qca1530_data.pdev = NULL; pr_debug("qca1530_create_sysfs_node() returned %d", retval); } } else pr_debug("qca1530_set_chip_state() returned %d", retval); return retval; } /** * qca1530_remove() - releases all resources * @pdev: platform device data Loading @@ -866,12 +1064,11 @@ err_reset_init: */ static int qca1530_remove(struct platform_device *pdev) { qca1530_pwr_deinit(pdev); qca1530_xlna_deinit(pdev); qca1530_clk_deinit(pdev); qca1530_reset_deinit(pdev); int retval; qca1530_remove_sysfs_node(); retval = qca1530_set_chip_state(pdev, 0); qca1530_data.pdev = NULL; return 0; return retval; } /* Loading Loading
Documentation/devicetree/bindings/platform/msm/qca1530.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ Required properties Optional properties - qca,pwr-supply: handle to the regulator device tree node - qca,pwr2-supply: handle to additional regulator device tree node - qca,pwr-gpio: handle the power control using GPIO interface - qca,reset-gpio: GPIO for reset control - qca,reset-supply: handle to the regulator for reset control Loading
drivers/platform/msm/qca1530.c +288 −91 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <linux/platform_device.h> #include <linux/uaccess.h> #include <linux/types.h> #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> /* RTC clock name for lookup */ #define QCA1530_RTC_CLK_ID "qca,rtc_clk" Loading @@ -32,6 +35,8 @@ #define QCA1530_TCXO_CLK_ID "qca,tcxo_clk" /* SoC power regulator prefix for DTS */ #define QCA1530_OF_PWR_REG_NAME "qca,pwr" /* SoC optional power regulator prefix for DTS */ #define QCA1530_OF_PWR_OPT_REG_NAME "qca,pwr2" /* SoC power regulator pin for DTS */ #define QCA1530_OF_PWR_GPIO_NAME "qca,pwr-gpio" /* Reset power regulator prefix for DTS */ Loading @@ -49,6 +54,14 @@ /* xLNA pin name for DTS */ #define QCA1530_OF_XLNA_GPIO_NAME "qca,xlna-gpio" #define QCA1530_ALL_FLG 0x0f #define QCA1530_POWER_FLG 0x01 #define QCA1530_XLNA_FLG 0x02 #define QCA1530_CLK_FLG 0x04 #define QCA1530_RESET_FLG 0x08 #define SYSFS_NODE_NAME "qca1530" /** * struct qca1530_static - keeps all driver instance variables * @pdev: Platform device data Loading @@ -72,9 +85,11 @@ struct qca1530_static { int rtc_clk_gpio; struct clk *tcxo_clk; struct regulator *pwr_reg; struct regulator *pwr_opt_reg; int pwr_gpio; struct regulator *xlna_reg; int xlna_gpio; int chip_state; }; /* Loading @@ -85,6 +100,7 @@ static struct qca1530_static qca1530_data = { .rtc_clk_gpio = -1, .pwr_gpio = -1, .xlna_gpio = -1, .chip_state = 0, }; /** Loading Loading @@ -143,7 +159,7 @@ static int qca1530_clk_prepare(struct clk *clk, int mode) else clk_disable_unprepare(clk); pr_debug("Configured clk (%p): mode=%d ret=%d", clk, mode, ret); pr_debug("Configured clock (%p): mode=%d ret=%d", clk, mode, ret); return ret; } Loading @@ -157,8 +173,7 @@ static int qca1530_clk_prepare(struct clk *clk, int mode) static void qca1530_clk_set_gpio(int mode) { gpio_set_value(qca1530_data.rtc_clk_gpio, mode ? 1 : 0); pr_debug("Configured clk (GPIO): mode=%d", mode); pr_debug("Set clk GPIO (%d): mode=%d", qca1530_data.rtc_clk_gpio, mode); } /** Loading @@ -175,51 +190,57 @@ static int qca1530_clk_set(int mode) { int ret = 0; if (qca1530_data.rtc_clk_gpio < 0 && !qca1530_data.rtc_clk && !qca1530_data.tcxo_clk) { if (qca1530_data.rtc_clk_gpio < 0 && !qca1530_data.rtc_clk && !qca1530_data.tcxo_clk) { ret = -ENOSYS; } else if (mode) { } else { if (qca1530_data.rtc_clk_gpio >= 0) qca1530_clk_set_gpio(1); qca1530_clk_set_gpio(mode); if (qca1530_data.rtc_clk) ret = qca1530_clk_prepare(qca1530_data.rtc_clk, 1); ret = qca1530_clk_prepare(qca1530_data.rtc_clk, mode); if (!ret && qca1530_data.tcxo_clk) ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, 1); } else { if (qca1530_data.tcxo_clk) ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, 0); if (!ret && qca1530_data.rtc_clk) ret = qca1530_clk_prepare(qca1530_data.rtc_clk, 0); if (!ret && qca1530_data.rtc_clk_gpio >= 0) qca1530_clk_set_gpio(0); ret = qca1530_clk_prepare(qca1530_data.tcxo_clk, mode); } pr_debug("Configured clk: mode=%d ret=%d", mode, ret); return ret; } /** * qca1530_clk_release_clocks() - release clocks * qca1530_clk_release_clock() - release clocks * @pdev: platform device data * @clk_name: clock name * @clk: pointer to clock handle pointer * * Function releases initialized clocks and sets clock handle * references to NULL. * pointer to NULL. */ static void qca1530_clk_release_clocks(struct platform_device *pdev) static void qca1530_clk_release_clock( struct platform_device *pdev, const char *clk_name, struct clk **clk) { if (qca1530_data.tcxo_clk) { pr_debug("Unregistering CLK: device=%s name=%s", dev_name(&pdev->dev), QCA1530_TCXO_CLK_ID); devm_clk_put(&pdev->dev, qca1530_data.tcxo_clk); qca1530_data.tcxo_clk = NULL; if (*clk) { pr_debug("Unregistering CLK: name=%s", clk_name); devm_clk_put(&pdev->dev, *clk); *clk = NULL; } if (qca1530_data.rtc_clk) { pr_debug("Unregistering CLK: device=%s name=%s", dev_name(&pdev->dev), QCA1530_RTC_CLK_ID); devm_clk_put(&pdev->dev, qca1530_data.rtc_clk); qca1530_data.rtc_clk = NULL; } /** * qca1530_clk_release_clocks() - release clocks * @pdev: platform device data * * Function releases initialized clocks and sets clock handle * pointers to NULL. */ static void qca1530_clk_release_clocks(struct platform_device *pdev) { qca1530_clk_release_clock(pdev, QCA1530_TCXO_CLK_ID, &qca1530_data.tcxo_clk); qca1530_clk_release_clock(pdev, QCA1530_RTC_CLK_ID, &qca1530_data.rtc_clk); } /** Loading @@ -237,13 +258,15 @@ static int qca1530_clk_init_gpio(struct platform_device *pdev) ret = of_get_named_gpio(pdev->dev.of_node, QCA1530_OF_CLK_GPIO_NAME, 0); if (ret == -ENOENT) { qca1530_data.rtc_clk_gpio = ret; pr_debug("%s GPIO is not defined", QCA1530_OF_CLK_GPIO_NAME); ret = 0; pr_debug("GPIO is not defined"); } else if (ret < 0) { pr_err("GPIO error: %d", ret); pr_err("Error getting GPIO %s: %d", QCA1530_OF_CLK_GPIO_NAME, ret); } else { qca1530_data.rtc_clk_gpio = ret; pr_debug("GPIO registered: gpio=%d", ret); pr_debug("GPIO %s registered: gpio=%d", QCA1530_OF_CLK_GPIO_NAME, ret); ret = 0; } return ret; Loading @@ -262,7 +285,7 @@ static int qca1530_clk_init(struct platform_device *pdev) { int ret; pr_debug("Clock initializing"); pr_debug("Initializing clock"); qca1530_data.rtc_clk = devm_clk_get(&pdev->dev, QCA1530_RTC_CLK_ID); Loading @@ -272,12 +295,15 @@ static int qca1530_clk_init(struct platform_device *pdev) if (ret == -ENOENT) { pr_debug("No RTC clock controller"); } else { pr_err("error: device=%s clock=%s ret=%d", pr_err("Clock init error: device=%s clock=%s ret=%d", dev_name(&pdev->dev), QCA1530_RTC_CLK_ID, ret); goto err_0; } } } else pr_debug("Ref to clock %s obtained: %p", QCA1530_RTC_CLK_ID, qca1530_data.rtc_clk); qca1530_data.tcxo_clk = devm_clk_get(&pdev->dev, QCA1530_TCXO_CLK_ID); if (IS_ERR(qca1530_data.tcxo_clk)) { ret = PTR_ERR(qca1530_data.tcxo_clk); Loading @@ -285,23 +311,26 @@ static int qca1530_clk_init(struct platform_device *pdev) if (ret == -ENOENT) { pr_debug("No TCXO clock controller"); } else { pr_err("error: device=%s clock=%s ret=%d", pr_err("Clock init error: device=%s clock=%s ret=%d", dev_name(&pdev->dev), QCA1530_TCXO_CLK_ID, ret); goto err_1; } } } else pr_debug("Ref to clock %s obtained: %p", QCA1530_TCXO_CLK_ID, qca1530_data.tcxo_clk); ret = qca1530_clk_init_gpio(pdev); if (ret) goto err_1; ret = qca1530_clk_set(1); if (ret < 0) { pr_err("error: ret=%d", ret); pr_err("Clock set error: ret=%d", ret); goto err_2; } pr_debug("init done: GPIO=%s RTC=%s TCXO=%s", pr_debug("Clock init done: GPIO=%s RTC=%s TCXO=%s", qca1530_data.rtc_clk_gpio >= 0 ? "ok" : "unused", qca1530_data.rtc_clk ? "ok" : "unused", qca1530_data.tcxo_clk ? "ok" : "unused"); Loading Loading @@ -379,7 +408,7 @@ static int qca1530_pwr_set_regulator(struct regulator *reg, int mode) } } pr_debug("Regulator result: regulator=%p mode=%d ret=%d", reg, mode, pr_debug("Regulator set result: regulator=%p mode=%d ret=%d", reg, mode, ret); return ret; Loading @@ -404,6 +433,8 @@ static int qca1530_pwr_init_gpio(struct platform_device *pdev) } else if (ret < 0) { pr_err("Power control GPIO error: %d", ret); } else { pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_PWR_GPIO_NAME, ret); qca1530_data.pwr_gpio = ret; ret = 0; } Loading Loading @@ -438,6 +469,7 @@ static int qca1530_pwr_init_regulator( } else pr_err("Failed to get regulator, ret=%d", ret); } else { pr_debug("Ref to regulator %s obtained: %p", name, pwr); *ppwr = pwr; ret = 0; } Loading @@ -455,20 +487,19 @@ static int qca1530_pwr_init_regulator( static int qca1530_pwr_set(int mode) { int ret = 0; if (!qca1530_data.pwr_reg && qca1530_data.pwr_gpio < 0) { if (!qca1530_data.pwr_reg && !qca1530_data.pwr_opt_reg && qca1530_data.pwr_gpio < 0) { ret = -ENOSYS; } else if (mode) { } else { if (qca1530_data.pwr_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_reg, mode); if (!ret && qca1530_data.pwr_opt_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_opt_reg, mode); if (!ret && qca1530_data.pwr_gpio >= 0) qca1530_pwr_set_gpio(mode); } else { if (qca1530_data.pwr_gpio >= 0) qca1530_pwr_set_gpio(mode); if (!ret && qca1530_data.pwr_reg) ret = qca1530_pwr_set_regulator( qca1530_data.pwr_reg, mode); } return ret; } Loading @@ -492,15 +523,22 @@ static int qca1530_pwr_init(struct platform_device *pdev) if (ret) goto err_0; ret = qca1530_pwr_init_gpio(pdev); ret = qca1530_pwr_init_regulator( pdev, QCA1530_OF_PWR_OPT_REG_NAME, &qca1530_data.pwr_opt_reg); if (ret) goto err_1; if (qca1530_data.pwr_reg || qca1530_data.pwr_gpio >= 0) { ret = qca1530_pwr_init_gpio(pdev); if (ret) goto err_2; if (qca1530_data.pwr_reg || qca1530_data.pwr_gpio >= 0 || qca1530_data.pwr_opt_reg) { ret = qca1530_pwr_set(1); if (ret) { pr_err("Failed to enable power, rc=%d", ret); goto err_2; goto err_3; } pr_debug("Configured: reg=%p gpio=%d", qca1530_data.pwr_reg, Loading @@ -510,8 +548,10 @@ static int qca1530_pwr_init(struct platform_device *pdev) } return ret; err_2: err_3: qca1530_deinit_gpio(pdev, &qca1530_data.pwr_gpio); err_2: qca1530_deinit_regulator(&qca1530_data.pwr_opt_reg); err_1: qca1530_deinit_regulator(&qca1530_data.pwr_reg); err_0: Loading @@ -528,6 +568,7 @@ static void qca1530_pwr_deinit(struct platform_device *pdev) { qca1530_pwr_set(0); qca1530_deinit_gpio(pdev, &qca1530_data.pwr_gpio); qca1530_deinit_regulator(&qca1530_data.pwr_opt_reg); qca1530_deinit_regulator(&qca1530_data.pwr_reg); } Loading @@ -544,7 +585,7 @@ static int qca1530_reset_init(struct platform_device *pdev) { int ret; pr_debug("reset control: initializing"); pr_debug("Initializing reset control"); ret = of_get_named_gpio(pdev->dev.of_node, QCA1530_OF_RESET_GPIO_NAME, 0); Loading @@ -552,6 +593,8 @@ static int qca1530_reset_init(struct platform_device *pdev) pr_err("failed to get gpio from config: %d", ret); goto err_gpio_get; } pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_RESET_GPIO_NAME, ret); qca1530_data.reset_gpio = ret; ret = devm_gpio_request(&pdev->dev, qca1530_data.reset_gpio, Loading Loading @@ -606,7 +649,7 @@ err_gpio_get: */ static void qca1530_reset_deinit(struct platform_device *pdev) { pr_debug("reset control: releasing"); pr_debug("Releasing reset control"); qca1530_deinit_gpio(pdev, &qca1530_data.reset_gpio); if (qca1530_data.reset_reg) { qca1530_pwr_set_regulator(qca1530_data.reset_reg, 0); Loading Loading @@ -635,6 +678,8 @@ static int qca1530_xlna_init_gpio(struct platform_device *pdev) } else if (ret < 0) { pr_err("xLNA control: GPIO error: %d", ret); } else { pr_debug("Ref to gpio %s obtained: %d", QCA1530_OF_XLNA_GPIO_NAME, ret); qca1530_data.xlna_gpio = ret; ret = 0; } Loading Loading @@ -726,7 +771,7 @@ static int qca1530_xlna_init(struct platform_device *pdev) int ret = 0; u32 tmp[2]; pr_debug("xLNA control: initializing"); pr_debug("Initializing xLNA control"); ret = qca1530_pwr_init_regulator( pdev, QCA1530_OF_XLNA_REG_NAME, &qca1530_data.xlna_reg); Loading Loading @@ -800,8 +845,9 @@ static void qca1530_xlna_deinit(struct platform_device *pdev) } /** * qca1530_probe() - performs driver initialization * qca1530_set_chip_state() - performs driver initialization * @pdev: platform device data * @on: target state, 1 - on, 0 - off * * The driver probing includes initialization of the subsystems in the * following order: Loading @@ -810,50 +856,202 @@ static void qca1530_xlna_deinit(struct platform_device *pdev) * - xLNA control * - SoC power control */ static int qca1530_probe(struct platform_device *pdev) static int qca1530_set_chip_state(struct platform_device *pdev, const int on_mask) { int ret; int on_req; ret = 0; on_req = on_mask; pr_debug("on_mask=%d", on_mask); pr_debug("Switching on"); if (!(qca1530_data.chip_state & QCA1530_RESET_FLG) && (on_req & QCA1530_RESET_FLG)) { ret = qca1530_reset_init(pdev); if (ret < 0) { pr_err("failed to init reset: %d", ret); goto err_reset_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_RESET_FLG; } } if (!(qca1530_data.chip_state & QCA1530_CLK_FLG) && (on_req & QCA1530_CLK_FLG)) { ret = qca1530_clk_init(pdev); if (ret) { pr_err("failed to initialize clock: %d", ret); goto err_clk_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_CLK_FLG; } } if (!(qca1530_data.chip_state & QCA1530_XLNA_FLG) && (on_req & QCA1530_XLNA_FLG)) { ret = qca1530_xlna_init(pdev); if (ret) { pr_err("failed to initialize xLNA: %d", ret); goto err_xlna_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_XLNA_FLG; } } if (!(qca1530_data.chip_state & QCA1530_POWER_FLG) && (on_req & QCA1530_POWER_FLG)) { ret = qca1530_pwr_init(pdev); if (ret < 0) { pr_err("failed to init power: %d", ret); goto err_pwr_init; on_req = 0; goto switching_off; } else { qca1530_data.chip_state |= QCA1530_POWER_FLG; } } qca1530_data.pdev = pdev; pr_debug("Probe OK"); return ret; pr_debug("Chip on section over, qca1530_data.chip_state=%d", qca1530_data.chip_state); err_pwr_init: switching_off: pr_debug("Switching off"); if ((qca1530_data.chip_state & QCA1530_POWER_FLG) && !(on_req & QCA1530_POWER_FLG)) { qca1530_pwr_deinit(pdev); qca1530_data.chip_state &= ~QCA1530_POWER_FLG; } if ((qca1530_data.chip_state & QCA1530_XLNA_FLG) && !(on_req & QCA1530_XLNA_FLG)) { qca1530_xlna_deinit(pdev); err_xlna_init: qca1530_data.chip_state &= ~QCA1530_XLNA_FLG; } if ((qca1530_data.chip_state & QCA1530_CLK_FLG) && !(on_req & QCA1530_CLK_FLG)) { qca1530_clk_deinit(pdev); err_clk_init: qca1530_data.chip_state &= ~QCA1530_CLK_FLG; } if ((qca1530_data.chip_state & QCA1530_RESET_FLG) && !(on_req & QCA1530_RESET_FLG)) { qca1530_reset_deinit(pdev); err_reset_init: qca1530_data.chip_state &= ~QCA1530_RESET_FLG; } pr_debug("Chip off section over, qca1530_data.chip_state=%d", qca1530_data.chip_state); pr_debug("Probe ret=%d", ret); return ret; } static ssize_t chip_state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return snprintf(buf, 16, "%d\n", qca1530_data.chip_state); } static ssize_t chip_state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { int retval; int new_state; sscanf(buf, "%du", &new_state); pr_debug("new_state=%d", new_state); if (count && ((new_state <= QCA1530_ALL_FLG) && (new_state >= 0))) { pr_debug("qca1530_data.chip_state=%d", qca1530_data.chip_state); retval = qca1530_set_chip_state(qca1530_data.pdev, new_state); pr_debug("qca1530_set_chip_state() returned %d", retval); pr_debug("qca1530_data.chip_state=%d", qca1530_data.chip_state); } return count; } static struct kobj_attribute chip_state_attribute = __ATTR(chip_state, 0600, chip_state_show, chip_state_store); static struct attribute *attrs[] = { &chip_state_attribute.attr, NULL, }; static struct attribute_group attr_group = { .attrs = attrs, }; static struct kobject *qca1530_kobject; static int qca1530_create_sysfs_node(void) { int retval; pr_debug("Creating sysfs node"); qca1530_kobject = kobject_create_and_add(SYSFS_NODE_NAME, kernel_kobj); pr_debug("qca1530_kobject=%p", qca1530_kobject); if (!qca1530_kobject) return -ENOMEM; retval = sysfs_create_group(qca1530_kobject, &attr_group); pr_debug("sysfs_create_group() returned %d", retval); if (retval) kobject_put(qca1530_kobject); return retval; } static void qca1530_remove_sysfs_node(void) { pr_debug("Removing sysfs node"); if (qca1530_kobject) { sysfs_remove_group(qca1530_kobject, &attr_group); kobject_put(qca1530_kobject); qca1530_kobject = NULL; } } /** * qca1530_probe() - performs driver initialization * @pdev: platform device data * * Function tried to turn on all required signals. * Refer to qca1530_set_chip_state() documentation for details. */ static int qca1530_probe(struct platform_device *pdev) { int retval; pr_debug("Probing to install"); retval = qca1530_set_chip_state(pdev, QCA1530_ALL_FLG); if (!retval) { qca1530_data.pdev = pdev; retval = qca1530_create_sysfs_node(); if (retval) { qca1530_set_chip_state(pdev, 0); qca1530_data.pdev = NULL; pr_debug("qca1530_create_sysfs_node() returned %d", retval); } } else pr_debug("qca1530_set_chip_state() returned %d", retval); return retval; } /** * qca1530_remove() - releases all resources * @pdev: platform device data Loading @@ -866,12 +1064,11 @@ err_reset_init: */ static int qca1530_remove(struct platform_device *pdev) { qca1530_pwr_deinit(pdev); qca1530_xlna_deinit(pdev); qca1530_clk_deinit(pdev); qca1530_reset_deinit(pdev); int retval; qca1530_remove_sysfs_node(); retval = qca1530_set_chip_state(pdev, 0); qca1530_data.pdev = NULL; return 0; return retval; } /* Loading